[Scummvm-git-logs] scummvm master -> 4364392b93d99b2db09c1dfa9f2efde0c4a44e81
sev-
noreply at scummvm.org
Thu May 8 22:18:43 UTC 2025
This automated email contains information about 27 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
413d323423 DIRECTOR: Add xlibs command to debugger
45ba56f00a DIRECTOR: Use refcounts for cast members, implement 'the media'
39f18f87a3 DIRECTOR: Remove alternate palette format
d99849b336 DIRECTOR: Implement the name of castLib setter
67199e61eb DIRECTOR: LINGO: Fix range check in b_member
ec17b18942 DIRECTOR: Add null check in TextCastMember::isWithin
972e7b150e DIRECTOR: Add Search for the Golden Dolphin to detection table
87fd826f50 DIRECTOR: Add perFrameHook recursion-break behaviour specific to D5
ea899dba35 DIRECTOR: LINGO: Improve accuracy of 'the result'
50ef13bb30 DIRECTOR: Only write back from TextCastMember widget if in edit mode
24747c4d6a DIRECTOR: LINGO: Implement the keyPressed
b96a8dd703 MACGUI: Fix MacText::getMouse*
61ec96df11 GRAPHICS: MACGUI: Add debugging output to getTextChunk
96871a30dd DIRECTOR: Check before reloading castLibs
fe2e7ebe7c DIRECTOR: LINGO: Enable dirty flag when setting locH/locV for trails
e0da2006d7 DIRECTOR: Allow AIFF playback in DigitalVideoCastMember
ae8a9b0b99 DIRECTOR: Keep track of old sprite bboxes for rollOver
5f8a9621bb DIRECTOR: Fix parsing "when mousedown then"
098fddf97a DIRECTOR: Move "the hilite" property to base CastMember
c69af23102 DIRECTOR: Fix Mac resource mouse cursor offset
a71c8b3cd4 DIRECTOR: Fix Cursor::readFromCast if no mask is provided
c9ca3d5706 DIRECTOR: Add Gus Goes to the Kooky Carnival to detection table
b1ccc9bec9 DIRECTOR: Add guardrail for empty RTE1 block
f1451082ee DIRECTOR: Add guardrail for copying from a zero-sized bitmap
77365baab4 DIRECTOR: Set default palette as soon as the first movie loads
61b0ab070b DIRECTOR: RichTextCastMember fixes
4364392b93 DIRECTOR: Wire up D5 rightMouseDown and rightMouseUp handlers
Commit: 413d3234235d518cea30dc095a01c7fd5f6c02a3
https://github.com/scummvm/scummvm/commit/413d3234235d518cea30dc095a01c7fd5f6c02a3
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Add xlibs command to debugger
Changed paths:
engines/director/debugger.cpp
engines/director/debugger.h
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 89e1716f784..0a8641a8155 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -29,6 +29,7 @@
#include "director/frame.h"
#include "director/movie.h"
#include "director/score.h"
+#include "director/types.h"
#include "director/util.h"
#include "director/window.h"
#include "director/lingo/lingo.h"
@@ -89,6 +90,8 @@ Debugger::Debugger(): GUI::Debugger() {
registerCmd("c", WRAP_METHOD(Debugger, cmdExit));
registerCmd("windows", WRAP_METHOD(Debugger, cmdWindows));
registerCmd("w", WRAP_METHOD(Debugger, cmdWindows));
+ registerCmd("xlibs", WRAP_METHOD(Debugger, cmdXLibs));
+ registerCmd("xl", WRAP_METHOD(Debugger, cmdXLibs));
registerCmd("bpset", WRAP_METHOD(Debugger, cmdBpSet));
registerCmd("b", WRAP_METHOD(Debugger, cmdBpSet));
@@ -168,6 +171,7 @@ bool Debugger::cmdHelp(int argc, const char **argv) {
debugPrintf(" finish / fin - Steps until the current stack frame returns\n");
debugPrintf(" continue / c - Continues execution\n");
debugPrintf(" windows / w - Lists all of the windows\n");
+ debugPrintf(" xlibs / xl - Lists all of the Lingo XObject/Xtras loaded\n");
debugPrintf("\n");
debugPrintf("Breakpoints:\n");
debugPrintf(" bpset / b - Creates a breakpoint at the current Lingo function and offset\n");
@@ -683,6 +687,16 @@ bool Debugger::cmdWindows(int argc, const char **argv) {
return true;
}
+bool Debugger::cmdXLibs(int argc, const char **argv) {
+ debugPrintf("XLibs:\n");
+ for (auto &it : g_lingo->_openXLibs) {
+ debugPrintf("%s: %s\n", it._key.c_str(), it._value == kXObj ? "XObj" : (it._value == kXtraObj ? "Xtra" : "unknown"));
+ }
+
+ debugPrintf("\n");
+ return true;
+}
+
bool Debugger::cmdBpSet(int argc, const char **argv) {
Breakpoint bp;
bp.type = kBreakpointFunction;
diff --git a/engines/director/debugger.h b/engines/director/debugger.h
index a214bfecac2..a87adab0cb5 100644
--- a/engines/director/debugger.h
+++ b/engines/director/debugger.h
@@ -107,6 +107,7 @@ private:
bool cmdNext(int argc, const char **argv);
bool cmdFinish(int argc, const char **argv);
bool cmdWindows(int argc, const char **argv);
+ bool cmdXLibs(int argc, const char **argv);
bool cmdBpSet(int argc, const char **argv);
bool cmdBpMovie(int argc, const char **argv);
Commit: 45ba56f00a7d638e39f697ef21ab0a09abd98117
https://github.com/scummvm/scummvm/commit/45ba56f00a7d638e39f697ef21ab0a09abd98117
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Use refcounts for cast members, implement 'the media'
Changed paths:
engines/director/cast.cpp
engines/director/castmember/bitmap.cpp
engines/director/castmember/bitmap.h
engines/director/castmember/castmember.cpp
engines/director/castmember/castmember.h
engines/director/castmember/digitalvideo.cpp
engines/director/castmember/digitalvideo.h
engines/director/castmember/filmloop.cpp
engines/director/castmember/filmloop.h
engines/director/castmember/movie.h
engines/director/castmember/palette.h
engines/director/castmember/richtext.cpp
engines/director/castmember/richtext.h
engines/director/castmember/script.h
engines/director/castmember/shape.cpp
engines/director/castmember/shape.h
engines/director/castmember/sound.cpp
engines/director/castmember/sound.h
engines/director/castmember/text.cpp
engines/director/castmember/text.h
engines/director/castmember/transition.h
engines/director/lingo/lingo-the.cpp
engines/director/lingo/lingo.cpp
engines/director/lingo/lingo.h
engines/director/types.h
diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index a5a974953ea..50988944bd7 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -98,7 +98,7 @@ Cast::~Cast() {
if (_loadedCast)
for (auto &it : *_loadedCast)
if (it._value) {
- delete it._value;
+ it._value->decRefCount();
it._value = nullptr;
}
@@ -236,10 +236,8 @@ void Cast::setCastMemberModified(int castId) {
}
CastMember *Cast::setCastMember(int castId, CastMember *cast) {
- if (_loadedCast->contains(castId)) {
- _loadedCast->erase(castId);
- }
-
+ eraseCastMember(castId);
+ cast->incRefCount();
_loadedCast->setVal(castId, cast);
return cast;
}
@@ -252,43 +250,7 @@ bool Cast::duplicateCastMember(CastMember *source, CastMemberInfo *info, int tar
// is the same as deleting the target
if (!source)
return true;
- CastMember *target = nullptr;
- switch (source->_type) {
- case kCastBitmap:
- target = (CastMember *)(new BitmapCastMember(this, targetId, *(BitmapCastMember *)source));
- break;
- case kCastDigitalVideo:
- target = (CastMember *)(new DigitalVideoCastMember(this, targetId, *(DigitalVideoCastMember *)source));
- break;
- case kCastFilmLoop:
- target = (CastMember *)(new FilmLoopCastMember(this, targetId, *(FilmLoopCastMember *)source));
- break;
- case kCastMovie:
- target = (CastMember *)(new MovieCastMember(this, targetId, *(MovieCastMember *)source));
- break;
- case kCastPalette:
- target = (CastMember *)(new PaletteCastMember(this, targetId, *(PaletteCastMember *)source));
- break;
- case kCastLingoScript:
- target = (CastMember *)(new ScriptCastMember(this, targetId, *(ScriptCastMember *)source));
- break;
- case kCastShape:
- target = (CastMember *)(new ShapeCastMember(this, targetId, *(ShapeCastMember *)source));
- break;
- case kCastText:
- target = (CastMember *)(new TextCastMember(this, targetId, *(TextCastMember *)source));
- break;
- case kCastRichText:
- target = (CastMember *)(new RichTextCastMember(this, targetId, *(RichTextCastMember *)source));
- break;
- case kCastTransition:
- target = (CastMember *)(new TransitionCastMember(this, targetId, *(TransitionCastMember *)source));
- break;
- default:
- warning("Cast::duplicateCastMember(): unsupported cast type %s", castType2str(source->_type));
- return false;
- break;
- }
+ CastMember *target = source->duplicate(this, targetId);
if (info) {
CastMemberInfo *newInfo = new CastMemberInfo(*info);
@@ -304,7 +266,7 @@ bool Cast::duplicateCastMember(CastMember *source, CastMemberInfo *info, int tar
bool Cast::eraseCastMember(int castId) {
if (_loadedCast->contains(castId)) {
CastMember *member = _loadedCast->getVal(castId);
- delete member;
+ member->decRefCount();
_loadedCast->erase(castId);
if (_castsInfo.contains(castId)) {
@@ -896,6 +858,7 @@ void Cast::loadCastDataVWCR(Common::SeekableReadStreamEndian &stream) {
}
int returnPos = stream.pos() + size;
+ CastMember *target = nullptr;
switch (castType) {
case kCastBitmap:
debugC(3, kDebugLoading, "Cast::loadCastDataVWCR(): CastTypes id: %d(%s) BitmapCastMember", id, numToCastNum(id));
@@ -908,42 +871,44 @@ void Cast::loadCastDataVWCR(Common::SeekableReadStreamEndian &stream) {
break;
}
- _loadedCast->setVal(id, new BitmapCastMember(this, id, stream, tag, _version, flags1));
+ target = new BitmapCastMember(this, id, stream, tag, _version, flags1);
break;
case kCastText:
debugC(3, kDebugLoading, "Cast::loadCastDataVWCR(): CastTypes id: %d(%s) TextCastMember", id, numToCastNum(id));
- _loadedCast->setVal(id, new TextCastMember(this, id, stream, _version, flags1));
+ target = new TextCastMember(this, id, stream, _version, flags1);
break;
case kCastShape:
debugC(3, kDebugLoading, "Cast::loadCastDataVWCR(): CastTypes id: %d(%s) ShapeCastMember", id, numToCastNum(id));
- _loadedCast->setVal(id, new ShapeCastMember(this, id, stream, _version));
+ target = new ShapeCastMember(this, id, stream, _version);
break;
case kCastButton:
debugC(3, kDebugLoading, "Cast::loadCastDataVWCR(): CastTypes id: %d(%s) ButtonCast", id, numToCastNum(id));
- _loadedCast->setVal(id, new TextCastMember(this, id, stream, _version, flags1, true));
+ target =new TextCastMember(this, id, stream, _version, flags1, true);
break;
case kCastSound:
debugC(3, kDebugLoading, "Cast::loadCastDataVWCR(): CastTypes id: %d(%s) SoundCastMember", id, numToCastNum(id));
- _loadedCast->setVal(id, new SoundCastMember(this, id, stream, _version));
+ target = new SoundCastMember(this, id, stream, _version);
break;
case kCastDigitalVideo:
debugC(3, kDebugLoading, "Cast::loadCastDataVWCR(): CastTypes id: %d(%s) DigitalVideoCastMember", id, numToCastNum(id));
- _loadedCast->setVal(id, new DigitalVideoCastMember(this, id, stream, _version));
+ target = new DigitalVideoCastMember(this, id, stream, _version);
break;
case kCastPalette:
debugC(3, kDebugLoading, "Cast::loadCastDataVWCR(): CastTypes id: %d(%s) PaletteCastMember", id, numToCastNum(id));
- _loadedCast->setVal(id, new PaletteCastMember(this, id, stream, _version));
+ target = new PaletteCastMember(this, id, stream, _version);
// load the palette now, as there are no CastInfo structs
- _loadedCast->getVal(id)->load();
+ target->load();
break;
case kCastFilmLoop:
debugC(3, kDebugLoading, "Cast::loadCastDataVWCR(): CastTypes id: %d(%s) FilmLoopCastMember", id, numToCastNum(id));
- _loadedCast->setVal(id, new FilmLoopCastMember(this, id, stream, _version));
+ target = new FilmLoopCastMember(this, id, stream, _version);
break;
default:
warning("Cast::loadCastDataVWCR(): Unhandled cast id: %d(%s), type: %d, %d bytes", id, numToCastNum(id), castType, size);
break;
}
+ if (target)
+ setCastMember(id, target);
stream.seek(returnPos);
}
}
@@ -1049,50 +1014,50 @@ void Cast::loadCastData(Common::SeekableReadStreamEndian &stream, uint16 id, Res
if (_loadedCast->contains(id)) {
warning("Cast::loadCastData(): Multiple cast members with ID %d, overwriting", id);
- delete _loadedCast->getVal(id);
- _loadedCast->erase(id);
+ eraseCastMember(id);
}
+ CastMember *target = nullptr;
switch (castType) {
case kCastBitmap:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastBitmap (%d children)", res->children.size());
- _loadedCast->setVal(id, new BitmapCastMember(this, id, castStream, res->tag, _version, flags1));
+ target = new BitmapCastMember(this, id, castStream, res->tag, _version, flags1);
break;
case kCastSound:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastSound (%d children)", res->children.size());
- _loadedCast->setVal(id, new SoundCastMember(this, id, castStream, _version));
+ target = new SoundCastMember(this, id, castStream, _version);
break;
case kCastText:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastText (%d children)", res->children.size());
- _loadedCast->setVal(id, new TextCastMember(this, id, castStream, _version, flags1));
+ target = new TextCastMember(this, id, castStream, _version, flags1);
break;
case kCastShape:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastShape (%d children)", res->children.size());
- _loadedCast->setVal(id, new ShapeCastMember(this, id, castStream, _version));
+ target = new ShapeCastMember(this, id, castStream, _version);
break;
case kCastButton:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastButton (%d children)", res->children.size());
- _loadedCast->setVal(id, new TextCastMember(this, id, castStream, _version, flags1, true));
+ target = new TextCastMember(this, id, castStream, _version, flags1, true);
break;
case kCastLingoScript:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastLingoScript");
- _loadedCast->setVal(id, new ScriptCastMember(this, id, castStream, _version));
+ target = new ScriptCastMember(this, id, castStream, _version);
break;
case kCastRichText:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastRichText (%d children)", res->children.size());
- _loadedCast->setVal(id, new RichTextCastMember(this, id, castStream, _version));
+ target = new RichTextCastMember(this, id, castStream, _version);
break;
case kCastDigitalVideo:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastDigitalVideo (%d children)", res->children.size());
- _loadedCast->setVal(id, new DigitalVideoCastMember(this, id, castStream, _version));
+ target = new DigitalVideoCastMember(this, id, castStream, _version);
break;
case kCastFilmLoop:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastFilmLoop (%d children)", res->children.size());
- _loadedCast->setVal(id, new FilmLoopCastMember(this, id, castStream, _version));
+ target = new FilmLoopCastMember(this, id, castStream, _version);
break;
case kCastPalette:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastPalette (%d children)", res->children.size());
- _loadedCast->setVal(id, new PaletteCastMember(this, id, castStream, _version));
+ target = new PaletteCastMember(this, id, castStream, _version);
break;
case kCastPicture:
warning("BUILDBOT: STUB: Cast::loadCastData(): kCastPicture (id=%d, %d children)! This will be missing from the movie and may cause problems", id, res->children.size());
@@ -1100,11 +1065,11 @@ void Cast::loadCastData(Common::SeekableReadStreamEndian &stream, uint16 id, Res
break;
case kCastMovie:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastMovie (id=%d, %d children)", id, res->children.size());
- _loadedCast->setVal(id, new MovieCastMember(this, id, castStream, _version));
+ target = new MovieCastMember(this, id, castStream, _version);
break;
case kCastTransition:
debugC(3, kDebugLoading, "Cast::loadCastData(): loading kCastTransition (id=%d, %d children)", id, res->children.size());
- _loadedCast->setVal(id, new TransitionCastMember(this, id, castStream, _version));
+ target = new TransitionCastMember(this, id, castStream, _version);
break;
default:
warning("BUILDBOT: STUB: Cast::loadCastData(): Unhandled cast type: %d [%s] (id=%d, %d children)! This will be missing from the movie and may cause problems", castType, tag2str(castType), id, res->children.size());
@@ -1112,6 +1077,9 @@ void Cast::loadCastData(Common::SeekableReadStreamEndian &stream, uint16 id, Res
castInfoSize = 0;
break;
}
+ if (target) {
+ setCastMember(id, target);
+ }
if (castStream.eos()) {
warning("BUILDBOT: Read past dataStream for id: %d type: %s", id, castType2str((CastType) castType));
}
@@ -1120,11 +1088,11 @@ void Cast::loadCastData(Common::SeekableReadStreamEndian &stream, uint16 id, Res
if (leftOver > 0)
warning("BUILDBOT: Left over bytes: %d in dataStream for id: %d type: %s", leftOver, id, castType2str((CastType) castType));
- if (_loadedCast->contains(id)) { // Skip unhandled casts
+ if (target) { // Skip unhandled casts
debugCN(3, kDebugLoading, "Children: ");
for (uint child = 0; child < res->children.size(); child++) {
debugCN(3, kDebugLoading, "%d ", res->children[child].index);
- _loadedCast->getVal(id)->_children.push_back(res->children[child]);
+ target->_children.push_back(res->children[child]);
}
debugCN(3, kDebugLoading, "\n");
}
diff --git a/engines/director/castmember/bitmap.cpp b/engines/director/castmember/bitmap.cpp
index e721c85f639..485e63f1e42 100644
--- a/engines/director/castmember/bitmap.cpp
+++ b/engines/director/castmember/bitmap.cpp
@@ -195,7 +195,8 @@ BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, BitmapCastMember &
_initialRect = source._initialRect;
_boundingRect = source._boundingRect;
- _children = source._children;
+ if (cast == source._cast)
+ _children = source._children;
_picture = source._picture ? new Picture(*source._picture) : nullptr;
_ditheredImg = nullptr;
diff --git a/engines/director/castmember/bitmap.h b/engines/director/castmember/bitmap.h
index 303f0955eb6..2538b7e67e6 100644
--- a/engines/director/castmember/bitmap.h
+++ b/engines/director/castmember/bitmap.h
@@ -37,6 +37,8 @@ public:
BitmapCastMember(Cast *cast, uint16 castId, BitmapCastMember &source);
~BitmapCastMember();
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new BitmapCastMember(cast, castId, *this)); }
+
Graphics::MacWidget *createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) override;
bool isModified() override;
diff --git a/engines/director/castmember/castmember.cpp b/engines/director/castmember/castmember.cpp
index e0685c309b8..84072797671 100644
--- a/engines/director/castmember/castmember.cpp
+++ b/engines/director/castmember/castmember.cpp
@@ -66,6 +66,11 @@ CastMember::CastMember(Cast *cast, uint16 castId) : Object<CastMember>("CastMemb
_erase = false;
}
+CastMember *CastMember::duplicate(Cast *cast, uint16 castId) {
+ warning("CastMember::duplicate(): unsupported cast type %s", castType2str(_type));
+ return nullptr;
+}
+
void CastMember::setModified(bool modified) {
_modified = modified;
if (modified)
diff --git a/engines/director/castmember/castmember.h b/engines/director/castmember/castmember.h
index 9519b3b9886..8a69af33081 100644
--- a/engines/director/castmember/castmember.h
+++ b/engines/director/castmember/castmember.h
@@ -50,6 +50,8 @@ public:
CastMember(Cast *cast, uint16 castId);
virtual ~CastMember() {}
+ virtual CastMember *duplicate(Cast *cast, uint16 castId);
+
Cast *getCast() { return _cast; }
uint16 getID() { return _castId; }
CastMemberInfo *getInfo();
diff --git a/engines/director/castmember/digitalvideo.cpp b/engines/director/castmember/digitalvideo.cpp
index 1ab10649ed8..06d0506e8f1 100644
--- a/engines/director/castmember/digitalvideo.cpp
+++ b/engines/director/castmember/digitalvideo.cpp
@@ -92,7 +92,8 @@ DigitalVideoCastMember::DigitalVideoCastMember(Cast *cast, uint16 castId, Digita
_initialRect = source._initialRect;
_boundingRect = source._boundingRect;
- _children = source._children;
+ if (cast == source._cast)
+ _children = source._children;
_filename = source._filename;
diff --git a/engines/director/castmember/digitalvideo.h b/engines/director/castmember/digitalvideo.h
index 4e545dfbd02..5ab694d06f0 100644
--- a/engines/director/castmember/digitalvideo.h
+++ b/engines/director/castmember/digitalvideo.h
@@ -42,6 +42,8 @@ public:
DigitalVideoCastMember(Cast *cast, uint16 castId, DigitalVideoCastMember &source);
~DigitalVideoCastMember();
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new DigitalVideoCastMember(cast, castId, *this)); }
+
bool isModified() override;
Graphics::MacWidget *createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) override;
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index a2d8eaed9dd..7f05d741163 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -67,7 +67,8 @@ FilmLoopCastMember::FilmLoopCastMember(Cast *cast, uint16 castId, FilmLoopCastMe
_initialRect = source._initialRect;
_boundingRect = source._boundingRect;
- _children = source._children;
+ if (cast == source._cast)
+ _children = source._children;
_enableSound = source._enableSound;
_crop = source._crop;
diff --git a/engines/director/castmember/filmloop.h b/engines/director/castmember/filmloop.h
index 1e291ae9d5e..2113acfadeb 100644
--- a/engines/director/castmember/filmloop.h
+++ b/engines/director/castmember/filmloop.h
@@ -38,6 +38,8 @@ public:
FilmLoopCastMember(Cast *cast, uint16 castId, FilmLoopCastMember &source);
~FilmLoopCastMember();
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new FilmLoopCastMember(cast, castId, *this)); }
+
bool isModified() override;
//Graphics::MacWidget *createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) override;
diff --git a/engines/director/castmember/movie.h b/engines/director/castmember/movie.h
index 703d422d1f6..8ee275109b6 100644
--- a/engines/director/castmember/movie.h
+++ b/engines/director/castmember/movie.h
@@ -31,6 +31,8 @@ public:
MovieCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version);
MovieCastMember(Cast *cast, uint16 castId, MovieCastMember &source);
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new MovieCastMember(cast, castId, *this)); }
+
Common::Array<Channel> *getSubChannels(Common::Rect &bbox, Channel *channel) override;
void load() override;
diff --git a/engines/director/castmember/palette.h b/engines/director/castmember/palette.h
index 78e5bb90f9d..874d226e169 100644
--- a/engines/director/castmember/palette.h
+++ b/engines/director/castmember/palette.h
@@ -31,6 +31,9 @@ public:
PaletteCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version);
PaletteCastMember(Cast *cast, uint16 castId, PaletteCastMember &source);
~PaletteCastMember();
+
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new PaletteCastMember(cast, castId, *this)); }
+
CastMemberID getPaletteId();
void activatePalette();
diff --git a/engines/director/castmember/richtext.cpp b/engines/director/castmember/richtext.cpp
index f0dfbdd88fc..d74c9a10fdb 100644
--- a/engines/director/castmember/richtext.cpp
+++ b/engines/director/castmember/richtext.cpp
@@ -64,6 +64,9 @@ RichTextCastMember::RichTextCastMember(Cast *cast, uint16 castId, RichTextCastMe
_initialRect = source._initialRect;
_boundingRect = source._boundingRect;
_bgColor = source._bgColor;
+ if (cast == source._cast)
+ _children = source._children;
+
}
RichTextCastMember::~RichTextCastMember() {
diff --git a/engines/director/castmember/richtext.h b/engines/director/castmember/richtext.h
index 427e2cffeb6..0728bdab70e 100644
--- a/engines/director/castmember/richtext.h
+++ b/engines/director/castmember/richtext.h
@@ -33,6 +33,8 @@ public:
RichTextCastMember(Cast *cast, uint16 castId, RichTextCastMember &source);
~RichTextCastMember();
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new RichTextCastMember(cast, castId, *this)); }
+
void load() override;
Graphics::MacWidget *createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) override;
diff --git a/engines/director/castmember/script.h b/engines/director/castmember/script.h
index 64cee79a4e4..79637eaba39 100644
--- a/engines/director/castmember/script.h
+++ b/engines/director/castmember/script.h
@@ -31,6 +31,8 @@ public:
ScriptCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version);
ScriptCastMember(Cast *cast, uint16 castId, ScriptCastMember &source);
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new ScriptCastMember(cast, castId, *this)); }
+
ScriptType _scriptType;
bool hasField(int field) override;
diff --git a/engines/director/castmember/shape.cpp b/engines/director/castmember/shape.cpp
index 7841bb0426b..d3680011628 100644
--- a/engines/director/castmember/shape.cpp
+++ b/engines/director/castmember/shape.cpp
@@ -88,7 +88,8 @@ ShapeCastMember::ShapeCastMember(Cast *cast, uint16 castId, ShapeCastMember &sou
_initialRect = source._initialRect;
_boundingRect = source._boundingRect;
- _children = source._children;
+ if (cast == source._cast)
+ _children = source._children;
_shapeType = source._shapeType;
_pattern = source._pattern;
diff --git a/engines/director/castmember/shape.h b/engines/director/castmember/shape.h
index 345e40ab803..ca2df0e0dca 100644
--- a/engines/director/castmember/shape.h
+++ b/engines/director/castmember/shape.h
@@ -30,6 +30,9 @@ class ShapeCastMember : public CastMember {
public:
ShapeCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version);
ShapeCastMember(Cast *cast, uint16 castId, ShapeCastMember &source);
+
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new ShapeCastMember(cast, castId, *this)); }
+
uint32 getForeColor() override { return _fgCol; }
uint32 getBackColor() override { return _bgCol; }
void setBackColor(uint32 bgCol) override;
diff --git a/engines/director/castmember/sound.cpp b/engines/director/castmember/sound.cpp
index ddd05a552b4..a854a88b378 100644
--- a/engines/director/castmember/sound.cpp
+++ b/engines/director/castmember/sound.cpp
@@ -40,6 +40,8 @@ SoundCastMember::SoundCastMember(Cast *cast, uint16 castId, SoundCastMember &sou
_loaded = false;
_audio = nullptr;
_looping = source._looping;
+ if (cast == source._cast)
+ _children = source._children;
warning("SoundCastMember(): Duplicating source %d to target %d! This is unlikely to work properly, as the resource loader is based on the cast ID", source._castId, castId);
}
diff --git a/engines/director/castmember/sound.h b/engines/director/castmember/sound.h
index 9c2b85c198f..79797d39be7 100644
--- a/engines/director/castmember/sound.h
+++ b/engines/director/castmember/sound.h
@@ -34,6 +34,8 @@ public:
SoundCastMember(Cast *cast, uint16 castId, SoundCastMember &source);
~SoundCastMember();
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new SoundCastMember(cast, castId, *this)); }
+
void load() override;
void unload() override;
Common::String formatInfo() override;
diff --git a/engines/director/castmember/text.cpp b/engines/director/castmember/text.cpp
index 4b9d53d9c22..c8aa180437c 100644
--- a/engines/director/castmember/text.cpp
+++ b/engines/director/castmember/text.cpp
@@ -167,7 +167,8 @@ TextCastMember::TextCastMember(Cast *cast, uint16 castId, TextCastMember &source
_initialRect = source._initialRect;
_boundingRect = source._boundingRect;
- _children = source._children;
+ if (cast == source._cast)
+ _children = source._children;
_borderSize = source._borderSize;
_gutterSize = source._gutterSize;
diff --git a/engines/director/castmember/text.h b/engines/director/castmember/text.h
index 6d551af24ee..a9d1201d025 100644
--- a/engines/director/castmember/text.h
+++ b/engines/director/castmember/text.h
@@ -34,6 +34,9 @@ class TextCastMember : public CastMember {
public:
TextCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version, uint8 flags1 = 0, bool asButton = false);
TextCastMember(Cast *cast, uint16 castId, TextCastMember &source);
+
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new TextCastMember(cast, castId, *this)); }
+
void setColors(uint32 *fgcolor, uint32 *bgcolor) override;
Graphics::MacWidget *createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) override;
diff --git a/engines/director/castmember/transition.h b/engines/director/castmember/transition.h
index b45781eb6c0..46fa295eb3f 100644
--- a/engines/director/castmember/transition.h
+++ b/engines/director/castmember/transition.h
@@ -31,6 +31,8 @@ public:
TransitionCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version);
TransitionCastMember(Cast *cast, uint16 castId, TransitionCastMember &source);
+ CastMember *duplicate(Cast *cast, uint16 castId) override { return (CastMember *)(new TransitionCastMember(cast, castId, *this)); }
+
bool hasField(int field) override;
Datum getField(int field) override;
bool setField(int field, const Datum &value) override;
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 8338fea221e..7bc8d930b61 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -1962,6 +1962,13 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
return d;
}
+ if (field == kTheMedia) {
+ // every time "the media" is invoked, a new copy is made.
+ member->load();
+ d = Datum(member->duplicate(nullptr, 0));
+ return d;
+ }
+
if (!member->hasField(field)) {
warning("Lingo::getTheCast(): %s has no property '%s'", id.asString().c_str(), field2str(field));
return d;
@@ -1987,6 +1994,17 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
return;
}
+ if (field == kTheMedia) {
+ if (d.type != MEDIA) {
+ warning("Lingo::setTheCast(): setting the media with a non-MEDIA object, ignoring");
+ return;
+ }
+ CastMember *replacement = (CastMember *)d.u.obj;
+ Cast *cast = movie->getCast(id);
+ cast->duplicateCastMember(replacement, nullptr, id.member);
+ return;
+ }
+
if (!member->hasField(field)) {
warning("Lingo::setTheCast(): %s has no property '%s'", id.asString().c_str(), field2str(field));
return;
@@ -2361,6 +2379,14 @@ void Lingo::getObjectProp(Datum &obj, Common::String &propName) {
return;
}
+ if (propName.equals("media")) {
+ // every time "the media" is invoked, a new copy is made.
+ member->load();
+ d = Datum(member->duplicate(nullptr, 0));
+ g_lingo->push(d);
+ return;
+ }
+
if (member->hasProp(propName)) {
d = member->getProp(propName);
} else {
@@ -2473,6 +2499,17 @@ void Lingo::setObjectProp(Datum &obj, Common::String &propName, Datum &val) {
return;
}
+ if (propName.equals("media")) {
+ if (val.type != MEDIA) {
+ warning("Lingo::setObjectProp(): setting the media with a non-MEDIA object, ignoring");
+ return;
+ }
+ CastMember *replacement = (CastMember *)val.u.obj;
+ Cast *cast = movie->getCast(id);
+ cast->duplicateCastMember(replacement, nullptr, id.member);
+ return;
+ }
+
if (member->hasProp(propName)) {
member->setProp(propName, val);
} else {
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 27890352208..f37b4d0b479 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -934,6 +934,20 @@ Datum::Datum(AbstractObject *val) {
ignoreGlobal = false;
}
+Datum::Datum(CastMember *val) {
+ u.obj = val;
+ if (val) {
+ type = MEDIA;
+ refCount = val->getRefCount();
+ *refCount += 1;
+ } else {
+ type = VOID;
+ refCount = new int;
+ *refCount = 1;
+ }
+ ignoreGlobal = false;
+}
+
Datum::Datum(const CastMemberID &val) {
u.cast = new CastMemberID(val);
type = CASTREF;
@@ -999,6 +1013,9 @@ void Datum::reset() {
case PARRAY:
delete u.parr;
break;
+ case MEDIA:
+ delete u.obj;
+ break;
case OBJECT:
if (u.obj->getObjType() == kWindowObj) {
// Window has an override for decRefCount, use it directly
@@ -1027,7 +1044,7 @@ void Datum::reset() {
warning("Datum::reset(): Unprocessed REF type %d", type);
break;
}
- if (type != OBJECT) // object owns refCount
+ if (type != OBJECT && type != MEDIA) // object owns refCount
delete refCount;
}
#endif
@@ -1144,6 +1161,9 @@ Common::String Datum::asString(bool printonly) const {
s = Common::String::format("#%s", u.s->c_str());
}
break;
+ case MEDIA:
+ s = Common::String::format("media %08x", ((uint32)(size_t)((void *)u.obj)) & 0xffffffff);
+ break;
case OBJECT:
if (!printonly) {
// Object names in Director are: "<Object:hex>"
@@ -1359,6 +1379,8 @@ const char *Datum::type2str(bool ilk) const {
return "LOCALREF";
case MENUREF:
return "MENUREF";
+ case MEDIA:
+ return ilk ? "media" : "MEDIA";
case OBJECT:
return ilk ? "object" : "OBJECT";
case PARRAY:
@@ -1408,6 +1430,7 @@ int Datum::equalTo(const Datum &d, bool ignoreCase) const {
} else {
return compareStringEquality(asString(), d.asString());
}
+ case MEDIA:
case OBJECT:
return u.obj == d.u.obj;
case CASTREF:
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 949a9679e51..efbee0070b4 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -154,6 +154,7 @@ struct Datum { /* interpreter stack type */
Datum(double val);
Datum(const Common::String &val);
Datum(AbstractObject *val);
+ Datum(CastMember *val);
Datum(const CastMemberID &val);
Datum(const Common::Point &point);
Datum(const Common::Rect &rect);
diff --git a/engines/director/types.h b/engines/director/types.h
index f3f019844b1..40278a2d553 100644
--- a/engines/director/types.h
+++ b/engines/director/types.h
@@ -375,6 +375,7 @@ enum DatumType {
GLOBALREF,
INT,
LOCALREF,
+ MEDIA,
MENUREF,
OBJECT,
PARRAY,
Commit: 39f18f87a36dc88a2d5d7185cfd1bf064412601d
https://github.com/scummvm/scummvm/commit/39f18f87a36dc88a2d5d7185cfd1bf064412601d
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Remove alternate palette format
I don't know what I was thinking when I added
bbce11c7edb08f0e8ce76fc934a89794ecea51d3, but it is possible to have
palettes with fewer than 256 colours and no header. None of the games I
checked seem to use this format, so it's gone for now.
Fixes palette loader for Pothead.
Changed paths:
engines/director/cast.cpp
diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 50988944bd7..1ab1822b5f9 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -789,32 +789,13 @@ PaletteV4 Cast::loadPalette(Common::SeekableReadStreamEndian &stream, int id) {
if (debugChannelSet(5, kDebugLoading))
stream.hexdump(stream.size());
- bool hasHeader = size != 6 * 256;
- int steps = 256;
- if (hasHeader) {
- stream.skip(6);
- steps = stream.readUint16();
- int maxSteps = (size - 8) / 8;
- if (steps > maxSteps) {
- warning("Cast::loadPalette(): header says %d steps but there's only enough data for %d, reducing", steps, maxSteps);
- steps = maxSteps;
- }
- }
+ int steps = size / 6;
debugC(3, kDebugLoading, "Cast::loadPalette(): %d steps", steps);
byte *palette = new byte[steps * 3];
-
int colorIndex = 0;
-
for (int i = 0; i < steps; i++) {
- if (hasHeader) {
- int index = stream.readUint16BE();
- if (index != 0x8000) {
- colorIndex = index;
- }
- }
-
if (colorIndex >= steps) {
warning("Cast::loadPalette(): attempted to set invalid color index %d, aborting", colorIndex);
break;
Commit: d99849b336e22444219c0a00b0b0dde51e42ca6c
https://github.com/scummvm/scummvm/commit/d99849b336e22444219c0a00b0b0dde51e42ca6c
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Implement the name of castLib setter
Changed paths:
engines/director/lingo/lingo-the.cpp
engines/director/movie.cpp
engines/director/movie.h
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 7bc8d930b61..86f3727bc8a 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -2082,7 +2082,7 @@ void Lingo::setTheCastLib(Datum &id1, int field, Datum &d) {
}
break;
case kTheName:
- warning("STUB: Lingo::setTheCastLib(): name not implemented");
+ movie->setCastLibName(d.asString(), id1.u.i);
break;
case kTheNumber:
warning("Lingo::setTheCastLib(): number is read-only");
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index 0d8d0a0757c..6cf2aff1f9a 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -557,6 +557,21 @@ int Movie::getCastLibIDByName(const Common::String &name) {
return -1;
}
+void Movie::setCastLibName(const Common::String &name, int castLib) {
+ if (!_casts.contains(castLib)) {
+ warning("Movie::setCastLibName: castLib %d not found", castLib);
+ return;
+ }
+ for (auto &it : _castNames) {
+ if (it._value == castLib) {
+ _castNames.erase(it._key);
+ }
+ }
+
+ _castNames[name] = castLib;
+ _casts[castLib]->setCastName(name);
+}
+
CastMemberID Movie::getCastMemberIDByName(const Common::String &name) {
return getCastMemberIDByNameAndType(name, 0, kCastTypeAny);
}
diff --git a/engines/director/movie.h b/engines/director/movie.h
index 8f59b71a36d..001fb0325bb 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -115,6 +115,7 @@ public:
bool duplicateCastMember(CastMemberID source, CastMemberID target);
CastMemberID getCastMemberIDByMember(int memberID);
int getCastLibIDByName(const Common::String &name);
+ void setCastLibName(const Common::String &name, int castLib);
CastMemberID getCastMemberIDByName(const Common::String &name);
CastMemberID getCastMemberIDByNameAndType(const Common::String &name, int castLib, CastType type);
CastMemberInfo *getCastMemberInfo(CastMemberID memberID);
Commit: 67199e61eb01662189ee32a9a26b710aa2ee67c7
https://github.com/scummvm/scummvm/commit/67199e61eb01662189ee32a9a26b710aa2ee67c7
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: LINGO: Fix range check in b_member
b_member will return a CASTREF as long as the member ID is within range
for that cast library; that is, less than or equal to the highest member
ID. It does not check that the cast member exists.
Fixes loading sequence of Gothos.
Changed paths:
engines/director/lingo/lingo-builtins.cpp
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index da4d51fe7ec..9728010d2fd 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -3550,8 +3550,6 @@ void LB::b_castLib(int nargs) {
}
void LB::b_member(int nargs) {
- Movie *movie = g_director->getCurrentMovie();
-
CastMemberID res;
if (nargs == 1) {
Datum member = g_lingo->pop();
@@ -3562,8 +3560,8 @@ void LB::b_member(int nargs) {
res = g_lingo->toCastMemberID(member, library);
}
- if (!movie->getCastMember(res)) {
- g_lingo->lingoError("No match found for cast member");
+ if (res.member > g_lingo->getMembersNum(res.castLib)) {
+ g_lingo->lingoError("b_member: Cast member ID out of range");
return;
}
g_lingo->push(res);
Commit: ec17b189427ad33eb9a106b4447f06d13bfe2f08
https://github.com/scummvm/scummvm/commit/ec17b189427ad33eb9a106b4447f06d13bfe2f08
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Add null check in TextCastMember::isWithin
Changed paths:
engines/director/castmember/text.cpp
diff --git a/engines/director/castmember/text.cpp b/engines/director/castmember/text.cpp
index c8aa180437c..d5dee1cd80e 100644
--- a/engines/director/castmember/text.cpp
+++ b/engines/director/castmember/text.cpp
@@ -384,7 +384,11 @@ CollisionTest TextCastMember::isWithin(const Common::Rect &bbox, const Common::P
if (!bbox.contains(pos))
return kCollisionNo;
- Graphics::MacWindowConstants::WindowClick result = getWidget()->isInScrollBar(pos.x, pos.y);
+ Graphics::MacText *target = getWidget();
+ if (!target)
+ return kCollisionYes;
+
+ Graphics::MacWindowConstants::WindowClick result = target->isInScrollBar(pos.x, pos.y);
if (result == Graphics::MacWindowConstants::kBorderScrollDown ||
result == Graphics::MacWindowConstants::kBorderScrollUp)
return kCollisionHole;
Commit: 972e7b150e25f6508a6bcf59ba76ba0c0a7cdb1f
https://github.com/scummvm/scummvm/commit/972e7b150e25f6508a6bcf59ba76ba0c0a7cdb1f
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Add Search for the Golden Dolphin to detection table
Changed paths:
engines/director/detection_tables.h
diff --git a/engines/director/detection_tables.h b/engines/director/detection_tables.h
index 61eb71451f0..fda3b726dc5 100644
--- a/engines/director/detection_tables.h
+++ b/engines/director/detection_tables.h
@@ -216,6 +216,7 @@ static const PlainGameDescriptor directorGames[] = {
{ "giggletour", "The Gigglebone Gang World Tour" },
{ "gigglevania", "Pantsylvania: The Kingdom of the Fancy Pants" },
{ "goferwinkel", "Goferwinkel's Adventures: The Lavender Land" },
+ { "goldendolphin", "Search for the Golden Dolphin" },
{ "goldilocks", "Goldilocks Gamebook" },
{ "gordak", "Gord at k" },
{ "gothos", "Gothos" },
@@ -8964,6 +8965,9 @@ static const DirectorGameDescription gameDescriptions[] = {
MACGAME1_l("glitzerschuppen", "", "GLITZERSCHUPPEN", "r:dec72b4b6f8e97f1ea24361794bf0bdf", 116459, Common::DE_DEU, 702),
WINGAME1_l("glitzerschuppen", "", "Glitzerschuppen.exe", "t:b04230237024e1c8e7f4d3920acba08a", 1820762, Common::DE_DEU, 702),
+ WINGAME1("goldendolphin", "", "files/Golden Dolphin/dolphin.exe", "t:f7faf63f4a68592cc83206874a89b54b", 2148101, 702),
+ MACGAME1("goldendolphin", "", "files/macinstall/Dolphin", "tr:fea0a7666493192c59b2051dd8485fe5", 114553, 702),
+
// Found on ã¢ã¯ãã£ããã¹ã³ããã»ãã¤ã¸ (Heidi Desktop Mascot) software from Inner Brain, Shinjuku, Tokyo
// Installers for the screen savers and other applications also use Director
// Original calculator filenames are ãã¤ã¸é»åï¼.exe, ãã¤ã¸é»åï¼.exe, ãã¤ã¸é»åï¼.exe
Commit: 87fd826f50716ffe5bfee4f3d9c4fdd7f53f3908
https://github.com/scummvm/scummvm/commit/87fd826f50716ffe5bfee4f3d9c4fdd7f53f3908
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Add perFrameHook recursion-break behaviour specific to D5
Changed paths:
engines/director/score.cpp
engines/director/window.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 3f0e9dfb624..2baf07edb9a 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -622,17 +622,20 @@ void Score::update() {
uint32 count = _window->frozenLingoStateCount();
- // new frame, first call the perFrameHook (if one exists)
- if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
- // Call the perFrameHook as soon as a frame switch is done.
- // If there is a transition, the perFrameHook is called
- // after each transition subframe instead of here.
- if (_currentFrame->_mainChannels.transType == 0 && _currentFrame->_mainChannels.trans.isNull()) {
- _lingo->executePerFrameHook(_curFrameNumber, 0);
+ // Director 4 and below will allow infinite recursion via the perFrameHook.
+ if (_vm->getVersion() < 500) {
+ // new frame, first call the perFrameHook (if one exists)
+ if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
+ // Call the perFrameHook as soon as a frame switch is done.
+ // If there is a transition, the perFrameHook is called
+ // after each transition subframe instead of here.
+ if (_currentFrame->_mainChannels.transType == 0 && _currentFrame->_mainChannels.trans.isNull()) {
+ _lingo->executePerFrameHook(_curFrameNumber, 0);
+ }
}
+ if (_window->frozenLingoStateCount() > count)
+ return;
}
- if (_window->frozenLingoStateCount() > count)
- return;
// Check to see if we've hit the recursion limit
if (_vm->getVersion() >= 400 && _window->frozenLingoRecursionCount() >= 2) {
@@ -645,6 +648,21 @@ void Score::update() {
return;
}
+ // Director 5 and above actually check for recursion for the perFrameHook.
+ if (_vm->getVersion() >= 500) {
+ // new frame, first call the perFrameHook (if one exists)
+ if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
+ // Call the perFrameHook as soon as a frame switch is done.
+ // If there is a transition, the perFrameHook is called
+ // after each transition subframe instead of here.
+ if (_currentFrame->_mainChannels.transType == 0 && _currentFrame->_mainChannels.trans.isNull()) {
+ _lingo->executePerFrameHook(_curFrameNumber, 0);
+ }
+ }
+ if (_window->frozenLingoStateCount() > count)
+ return;
+ }
+
if (_vm->getVersion() >= 600) {
// _movie->processEvent(kEventBeginSprite);
// TODO: Director 6 step: send beginSprite event to any sprites whose span begin in the upcoming frame
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index f0ee7a437a9..fbb11616699 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -438,6 +438,9 @@ void Window::updateBorderType() {
}
void Window::loadNewSharedCast(Cast *previousSharedCast) {
+ if (g_director->getVersion() >= 500)
+ return;
+
Common::Path previousSharedCastPath;
Common::Path newSharedCastPath = getSharedCastPath();
if (previousSharedCast && previousSharedCast->getArchive()) {
@@ -530,7 +533,8 @@ bool Window::loadNextMovie() {
debug(0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
g_director->setCurrentWindow(this);
- loadNewSharedCast(previousSharedCast);
+ if (g_director->getVersion() < 500)
+ loadNewSharedCast(previousSharedCast);
return true;
}
@@ -644,9 +648,6 @@ Common::Path Window::getSharedCastPath() {
}
} else if (_vm->getVersion() < 500) {
namesToTry.push_back("Shared.dir");
- } else {
- // TODO: Does D5 actually support D4-style shared cast?
- namesToTry.push_back("Shared.cst");
}
Common::Path result;
@@ -732,11 +733,14 @@ void Window::moveLingoState(Window *target) {
uint32 Window::frozenLingoRecursionCount() {
uint32 count = 0;
+ bool stepFrameCanRecurse = _vm->getVersion() < 500;
+
for (int i = (int)_frozenLingoStates.size() - 1; i >= 0; i--) {
LingoState *state = _frozenLingoStates[i];
CFrame *frame = state->callstack.front();
if (frame->sp.name->equalsIgnoreCase("enterFrame") ||
- frame->sp.name->equalsIgnoreCase("stepMovie")) {
+ frame->sp.name->equalsIgnoreCase("stepMovie") ||
+ (!stepFrameCanRecurse && frame->sp.name->equalsIgnoreCase("stepFrame"))) {
count++;
} else {
break;
Commit: ea899dba35ed3c1d900327ec3bbd87f58ee1b461
https://github.com/scummvm/scummvm/commit/ea899dba35ed3c1d900327ec3bbd87f58ee1b461
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: LINGO: Improve accuracy of 'the result'
Turns out the criteria was a bit different. the result does work with
recursive calls, the capture criteria is if the returned value
is otherwise discarded.
Fixes director-tests/D4-unit/T_LING03.DIR
Fixes sound playback in Pothead.
Changed paths:
engines/director/lingo/lingo-builtins.cpp
engines/director/lingo/lingo-code.cpp
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 9728010d2fd..31309de9503 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1986,8 +1986,6 @@ void LB::b_return(int nargs) {
Datum retVal;
if (nargs > 0) {
retVal = g_lingo->pop();
- if (retVal.type != VOID && g_lingo->_state->callstack.size() <= 2)
- g_lingo->_theResult = retVal; // Store result for possible reference
}
// clear any temp values from loops
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index abfeca5119f..2dbfd63d029 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -316,8 +316,10 @@ void Lingo::popContext(bool aborting) {
if (_state->stack.size() == fp->stackSizeBefore + 1) {
if (!fp->allowRetVal) {
- debugC(5, kDebugLingoExec, "dropping return value");
- pop();
+ debugC(5, kDebugLingoExec, "dropping return value, storing as the result");
+ Datum res = pop();
+ if (res.type != VOID)
+ g_lingo->_theResult = res;
}
} else if (_state->stack.size() == fp->stackSizeBefore) {
if (fp->allowRetVal) {
Commit: 50ef13bb300178b2f8f55ee0bd32b886d66c1c62
https://github.com/scummvm/scummvm/commit/50ef13bb300178b2f8f55ee0bd32b886d66c1c62
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Only write back from TextCastMember widget if in edit mode
Changed paths:
engines/director/castmember/castmember.h
engines/director/castmember/text.cpp
engines/director/castmember/text.h
engines/director/channel.cpp
diff --git a/engines/director/castmember/castmember.h b/engines/director/castmember/castmember.h
index 8a69af33081..76afa109adf 100644
--- a/engines/director/castmember/castmember.h
+++ b/engines/director/castmember/castmember.h
@@ -66,7 +66,7 @@ public:
void setModified(bool modified);
virtual Graphics::MacWidget *createWidget(Common::Rect &bbox, Channel *channel, SpriteType spriteType) { return nullptr; }
virtual void updateWidget(Graphics::MacWidget *widget, Channel *channel) {}
- virtual void updateFromWidget(Graphics::MacWidget *widget) {}
+ virtual void updateFromWidget(Graphics::MacWidget *widget, bool spriteEditable) {}
virtual Common::Rect getInitialRect() { return _initialRect; }
virtual void setColors(uint32 *fgcolor, uint32 *bgcolor) { return; }
diff --git a/engines/director/castmember/text.cpp b/engines/director/castmember/text.cpp
index d5dee1cd80e..599e1428bc0 100644
--- a/engines/director/castmember/text.cpp
+++ b/engines/director/castmember/text.cpp
@@ -572,8 +572,8 @@ void TextCastMember::setTextStyle(const Common::String &textStyle, int start, in
_modified = true;
}
-void TextCastMember::updateFromWidget(Graphics::MacWidget *widget) {
- if (widget) {
+void TextCastMember::updateFromWidget(Graphics::MacWidget *widget, bool spriteEditable) {
+ if (widget && (spriteEditable || _editable)) {
Common::String content = ((Graphics::MacText *)widget)->getEditedString();
content.replace('\n', '\r');
_ptext = content;
diff --git a/engines/director/castmember/text.h b/engines/director/castmember/text.h
index a9d1201d025..c6cd8302f61 100644
--- a/engines/director/castmember/text.h
+++ b/engines/director/castmember/text.h
@@ -47,7 +47,7 @@ public:
bool isEditable() override { return _editable; }
void setEditable(bool editable) override { _editable = editable; }
- void updateFromWidget(Graphics::MacWidget *widget) override;
+ void updateFromWidget(Graphics::MacWidget *widget, bool spriteEditable) override;
Graphics::TextAlign getAlignment();
uint32 getBackColor() override { return _bgcolor; }
diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index 3677745991a..92fa0097c2c 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -663,7 +663,7 @@ bool Channel::updateWidget() {
}
if (_widget && _widget->needsRedraw()) {
if (_sprite->_cast) {
- _sprite->_cast->updateFromWidget(_widget);
+ _sprite->_cast->updateFromWidget(_widget, _sprite->_editable);
}
_widget->draw();
return true;
Commit: 24747c4d6ae9ab410e798d1cf63e37821e77c849
https://github.com/scummvm/scummvm/commit/24747c4d6ae9ab410e798d1cf63e37821e77c849
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: LINGO: Implement the keyPressed
Changed paths:
engines/director/events.cpp
engines/director/lingo/lingo-the.cpp
engines/director/movie.h
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index 14e4ece7e9d..f485e8ff539 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -222,7 +222,7 @@ bool Movie::processEvent(Common::Event &event) {
case Common::EVENT_KEYDOWN:
_keyCode = _vm->_KeyCodes.contains(event.kbd.keycode) ? _vm->_KeyCodes[event.kbd.keycode] : 0;
- _key = (unsigned char)(event.kbd.ascii & 0xff);
+ _key = event.kbd.ascii;
_keyFlags = event.kbd.flags;
if (event.kbd.keycode == Common::KEYCODE_LSHIFT || event.kbd.keycode == Common::KEYCODE_RSHIFT ||
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 86f3727bc8a..75fe0058818 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -609,8 +609,11 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
}
break;
case kTheKey:
- d.type = STRING;
- d.u.s = new Common::String(movie->_key);
+ if (movie->_key < 0x80) {
+ d = Common::String::format("%c", (char)movie->_key);
+ } else {
+ d = Common::String();
+ }
break;
case kTheKeyCode:
d = movie->_keyCode;
@@ -622,6 +625,13 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
else
d.u.s = new Common::String();
break;
+ case kTheKeyPressed:
+ {
+ Common::U32String buf;
+ buf.insertChar(movie->_key, 0);
+ d = buf.encode();
+ }
+ break;
case kTheKeyUpScript:
d.type = STRING;
if (mainArchive->primaryEventHandlers.contains(kEventKeyUp))
diff --git a/engines/director/movie.h b/engines/director/movie.h
index 001fb0325bb..0dbf214a367 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -173,7 +173,7 @@ public:
int _nextEventId;
Common::Queue<LingoEvent> _inputEventQueue;
- unsigned char _key;
+ uint16 _key;
int _keyCode;
byte _keyFlags;
Commit: b96a8dd7039d01dffb76dd3d6cb322483164ac14
https://github.com/scummvm/scummvm/commit/b96a8dd7039d01dffb76dd3d6cb322483164ac14
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
MACGUI: Fix MacText::getMouse*
The output is expected to use line/character positioning instead of
row/column positioning; so if a line of text spans multiple rows, it
should be handled normally.
Fixes selecting inventory items after "Ptn of Random Teleport" in Derrat Sorcerum.
Changed paths:
graphics/macgui/mactext.cpp
graphics/macgui/mactext.h
diff --git a/graphics/macgui/mactext.cpp b/graphics/macgui/mactext.cpp
index 05f2664b7f6..b4fb2229b1a 100644
--- a/graphics/macgui/mactext.cpp
+++ b/graphics/macgui/mactext.cpp
@@ -1554,7 +1554,7 @@ int MacText::getMouseChar(int x, int y) {
y += _scrollPos;
int dx, dy, row, col;
- getRowCol(x, y, &dx, &dy, &row, &col);
+ getLineCharacter(x, y, &dx, &dy, &row, &col);
debug(5, "mouseChar: x: %d, y: %d, row: %d, col: %d", x, y, row, col);
int index = 1;
@@ -1576,7 +1576,7 @@ int MacText::getMouseWord(int x, int y) {
y += _scrollPos;
int dx, dy, row, col;
- getRowCol(x, y, &dx, &dy, &row, &col);
+ getLineCharacter(x, y, &dx, &dy, &row, &col);
int index = 1;
bool inWhitespace = true;
@@ -1648,7 +1648,7 @@ int MacText::getMouseItem(int x, int y) {
y += _scrollPos;
int dx, dy, row, col;
- getRowCol(x, y, &dx, &dy, &row, &col);
+ getLineCharacter(x, y, &dx, &dy, &row, &col);
// getMouseItem
// - starts from index 1
@@ -1706,7 +1706,7 @@ int MacText::getMouseLine(int x, int y) {
y += _scrollPos;
int dx, dy, row, col;
- getRowCol(x, y, &dx, &dy, &row, &col);
+ getLineCharacter(x, y, &dx, &dy, &row, &col);
return row + 1;
}
@@ -1718,7 +1718,7 @@ Common::U32String MacText::getMouseLink(int x, int y) {
y += _scrollPos;
int row, chunk;
- getRowCol(x, y, nullptr, nullptr, &row, nullptr, &chunk);
+ getLineCharacter(x, y, nullptr, nullptr, &row, nullptr, &chunk);
if (chunk < 0)
return Common::U32String();
@@ -1810,6 +1810,42 @@ void MacText::getRowCol(int x, int y, int *sx, int *sy, int *row, int *col, int
*chunk_ = (int)chunk;
}
+void MacText::getLineCharacter(int x, int y, int *sx, int *sy, int *line, int *character, int *chunk_) {
+ int nsx = 0, nsy = 0, nrow = 0, ncol = 0;
+ getRowCol(x, y, &nsx, &nsy, &nrow, &ncol, chunk_);
+
+ int nline = 0, ncharacter = 0;
+ // Determine the position in character space, taking into account newlines.
+ for (int i = 0; i < nrow; i++) {
+ if (_canvas._text[i].paragraphEnd) {
+ nline += 1;
+ ncharacter = 0;
+ } else {
+ for (auto &it : _canvas._text[i].chunks) {
+ ncharacter += it.text.size();
+ }
+ }
+ }
+
+
+ for (int i = 0; i < _canvas._text[nrow].chunks.size(); i++) {
+ Common::U32String &text = _canvas._text[nrow].chunks[i].text;
+ if (ncol > text.size()) {
+ ncol -= text.size();
+ ncharacter += text.size();
+ } else {
+ ncharacter += ncol;
+ }
+ }
+
+ if (line)
+ *line = nline;
+ if (character)
+ *character = ncharacter;
+}
+
+
+
Common::U32String MacText::getTextChunk(int startRow, int startCol, int endRow, int endCol, bool formatted, bool newlines) {
return _canvas.getTextChunk(startRow, startCol, endRow, endCol, formatted, newlines);
}
diff --git a/graphics/macgui/mactext.h b/graphics/macgui/mactext.h
index d29b189f39f..00d40407979 100644
--- a/graphics/macgui/mactext.h
+++ b/graphics/macgui/mactext.h
@@ -159,6 +159,7 @@ public:
void getChunkPosFromIndex(int index, uint &lineNum, uint &chunkNum, uint &offset);
void getRowCol(int x, int y, int *sx, int *sy, int *row, int *col, int *chunk_ = nullptr);
+ void getLineCharacter(int x, int y, int *sx, int *sy, int *line, int *character, int *chunk_ = nullptr);
Common::U32String getTextChunk(int startRow, int startCol, int endRow, int endCol, bool formatted = false, bool newlines = true);
Common::U32String getSelection(bool formatted = false, bool newlines = true);
Commit: 61ec96df112517a0dd5953fc75c280aa10f94d39
https://github.com/scummvm/scummvm/commit/61ec96df112517a0dd5953fc75c280aa10f94d39
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
GRAPHICS: MACGUI: Add debugging output to getTextChunk
Changed paths:
graphics/macgui/mactext-canvas.cpp
diff --git a/graphics/macgui/mactext-canvas.cpp b/graphics/macgui/mactext-canvas.cpp
index e2db3499cde..387604bb8dd 100644
--- a/graphics/macgui/mactext-canvas.cpp
+++ b/graphics/macgui/mactext-canvas.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/debug.h"
#include "common/tokenizer.h"
#include "common/unicode-bidi.h"
@@ -1042,16 +1043,23 @@ Common::U32String MacTextCanvas::getTextChunk(int startRow, int startCol, int en
continue;
}
+ Common::U32String nextChunk;
if (startCol <= 0) {
- ADDFORMATTING();
-
- if (endCol >= (int)_text[i].chunks[chunk].text.size())
- res += _text[i].chunks[chunk].text;
- else
- res += _text[i].chunks[chunk].text.substr(0, endCol);
+ if (endCol >= (int)_text[i].chunks[chunk].text.size()) {
+ nextChunk = _text[i].chunks[chunk].text;
+ } else {
+ nextChunk = _text[i].chunks[chunk].text.substr(0, endCol);
+ }
} else if ((int)_text[i].chunks[chunk].text.size() > startCol) {
+ nextChunk = _text[i].chunks[chunk].text.substr(startCol, endCol - startCol);
+ }
+
+ if (!nextChunk.empty()) {
ADDFORMATTING();
- res += _text[i].chunks[chunk].text.substr(startCol, endCol - startCol);
+ res += nextChunk;
+ if (debugLevelSet(5)) {
+ debugN(5, "MacTextCanvas::getTextChunk: row %d, startCol %d, endCol %d - %s\n", i, startCol, endCol, nextChunk.encode().c_str());
+ }
}
startCol -= _text[i].chunks[chunk].text.size();
@@ -1066,12 +1074,20 @@ Common::U32String MacTextCanvas::getTextChunk(int startRow, int startCol, int en
if (_text[i].chunks[chunk].text.empty()) // skip empty chunks
continue;
+ Common::U32String nextChunk;
+
if (startCol <= 0) {
- ADDFORMATTING();
- res += _text[i].chunks[chunk].text;
+ nextChunk = _text[i].chunks[chunk].text;
} else if ((int)_text[i].chunks[chunk].text.size() > startCol) {
+ nextChunk = _text[i].chunks[chunk].text.substr(startCol);
+ }
+
+ if (!nextChunk.empty()) {
ADDFORMATTING();
- res += _text[i].chunks[chunk].text.substr(startCol);
+ res += nextChunk;
+ if (debugLevelSet(5)) {
+ debugN(5, "MacTextCanvas::getTextChunk: (topline) row %d, startCol %d, endCol %d - %s\n", i, startCol, endCol, nextChunk.encode().c_str());
+ }
}
startCol -= _text[i].chunks[chunk].text.size();
@@ -1084,12 +1100,21 @@ Common::U32String MacTextCanvas::getTextChunk(int startRow, int startCol, int en
if (_text[i].chunks[chunk].text.empty()) // skip empty chunks
continue;
- ADDFORMATTING();
+ Common::U32String nextChunk;
- if (endCol >= (int)_text[i].chunks[chunk].text.size())
- res += _text[i].chunks[chunk].text;
- else
- res += _text[i].chunks[chunk].text.substr(0, endCol);
+ if (endCol >= (int)_text[i].chunks[chunk].text.size()) {
+ nextChunk = _text[i].chunks[chunk].text;
+ } else {
+ nextChunk = _text[i].chunks[chunk].text.substr(0, endCol);
+ }
+
+ if (!nextChunk.empty()) {
+ ADDFORMATTING();
+ res += nextChunk;
+ if (debugLevelSet(5)) {
+ debugN(5, "MacTextCanvas::getTextChunk: (endline) row %d, startCol %d, endCol %d - %s\n", i, startCol, endCol, nextChunk.encode().c_str());
+ }
+ }
endCol -= _text[i].chunks[chunk].text.size();
@@ -1104,6 +1129,9 @@ Common::U32String MacTextCanvas::getTextChunk(int startRow, int startCol, int en
ADDFORMATTING();
res += _text[i].chunks[chunk].text;
+ if (debugLevelSet(5)) {
+ debugN(5, "MacTextCanvas::getTextChunk: (midline) row %d, startCol %d, endCol %d - %s\n", i, startCol, endCol, _text[i].chunks[chunk].text.encode().c_str());
+ }
}
if (newlines && _text[i].paragraphEnd)
Commit: 96871a30dd0f66d3a637a63541eeaf4a0fc7a533
https://github.com/scummvm/scummvm/commit/96871a30dd0f66d3a637a63541eeaf4a0fc7a533
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Check before reloading castLibs
Changed paths:
engines/director/movie.cpp
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index 6cf2aff1f9a..048b04f5974 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -419,24 +419,34 @@ Archive *Movie::loadExternalCastFrom(Common::Path &filename) {
}
bool Movie::loadCastLibFrom(uint16 libId, Common::Path &filename) {
+ if (_casts.contains(libId)) {
+ Cast *cast = _casts[libId];
+ if (cast->getArchive()->getPathName() == filename) {
+ // CastLib is already loaded, change nothing
+ return false;
+ }
+ }
+
Archive *castArchive = loadExternalCastFrom(filename);
if (!castArchive) {
return false;
}
- Cast *cast = nullptr;
uint16 libResourceId = 1024;
Common::String name;
if (_casts.contains(libId)) {
- cast = _casts[libId];
+ Cast *cast = _casts[libId];
libResourceId = cast->_libResourceId;
name = cast->getCastName();
+ delete cast;
+ _casts.erase(libId);
}
- // FIXME: There's no lifetime handling for multiple castlibs in _casts.
- cast = new Cast(this, libId, false, true, libResourceId);
+
+ Cast *cast = new Cast(this, libId, false, true, libResourceId);
cast->setArchive(castArchive);
cast->loadConfig();
cast->loadCast();
+
_casts.setVal(libId, cast);
_score->refreshPointersForCastLib(libId);
return true;
Commit: fe2e7ebe7c006bc997259555421d8018820438ae
https://github.com/scummvm/scummvm/commit/fe2e7ebe7c006bc997259555421d8018820438ae
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: LINGO: Enable dirty flag when setting locH/locV for trails
Fixes the dot-to-dot puzzle in Interactive Bible for Kids: The Life of Paul
Changed paths:
engines/director/lingo/lingo-the.cpp
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 75fe0058818..4e2287bc8aa 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -1814,12 +1814,12 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
break;
case kTheLocH:
if (d.asInt() != channel->getPosition().x) {
- // adding the dirtyRect only when the trails is false. Other changes which will add dirtyRect may also apply this patch
- // this is for fixing the bug in jman-win. Currently, i've only patched the LocH, LocV and castNum since those are the only ones used in jman
+ // Only add a dirty rectangle for the original position if we're not rendering in trails mode.
+ // Otherwise, it will erase the trail.
if (!channel->_sprite->_trails) {
movie->getWindow()->addDirtyRect(channel->getBbox());
- channel->_dirty = true;
}
+ channel->_dirty = true;
channel->setPosition(d.asInt(), channel->getPosition().y);
}
@@ -1831,8 +1831,8 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
if (d.asInt() != channel->getPosition().y) {
if (!channel->_sprite->_trails) {
movie->getWindow()->addDirtyRect(channel->getBbox());
- channel->_dirty = true;
}
+ channel->_dirty = true;
channel->setPosition(channel->getPosition().x, d.asInt());
}
Commit: e0da2006d717aea63f87f6fbffdf58130bf8b50b
https://github.com/scummvm/scummvm/commit/e0da2006d717aea63f87f6fbffdf58130bf8b50b
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Allow AIFF playback in DigitalVideoCastMember
Fixes talking to the barmaid in Derrat Sorcerum.
Changed paths:
engines/director/castmember/digitalvideo.cpp
diff --git a/engines/director/castmember/digitalvideo.cpp b/engines/director/castmember/digitalvideo.cpp
index 06d0506e8f1..bd991c4ec62 100644
--- a/engines/director/castmember/digitalvideo.cpp
+++ b/engines/director/castmember/digitalvideo.cpp
@@ -19,12 +19,14 @@
*
*/
+#include "audio/decoders/aiff.h"
#include "common/macresman.h"
#include "graphics/paletteman.h"
#include "graphics/surface.h"
#include "graphics/macgui/macwidget.h"
+#include "video/video_decoder.h"
#include "video/avi_decoder.h"
#include "video/qt_decoder.h"
@@ -39,6 +41,46 @@
namespace Director {
+
+class NoVideoAIFFDecoder : public Video::VideoDecoder {
+
+protected:
+ class AIFFAudioTrack : public Video::VideoDecoder::AudioTrack {
+ private:
+ Audio::RewindableAudioStream *_audioStream = nullptr;
+ public:
+ AIFFAudioTrack(Audio::Mixer::SoundType soundType, Audio::RewindableAudioStream *stream) : AudioTrack(soundType) {
+ _audioStream = stream;
+ }
+
+ virtual Audio::AudioStream *getAudioStream() const {
+ return _audioStream;
+ }
+ };
+
+public:
+ bool loadFile(const Common::Path &filename) override {
+ Common::SeekableReadStream *file = Common::MacResManager::openFileOrDataFork(filename);
+ if (!file) {
+ delete file;
+ return false;
+ }
+
+ bool result = loadStream(file);
+ if (!result)
+ delete file;
+ return result;
+ }
+
+ virtual bool loadStream(Common::SeekableReadStream *stream) override {
+ addTrack(new AIFFAudioTrack(Audio::Mixer::SoundType::kSFXSoundType, Audio::makeAIFFStream(stream, DisposeAfterUse::Flag::NO)));
+ return true;
+ }
+
+};
+
+
+
DigitalVideoCastMember::DigitalVideoCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version)
: CastMember(cast, castId, stream) {
_type = kCastDigitalVideo;
@@ -144,11 +186,12 @@ bool DigitalVideoCastMember::loadVideo(Common::String path) {
// TODO: detect file type (AVI, QuickTime, FLIC) based on magic number,
// insert the right video decoder
- if (_video)
+ if (_video) {
delete _video;
+ _video = nullptr;
+ }
_filename = path;
- _video = new Video::QuickTimeDecoder();
Common::Path location = findPath(path);
if (location.empty()) {
@@ -156,34 +199,63 @@ bool DigitalVideoCastMember::loadVideo(Common::String path) {
return false;
}
- debugC(2, kDebugLoading, "Loading video %s -> %s", path.c_str(), location.toString(Common::Path::kNativeSeparator).c_str());
- bool result = _video->loadFile(location);
- if (!result) {
- delete _video;
- _video = nullptr;
+ Common::SeekableReadStream *copiedStream = Common::MacResManager::openFileOrDataFork(location);
+ if (!copiedStream) {
+ warning("DigitalVideoCastMember::loadVideo Failed to open %s", path.c_str());
+ return false;
+ }
- // Probe for empty file
- Common::MacResManager mgr;
- if (mgr.open(location)) {
- if (!mgr.hasDataFork()) {
- debugC(8, kDebugLevelGVideo, "DigitalVideoCastMember::loadVideo(): skipping empty stream");
- _emptyFile = true;
- }
+ uint32 magic1 = copiedStream->readUint32BE();
+ uint32 magic2 = copiedStream->readUint32BE();
+ uint32 magic3 = copiedStream->readUint32BE();
+ delete copiedStream;
+ bool result = false;
+ debugC(2, kDebugLoading, "Loading video %s -> %s", path.c_str(), location.toString(Common::Path::kNativeSeparator).c_str());
+ if (magic1 == MKTAG('F', 'O', 'R', 'M') &&
+ (magic3 == MKTAG('A', 'I', 'F', 'F') || magic3 == MKTAG('A', 'I', 'F', 'C'))) {
+ _video = new NoVideoAIFFDecoder();
+ result = _video->loadFile(location);
+ if (!result) {
+ delete _video;
+ _video = nullptr;
return false;
+ } else {
+ // Pretend that this is our friend QuickTime
+ _videoType = kDVQuickTime;
}
+ } else if (magic2 == MKTAG('m', 'o', 'o', 'v') || magic2 == MKTAG('m', 'd', 'a', 't')) {
+ _video = new Video::QuickTimeDecoder();
+ result = _video->loadFile(location);
+ if (!result) {
+ delete _video;
+ _video = nullptr;
+
+ // Probe for empty file
+ Common::MacResManager mgr;
+ if (mgr.open(location)) {
+ if (!mgr.hasDataFork()) {
+ debugC(8, kDebugLevelGVideo, "DigitalVideoCastMember::loadVideo(): skipping empty stream");
+ _emptyFile = true;
+ }
+
+ return false;
+ }
+ } else {
+ _videoType = kDVQuickTime;
+ }
+ } else if (magic1 == MKTAG('R', 'I', 'F', 'F') && (magic3 == MKTAG('A', 'V', 'I', ' '))) {
_video = new Video::AVIDecoder();
result = _video->loadFile(location);
if (!result) {
warning("DigitalVideoCastMember::loadVideo(): format not supported, skipping video '%s'", path.c_str());
delete _video;
_video = nullptr;
+ return false;
} else {
_videoType = kDVVideoForWindows;
}
- } else {
- _videoType = kDVQuickTime;
}
if (result && g_director->_pixelformat.bytesPerPixel == 1) {
Commit: ae8a9b0b999fd6d2619c964e5eeb29493c228d85
https://github.com/scummvm/scummvm/commit/ae8a9b0b999fd6d2619c964e5eeb29493c228d85
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Keep track of old sprite bboxes for rollOver
Apparently this is also used for for constraint checks.
Fixes mouse code in the Barber Joe minigame of Rodney's Funscreen.
Changed paths:
engines/director/channel.cpp
engines/director/channel.h
engines/director/lingo/lingo-builtins.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index 92fa0097c2c..db14e8d2631 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -265,6 +265,15 @@ bool Channel::isDirty(Sprite *nextSprite) {
return isDirtyFlag;
}
+Common::Rect Channel::getRollOverBbox() {
+ // In D4 and below, the rollOver command will check against whatever the last
+ // contents of the sprite were, regardless of whether the score has zeroed it out.
+ if (g_director->getVersion() < 500 && _sprite->_castId.member == 0) {
+ return _rollOverBbox;
+ }
+ return getBbox();
+}
+
bool Channel::isStretched() {
return _sprite->_stretch;
}
@@ -582,7 +591,7 @@ void Channel::replaceSprite(Sprite *nextSprite) {
void Channel::setPosition(int x, int y, bool force) {
Common::Point newPos(x, y);
if (_constraint > 0 && _score && _constraint <= _score->_channels.size()) {
- Common::Rect constraintBbox = _score->_channels[_constraint]->getBbox();
+ Common::Rect constraintBbox = _score->_channels[_constraint]->getRollOverBbox();
newPos.x = MIN(constraintBbox.right, MAX(constraintBbox.left, newPos.x));
newPos.y = MIN(constraintBbox.bottom, MAX(constraintBbox.top, newPos.y));
}
diff --git a/engines/director/channel.h b/engines/director/channel.h
index df75a9f18a2..7360959f34b 100644
--- a/engines/director/channel.h
+++ b/engines/director/channel.h
@@ -52,6 +52,7 @@ public:
inline Common::Point getPosition() { return _sprite->getPosition(); };
// Return the area of screen to be used for drawing content.
inline Common::Rect getBbox(bool unstretched = false) { return _sprite->getBbox(unstretched); };
+ Common::Rect getRollOverBbox();
bool isStretched();
bool isDirty(Sprite *nextSprite = nullptr);
@@ -116,6 +117,8 @@ public:
// Used in film loops
uint _filmLoopFrame;
+ Common::Rect _rollOverBbox;
+
private:
Graphics::ManagedSurface *getSurface();
Score *_score;
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index 31309de9503..b8da9835a3e 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -2979,7 +2979,7 @@ void LB::b_rollOver(int nargs) {
Common::Point pos = g_director->getCurrentWindow()->getMousePos();
- if (score->checkSpriteIntersection(arg, pos))
+ if (score->checkSpriteRollOver(arg, pos))
res.u.i = 1; // TRUE
g_lingo->push(res);
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 2baf07edb9a..0037c5b57b4 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -471,6 +471,17 @@ void Score::updateCurrentFrame() {
}
if (_curFrameNumber != nextFrameNumberToLoad) {
+ // Cache the previous bounding box for the purposes of rollOver.
+ // If the sprite is blank, D4 and below will use whatever the previous valid bounding
+ // box was for rollOver testing.
+ if (g_director->getVersion() < 500) {
+ for (uint ch = 0; ch < _channels.size(); ch++) {
+ if (_channels[ch]->_sprite->_castId.member != 0) {
+ _channels[ch]->_rollOverBbox = _channels[ch]->getBbox();
+ }
+ }
+ }
+
// Load the current sprite information into the _currentFrame data store.
// This is specifically because of delta updates; loading the next frame
// in the score applies delta changes to _currentFrame, and ideally we want
@@ -1522,8 +1533,8 @@ uint16 Score::getActiveSpriteIDFromPos(Common::Point pos) {
return 0;
}
-bool Score::checkSpriteIntersection(uint16 spriteId, Common::Point pos) {
- if (_channels[spriteId]->getBbox().contains(pos))
+bool Score::checkSpriteRollOver(uint16 spriteId, Common::Point pos) {
+ if (_channels[spriteId]->getRollOverBbox().contains(pos))
return true;
return false;
diff --git a/engines/director/score.h b/engines/director/score.h
index c2c1b07395a..75531ebce06 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -112,7 +112,7 @@ public:
uint16 getSpriteIDFromPos(Common::Point pos);
uint16 getMouseSpriteIDFromPos(Common::Point pos);
uint16 getActiveSpriteIDFromPos(Common::Point pos);
- bool checkSpriteIntersection(uint16 spriteId, Common::Point pos);
+ bool checkSpriteRollOver(uint16 spriteId, Common::Point pos);
Common::List<Channel *> getSpriteIntersections(const Common::Rect &r);
uint16 getSpriteIdByMemberId(CastMemberID id);
bool refreshPointersForCastMemberID(CastMemberID id);
Commit: 5f8a9621bb1c49e9accd5267e75ba77977d9d067
https://github.com/scummvm/scummvm/commit/5f8a9621bb1c49e9accd5267e75ba77977d9d067
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Fix parsing "when mousedown then"
Director reads until the end of the line after "then" and sets the Lingo
event handler to that expression. This could be a newline immediately
after "then".
Fixes script execution in the Barber Joe minigame of Rodney's Funscreen.
Changed paths:
engines/director/lingo/lingo-lex.cpp
engines/director/lingo/lingo-lex.l
diff --git a/engines/director/lingo/lingo-lex.cpp b/engines/director/lingo/lingo-lex.cpp
index c5a66926f7b..e371f81c756 100644
--- a/engines/director/lingo/lingo-lex.cpp
+++ b/engines/director/lingo/lingo-lex.cpp
@@ -364,7 +364,7 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static const flex_int16_t yy_accept[370] =
+static const flex_int16_t yy_accept[368] =
{ 0,
0, 0, 93, 91, 1, 89, 89, 91, 91, 88,
88, 87, 88, 84, 88, 85, 85, 85, 85, 85,
@@ -404,8 +404,8 @@ static const flex_int16_t yy_accept[370] =
0, 0, 21, 85, 85, 43, 85, 0, 0, 0,
0, 85, 29, 85, 0, 0, 0, 0, 3, 85,
0, 0, 0, 0, 0, 0, 85, 0, 0, 0,
- 0, 0, 85, 0, 0, 85, 0, 0, 85, 0,
- 85, 72, 0, 85, 72, 72, 72, 61, 0
+ 0, 0, 85, 0, 0, 85, 0, 0, 85, 72,
+ 85, 72, 72, 72, 85, 61, 0
} ;
static const YY_CHAR yy_ec[256] =
@@ -451,36 +451,36 @@ static const YY_CHAR yy_meta[64] =
5, 1, 2
} ;
-static const flex_int16_t yy_base[377] =
+static const flex_int16_t yy_base[375] =
{ 0,
- 0, 62, 472, 829, 66, 829, 829, 460, 0, 829,
- 436, 55, 59, 829, 425, 58, 56, 61, 62, 59,
+ 0, 62, 466, 823, 66, 823, 823, 439, 0, 823,
+ 429, 55, 59, 823, 404, 58, 56, 61, 62, 59,
57, 63, 56, 98, 0, 101, 108, 109, 137, 138,
- 74, 179, 181, 133, 64, 355, 130, 182, 243, 212,
- 829, 239, 252, 829, 0, 829, 240, 84, 829, 829,
- 829, 0, 105, 103, 104, 119, 139, 143, 148, 150,
+ 74, 179, 181, 133, 64, 243, 130, 182, 239, 212,
+ 823, 196, 245, 823, 0, 823, 178, 84, 823, 823,
+ 823, 0, 105, 103, 104, 119, 139, 143, 148, 150,
158, 175, 186, 160, 196, 204, 211, 201, 235, 212,
0, 212, 220, 210, 218, 220, 232, 227, 239, 219,
226, 235, 0, 0, 233, 0, 249, 251, 233, 254,
259, 239, 257, 257, 261, 281, 273, 281, 275, 0,
- 285, 278, 281, 286, 334, 303, 127, 302, 0, 175,
+ 285, 278, 281, 286, 334, 303, 124, 302, 0, 166,
290, 304, 0, 297, 294, 299, 300, 312, 322, 317,
- 327, 346, 319, 331, 331, 343, 358, 115, 338, 331,
+ 327, 346, 319, 331, 331, 343, 358, 113, 338, 331,
343, 339, 334, 350, 353, 340, 360, 339, 355, 0,
356, 349, 0, 368, 360, 354, 364, 372, 0, 385,
372, 384, 383, 0, 381, 385, 393, 387, 393, 392,
404, 398, 401, 406, 408, 414, 419, 420, 406, 425,
415, 420, 426, 421, 440, 0, 424, 0, 0, 458,
- 113, 0, 441, 445, 450, 438, 437, 456, 442, 0,
+ 111, 0, 441, 445, 450, 438, 437, 456, 442, 0,
445, 0, 446, 0, 452, 463, 462, 455, 467, 0,
468, 0, 0, 468, 473, 483, 466, 472, 476, 472,
481, 475, 479, 0, 0, 0, 522, 494, 489, 491,
487, 497, 497, 503, 498, 0, 515, 513, 0, 516,
- 521, 0, 0, 0, 517, 829, 525, 518, 515, 0,
+ 521, 0, 0, 0, 517, 823, 525, 518, 515, 0,
0, 0, 517, 516, 0, 532, 0, 523, 528, 528,
- 528, 537, 534, 538, 0, 0, 532, 544, 576, 111,
+ 528, 537, 534, 538, 0, 0, 532, 544, 576, 108,
0, 543, 555, 0, 0, 558, 558, 539, 0, 575,
565, 0, 0, 0, 0, 577, 576, 0, 578, 0,
0, 566, 571, 0, 0, 0, 578, 0, 0, 579,
@@ -488,60 +488,60 @@ static const flex_int16_t yy_base[377] =
612, 606, 602, 599, 626, 606, 611, 619, 609, 0,
615, 0, 0, 0, 617, 619, 0, 0, 620, 624,
- 622, 636, 829, 640, 629, 0, 630, 634, 634, 653,
+ 622, 636, 823, 640, 629, 0, 630, 634, 634, 653,
647, 660, 0, 661, 646, 686, 672, 655, 0, 661,
- 665, 692, 108, 666, 668, 667, 668, 705, 681, 672,
+ 665, 692, 82, 666, 668, 667, 668, 705, 681, 672,
715, 717, 690, 692, 685, 697, 702, 732, 707, 737,
- 711, 739, 82, 712, 0, 745, 79, 0, 829, 808,
- 79, 810, 812, 816, 818, 823
+ 711, 0, 739, 79, 712, 0, 823, 802, 79, 804,
+ 806, 810, 812, 817
} ;
-static const flex_int16_t yy_def[377] =
+static const flex_int16_t yy_def[375] =
{ 0,
- 369, 1, 369, 369, 369, 369, 369, 370, 371, 369,
- 369, 369, 369, 369, 369, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 369, 369, 372, 369, 369,
- 369, 369, 370, 369, 373, 369, 369, 369, 369, 369,
- 369, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
-
- 372, 372, 372, 372, 369, 369, 369, 372, 373, 369,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 369, 369, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 369, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 374,
- 369, 372, 372, 372, 372, 369, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
-
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 369, 372, 372, 372, 372, 372, 372, 372,
- 372, 375, 372, 372, 372, 369, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 369, 369,
- 372, 372, 372, 372, 372, 369, 372, 372, 372, 372,
- 372, 372, 375, 372, 372, 372, 372, 372, 372, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 369,
- 369, 369, 372, 372, 369, 372, 372, 372, 372, 372,
-
- 372, 372, 372, 372, 372, 369, 369, 369, 369, 372,
- 372, 372, 372, 372, 372, 372, 372, 372, 372, 369,
- 369, 369, 369, 372, 372, 372, 372, 369, 369, 369,
- 369, 372, 372, 372, 369, 369, 369, 369, 372, 372,
- 369, 369, 369, 369, 369, 369, 372, 369, 369, 369,
- 369, 369, 372, 369, 369, 372, 369, 369, 372, 369,
- 372, 376, 369, 372, 376, 376, 376, 372, 0, 369,
- 369, 369, 369, 369, 369, 369
+ 367, 1, 367, 367, 367, 367, 367, 368, 369, 367,
+ 367, 367, 367, 367, 367, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 367, 367, 370, 367, 367,
+ 367, 367, 368, 367, 371, 367, 367, 367, 367, 367,
+ 367, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+
+ 370, 370, 370, 370, 367, 367, 367, 370, 371, 367,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 367, 367, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 367, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 372,
+ 367, 370, 370, 370, 370, 367, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 367, 370, 370, 370, 370, 370, 370, 370,
+ 370, 373, 370, 370, 370, 367, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 367, 367,
+ 370, 370, 370, 370, 370, 367, 370, 370, 370, 370,
+ 370, 370, 373, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 367,
+ 367, 367, 370, 370, 367, 370, 370, 370, 370, 370,
+
+ 370, 370, 370, 370, 370, 367, 367, 367, 367, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 367,
+ 367, 367, 367, 370, 370, 370, 370, 367, 367, 367,
+ 367, 370, 370, 370, 367, 367, 367, 367, 370, 370,
+ 367, 367, 367, 367, 367, 367, 370, 367, 367, 367,
+ 367, 367, 370, 367, 367, 370, 367, 367, 370, 374,
+ 370, 374, 374, 374, 370, 370, 0, 367, 367, 367,
+ 367, 367, 367, 367
} ;
-static const flex_int16_t yy_nxt[893] =
+static const flex_int16_t yy_nxt[887] =
{ 0,
4, 5, 6, 7, 5, 8, 9, 10, 11, 4,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
@@ -558,11 +558,11 @@ static const flex_int16_t yy_nxt[893] =
67, 68, 59, 62, 69, 74, 90, 71, 65, 104,
111, 113, 77, 75, 39, 72, 78, 80, 42, 76,
73, 105, 41, 41, 105, 112, 79, 81, 114, 74,
- 366, 71, 82, 362, 111, 113, 77, 75, 72, 106,
+ 363, 71, 82, 342, 111, 113, 77, 75, 72, 106,
78, 80, 76, 73, 101, 102, 83, 116, 112, 79,
- 81, 103, 114, 87, 84, 82, 85, 86, 88, 342,
- 115, 89, 259, 106, 180, 117, 127, 122, 101, 102,
- 83, 116, 118, 119, 103, 110, 87, 84, 105, 85,
+ 81, 103, 114, 87, 84, 82, 85, 86, 88, 259,
+ 115, 89, 180, 106, 127, 117, 110, 122, 101, 102,
+ 83, 116, 118, 119, 103, 105, 87, 84, 110, 85,
86, 88, 107, 115, 89, 91, 108, 92, 117, 97,
93, 122, 98, 99, 66, 118, 119, 94, 95, 100,
@@ -570,13 +570,13 @@ static const flex_int16_t yy_nxt[893] =
108, 92, 124, 97, 93, 125, 98, 99, 66, 126,
94, 95, 100, 120, 96, 67, 127, 129, 132, 127,
121, 133, 123, 130, 131, 134, 124, 135, 136, 125,
- 110, 145, 126, 137, 138, 142, 140, 44, 143, 139,
+ 44, 145, 126, 137, 138, 142, 140, 40, 143, 139,
129, 144, 132, 146, 133, 149, 130, 131, 134, 147,
135, 154, 136, 141, 42, 145, 137, 138, 142, 148,
140, 143, 139, 150, 144, 155, 151, 146, 149, 152,
156, 157, 153, 147, 154, 158, 141, 128, 159, 160,
- 40, 161, 148, 162, 105, 164, 150, 163, 155, 151,
+ 105, 161, 148, 162, 40, 164, 150, 163, 155, 151,
165, 166, 152, 156, 157, 153, 167, 168, 169, 158,
170, 159, 171, 160, 161, 172, 173, 162, 164, 174,
176, 163, 175, 165, 166, 105, 41, 41, 105, 167,
@@ -588,13 +588,13 @@ static const flex_int16_t yy_nxt[893] =
186, 203, 193, 195, 190, 197, 107, 194, 204, 196,
198, 205, 199, 206, 200, 207, 208, 201, 181, 209,
- 202, 210, 211, 186, 203, 212, 40, 213, 214, 215,
+ 202, 210, 211, 186, 203, 212, 51, 213, 214, 215,
128, 204, 216, 219, 205, 217, 218, 206, 207, 220,
- 208, 221, 209, 222, 210, 211, 223, 51, 224, 212,
- 213, 214, 215, 225, 46, 226, 216, 219, 217, 218,
+ 208, 221, 209, 222, 210, 211, 223, 46, 224, 212,
+ 213, 214, 215, 225, 44, 226, 216, 219, 217, 218,
227, 228, 229, 220, 230, 221, 231, 222, 233, 180,
- 223, 224, 180, 234, 235, 44, 236, 225, 226, 237,
- 238, 369, 239, 227, 228, 229, 240, 241, 230, 231,
+ 223, 224, 180, 234, 235, 367, 236, 225, 226, 237,
+ 238, 367, 239, 227, 228, 229, 240, 241, 230, 231,
242, 243, 233, 246, 244, 247, 248, 234, 235, 236,
249, 250, 237, 245, 238, 239, 252, 251, 256, 240,
@@ -602,12 +602,12 @@ static const flex_int16_t yy_nxt[893] =
248, 258, 261, 263, 249, 250, 245, 262, 264, 252,
181, 251, 256, 259, 253, 254, 259, 255, 265, 266,
257, 267, 268, 269, 258, 270, 261, 263, 271, 272,
- 262, 264, 274, 275, 369, 276, 277, 278, 279, 280,
+ 262, 264, 274, 275, 367, 276, 277, 278, 279, 280,
288, 265, 266, 281, 267, 268, 282, 269, 283, 270,
284, 297, 271, 272, 285, 274, 286, 275, 276, 277,
278, 279, 287, 280, 288, 289, 281, 259, 293, 282,
259, 283, 294, 284, 260, 297, 295, 285, 296, 286,
- 298, 369, 299, 300, 301, 287, 302, 306, 289, 303,
+ 298, 367, 299, 300, 301, 287, 302, 306, 289, 303,
290, 293, 291, 304, 305, 294, 307, 309, 292, 295,
308, 296, 310, 311, 298, 299, 312, 300, 301, 313,
@@ -622,29 +622,27 @@ static const flex_int16_t yy_nxt[893] =
353, 339, 354, 340, 341, 345, 342, 355, 356, 342,
357, 346, 358, 344, 347, 348, 342, 350, 342, 342,
- 351, 342, 352, 353, 349, 369, 354, 359, 345, 360,
- 355, 369, 356, 342, 357, 358, 342, 361, 362, 364,
- 366, 362, 368, 366, 369, 369, 366, 349, 343, 366,
- 359, 369, 360, 369, 343, 369, 369, 369, 369, 369,
- 361, 369, 364, 369, 369, 368, 369, 343, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 343, 369, 343,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 343, 369, 369, 369, 369, 363,
-
- 369, 367, 369, 369, 369, 369, 369, 367, 43, 43,
- 369, 43, 43, 52, 52, 109, 109, 232, 369, 369,
- 232, 273, 273, 365, 365, 369, 365, 365, 3, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369
-
+ 351, 342, 352, 353, 349, 367, 354, 359, 345, 360,
+ 355, 367, 356, 342, 357, 358, 342, 361, 363, 365,
+ 363, 363, 366, 363, 367, 367, 367, 349, 343, 367,
+ 359, 367, 360, 367, 343, 367, 367, 367, 367, 367,
+ 361, 367, 365, 367, 367, 366, 367, 343, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 343, 367, 343,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 343, 367, 367, 367, 367, 364,
+
+ 367, 364, 43, 43, 367, 43, 43, 52, 52, 109,
+ 109, 232, 367, 367, 232, 273, 273, 362, 362, 367,
+ 362, 362, 3, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367
} ;
-static const flex_int16_t yy_chk[893] =
+static const flex_int16_t yy_chk[887] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -654,18 +652,18 @@ static const flex_int16_t yy_chk[893] =
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 12, 12, 2, 5, 5, 5,
5, 13, 13, 16, 17, 18, 19, 16, 23, 21,
- 19, 2, 18, 371, 20, 16, 20, 21, 22, 18,
+ 19, 2, 18, 369, 20, 16, 20, 21, 22, 18,
19, 22, 31, 48, 48, 20, 35, 16, 17, 18,
19, 16, 23, 21, 19, 2, 18, 20, 16, 20,
21, 22, 18, 19, 22, 26, 31, 24, 20, 35,
53, 55, 27, 26, 2, 24, 27, 28, 5, 26,
24, 37, 37, 37, 37, 54, 27, 28, 56, 26,
- 367, 24, 28, 363, 53, 55, 27, 26, 24, 37,
+ 364, 24, 28, 343, 53, 55, 27, 26, 24, 37,
27, 28, 26, 24, 34, 34, 29, 58, 54, 27,
- 28, 34, 56, 30, 29, 28, 29, 29, 30, 343,
- 57, 30, 260, 37, 181, 59, 128, 64, 34, 34,
- 29, 58, 60, 61, 34, 110, 30, 29, 107, 29,
+ 28, 34, 56, 30, 29, 28, 29, 29, 30, 260,
+ 57, 30, 181, 37, 128, 59, 110, 64, 34, 34,
+ 29, 58, 60, 61, 34, 107, 30, 29, 47, 29,
29, 30, 37, 57, 30, 32, 38, 32, 59, 33,
32, 64, 33, 33, 38, 60, 61, 32, 32, 33,
@@ -673,13 +671,13 @@ static const flex_int16_t yy_chk[893] =
38, 32, 66, 33, 32, 67, 33, 33, 38, 68,
32, 32, 33, 62, 32, 38, 69, 70, 73, 69,
63, 74, 65, 72, 72, 75, 66, 76, 77, 67,
- 47, 85, 68, 78, 78, 80, 79, 43, 81, 78,
+ 43, 85, 68, 78, 78, 80, 79, 42, 81, 78,
70, 82, 73, 87, 74, 89, 72, 72, 75, 88,
76, 92, 77, 79, 40, 85, 78, 78, 80, 88,
79, 81, 78, 90, 82, 93, 90, 87, 89, 91,
94, 95, 91, 88, 92, 96, 79, 69, 97, 98,
- 42, 99, 88, 101, 39, 102, 90, 101, 93, 90,
+ 39, 99, 88, 101, 36, 102, 90, 101, 93, 90,
102, 103, 91, 94, 95, 91, 104, 106, 108, 96,
111, 97, 112, 98, 99, 114, 115, 101, 102, 116,
118, 101, 117, 102, 103, 105, 105, 105, 105, 104,
@@ -691,13 +689,13 @@ static const flex_int16_t yy_chk[893] =
127, 146, 134, 136, 131, 138, 105, 135, 147, 137,
139, 148, 141, 150, 142, 151, 152, 144, 122, 153,
- 145, 155, 156, 127, 146, 157, 36, 158, 159, 160,
+ 145, 155, 156, 127, 146, 157, 15, 158, 159, 160,
127, 147, 161, 164, 148, 162, 163, 150, 151, 165,
- 152, 166, 153, 167, 155, 156, 168, 15, 169, 157,
- 158, 159, 160, 170, 11, 171, 161, 164, 162, 163,
+ 152, 166, 153, 167, 155, 156, 168, 11, 169, 157,
+ 158, 159, 160, 170, 8, 171, 161, 164, 162, 163,
172, 173, 174, 165, 175, 166, 177, 167, 183, 180,
- 168, 169, 180, 184, 185, 8, 186, 170, 171, 187,
- 188, 3, 189, 172, 173, 174, 191, 193, 175, 177,
+ 168, 169, 180, 184, 185, 3, 186, 170, 171, 187,
+ 188, 0, 189, 172, 173, 174, 191, 193, 175, 177,
195, 196, 183, 198, 197, 199, 201, 184, 185, 186,
204, 205, 187, 197, 188, 189, 207, 206, 211, 191,
@@ -727,24 +725,22 @@ static const flex_int16_t yy_chk[893] =
354, 338, 355, 337, 340, 341, 351, 344, 352, 351,
345, 352, 346, 347, 342, 0, 349, 356, 337, 357,
350, 0, 353, 358, 354, 355, 358, 359, 360, 361,
- 362, 360, 364, 362, 0, 0, 366, 342, 336, 366,
+ 363, 360, 365, 363, 0, 0, 0, 342, 336, 0,
356, 0, 357, 0, 342, 0, 0, 0, 0, 0,
- 359, 0, 361, 0, 0, 364, 0, 348, 0, 0,
+ 359, 0, 361, 0, 0, 365, 0, 348, 0, 0,
0, 0, 0, 0, 0, 0, 0, 351, 0, 352,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 358, 0, 0, 0, 0, 360,
- 0, 362, 0, 0, 0, 0, 0, 366, 370, 370,
- 0, 370, 370, 372, 372, 373, 373, 374, 0, 0,
- 374, 375, 375, 376, 376, 0, 376, 376, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369
-
+ 0, 363, 368, 368, 0, 368, 368, 370, 370, 371,
+ 371, 372, 0, 0, 372, 373, 373, 374, 374, 0,
+ 374, 374, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+ 367, 367, 367, 367, 367, 367
} ;
static yy_state_type yy_last_accepting_state;
@@ -891,10 +887,10 @@ static Common::String *readUntilWhitespace(const char **ptr) {
return res;
}
-static Common::String *readUntilNull(const char **ptr) {
+static Common::String *readUntilNewline(const char **ptr) {
Common::String *res = new Common::String;
- while (**ptr) {
+ while ((**ptr != '\n') && (**ptr != '\r') && (**ptr != '\0')) {
if (**ptr == '\xC2' && *(*ptr + 1) == '\xAC') { // continuation
*ptr += 2;
*res += ' '; // replace with space
@@ -907,8 +903,8 @@ static Common::String *readUntilNull(const char **ptr) {
return res;
}
-#line 910 "engines/director/lingo/lingo-lex.cpp"
-#line 911 "engines/director/lingo/lingo-lex.cpp"
+#line 906 "engines/director/lingo/lingo-lex.cpp"
+#line 907 "engines/director/lingo/lingo-lex.cpp"
#define INITIAL 0
@@ -1129,7 +1125,7 @@ YY_DECL
#line 166 "engines/director/lingo/lingo-lex.l"
-#line 1132 "engines/director/lingo/lingo-lex.cpp"
+#line 1128 "engines/director/lingo/lingo-lex.cpp"
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{
@@ -1157,13 +1153,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 370 )
+ if ( yy_current_state >= 368 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
++yy_cp;
}
- while ( yy_current_state != 369 );
+ while ( yy_current_state != 367 );
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);
@@ -1566,10 +1562,10 @@ YY_RULE_SETUP
Common::String *eventName = readUntilWhitespace(&ptr);
skipWhitespace(&ptr);
- ptr += 5; // Skip 'then '
+ ptr += 4; // Skip 'then'
skipWhitespace(&ptr);
- Common::String *stmt = readUntilNull(&ptr);
+ Common::String *stmt = readUntilNewline(&ptr);
yylval.w.eventName = eventName;
yylval.w.stmt = stmt;
@@ -1682,7 +1678,7 @@ YY_RULE_SETUP
#line 302 "engines/director/lingo/lingo-lex.l"
ECHO;
YY_BREAK
-#line 1685 "engines/director/lingo/lingo-lex.cpp"
+#line 1681 "engines/director/lingo/lingo-lex.cpp"
case YY_STATE_EOF(INITIAL):
yyterminate();
@@ -1981,7 +1977,7 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 370 )
+ if ( yy_current_state >= 368 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
@@ -2009,11 +2005,11 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 370 )
+ if ( yy_current_state >= 368 )
yy_c = yy_meta[yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
- yy_is_jam = (yy_current_state == 369);
+ yy_is_jam = (yy_current_state == 367);
return yy_is_jam ? 0 : yy_current_state;
}
diff --git a/engines/director/lingo/lingo-lex.l b/engines/director/lingo/lingo-lex.l
index 5a64738f5a8..475e277f52f 100644
--- a/engines/director/lingo/lingo-lex.l
+++ b/engines/director/lingo/lingo-lex.l
@@ -135,10 +135,10 @@ static Common::String *readUntilWhitespace(const char **ptr) {
return res;
}
-static Common::String *readUntilNull(const char **ptr) {
+static Common::String *readUntilNewline(const char **ptr) {
Common::String *res = new Common::String;
- while (**ptr) {
+ while ((**ptr != '\n') && (**ptr != '\r') && (**ptr != '\0')) {
if (**ptr == '\xC2' && *(*ptr + 1) == '\xAC') { // continuation
*ptr += 2;
*res += ' '; // replace with space
@@ -254,7 +254,7 @@ the { count(); return tTHE; }
then { count(); return tTHEN; }
time { count(); return tTIME; }
to { count(); return tTO; }
-when{spc}+{eventname}{spc}+then{spc}+{unparsedstmt} {
+when{spc}+{eventname}{spc}+then{spc}*{unparsedstmt} {
count();
const char *ptr = &yytext[5]; // Skip 'when '
@@ -263,10 +263,10 @@ when{spc}+{eventname}{spc}+then{spc}+{unparsedstmt} {
Common::String *eventName = readUntilWhitespace(&ptr);
skipWhitespace(&ptr);
- ptr += 5; // Skip 'then '
+ ptr += 4; // Skip 'then'
skipWhitespace(&ptr);
- Common::String *stmt = readUntilNull(&ptr);
+ Common::String *stmt = readUntilNewline(&ptr);
yylval.w.eventName = eventName;
yylval.w.stmt = stmt;
Commit: 098fddf97a5431ae4d6e1b3d07c3c957fb9012bd
https://github.com/scummvm/scummvm/commit/098fddf97a5431ae4d6e1b3d07c3c957fb9012bd
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Move "the hilite" property to base CastMember
The manual implies that this property is only used by buttons, but it is
a boolean property that you can get and set on any cast member type.
Fixes sound playback in the Barber Joe minigame of Rodney's Funscreen.
Changed paths:
engines/director/castmember/castmember.cpp
engines/director/castmember/richtext.cpp
engines/director/castmember/text.cpp
diff --git a/engines/director/castmember/castmember.cpp b/engines/director/castmember/castmember.cpp
index 84072797671..4dbdd345d19 100644
--- a/engines/director/castmember/castmember.cpp
+++ b/engines/director/castmember/castmember.cpp
@@ -124,6 +124,7 @@ bool CastMember::hasField(int field) {
case kTheFileName:
case kTheForeColor:
case kTheHeight:
+ case kTheHilite:
case kTheLoaded:
case kTheModified:
case kTheMemberNum:
@@ -175,6 +176,9 @@ Datum CastMember::getField(int field) {
case kTheHeight:
d = _cast->getCastMemberInitialRect(_castId).height();
break;
+ case kTheHilite:
+ d = (int)_hilite;
+ break;
case kTheLoaded:
d = 1; // Not loaded handled in Lingo::getTheCast
break;
@@ -245,6 +249,10 @@ bool CastMember::setField(int field, const Datum &d) {
case kTheHeight:
warning("BUILDBOT: CastMember::setField(): Attempt to set read-only field \"%s\" of cast %d", g_lingo->field2str(field), _castId);
return false;
+ case kTheHilite:
+ _hilite = (bool)d.asInt();
+ _modified = true;
+ return true;
case kTheName:
if (!castInfo) {
warning("CastMember::setField(): CastMember info for %d not found", _castId);
diff --git a/engines/director/castmember/richtext.cpp b/engines/director/castmember/richtext.cpp
index d74c9a10fdb..de3d21fce1a 100644
--- a/engines/director/castmember/richtext.cpp
+++ b/engines/director/castmember/richtext.cpp
@@ -165,7 +165,6 @@ Graphics::MacWidget *RichTextCastMember::createWidget(Common::Rect &bbox, Channe
bool RichTextCastMember::hasField(int field) {
switch (field) {
- case kTheHilite:
case kTheText:
case kThePageHeight:
case kTheScrollTop:
@@ -183,7 +182,6 @@ Datum RichTextCastMember::getField(int field) {
case kTheText:
d = Datum(Common::String(_plainText));
break;
- case kTheHilite:
case kThePageHeight:
case kTheScrollTop:
default:
@@ -200,7 +198,6 @@ bool RichTextCastMember::setField(int field, const Datum &d) {
_plainText = Common::U32String(d.asString());
warning("STUB: RichTextCastMember::setField: text set to \"%s\", but won't rerender!", d.asString().c_str());
break;
- case kTheHilite:
case kThePageHeight:
case kTheScrollTop:
default:
diff --git a/engines/director/castmember/text.cpp b/engines/director/castmember/text.cpp
index 599e1428bc0..93bfb094cc1 100644
--- a/engines/director/castmember/text.cpp
+++ b/engines/director/castmember/text.cpp
@@ -633,7 +633,6 @@ void TextCastMember::unload() {
bool TextCastMember::hasField(int field) {
switch (field) {
- case kTheHilite:
case kTheText:
case kTheTextAlign:
case kTheTextFont:
@@ -664,9 +663,6 @@ Datum TextCastMember::getField(int field) {
Datum d;
switch (field) {
- case kTheHilite:
- d = _hilite;
- break;
case kTheText:
d = getText().encode(Common::kUtf8);
break;
@@ -769,12 +765,6 @@ bool TextCastMember::setField(int field, const Datum &d) {
setColors(&color, nullptr);
}
return true;
- case kTheHilite:
- // TODO: Understand how texts can be selected programmatically as well.
- // since hilite won't affect text castmember, and we may have button info in text cast in D2/3. so don't check type here
- _hilite = (bool)d.asInt();
- _modified = true;
- return true;
case kTheText:
setRawText(d.asString());
return true;
Commit: c69af23102d7304468da7ed20a897b8ccfc4e977
https://github.com/scummvm/scummvm/commit/c69af23102d7304468da7ed20a897b8ccfc4e977
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Fix Mac resource mouse cursor offset
Fixes mouse cursor relative position in the Barber Joe minigame of
Rodney's Funscreen.
Changed paths:
engines/director/cursor.cpp
diff --git a/engines/director/cursor.cpp b/engines/director/cursor.cpp
index f1ddc55b28f..0d039c001ca 100644
--- a/engines/director/cursor.cpp
+++ b/engines/director/cursor.cpp
@@ -251,9 +251,9 @@ bool Cursor::readFromArchive(Archive *archive, uint16 resourceId) {
if (cursorStream && readFromStream(*((Common::SeekableReadStream *)cursorStream), false, 0)) {
_usePalette = true;
_keyColor = 0xff;
+ _cursorType = Graphics::kMacCursorCustom;
+ _cursorResId = resourceId;
readSuccessful = true;
-
- resetCursor(Graphics::kMacCursorCustom, false, resourceId);
}
delete cursorStream;
return readSuccessful;
Commit: a71c8b3cd4e6678e8a3891faf7f3d8f57535b199
https://github.com/scummvm/scummvm/commit/a71c8b3cd4e6678e8a3891faf7f3d8f57535b199
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Fix Cursor::readFromCast if no mask is provided
Changed paths:
engines/director/cursor.cpp
diff --git a/engines/director/cursor.cpp b/engines/director/cursor.cpp
index 0d039c001ca..d6bf2e8d088 100644
--- a/engines/director/cursor.cpp
+++ b/engines/director/cursor.cpp
@@ -59,27 +59,34 @@ bool Cursor::operator==(const CursorRef &c) {
}
void Cursor::readFromCast(Datum cursorCasts) {
- if (cursorCasts.type != ARRAY || cursorCasts.u.farr->arr.size() != 2 ) {
- warning("Cursor::readFromCast: Needs array of 2");
+ if (cursorCasts.type != ARRAY || cursorCasts.u.farr->arr.size() < 1) {
+ warning("Cursor::readFromCast: Needs array of at least 1");
return;
}
if (_cursorResId.type == ARRAY && LC::eqData(_cursorResId, cursorCasts).asInt())
return;
- CastMemberID cursorId = cursorCasts.u.farr->arr[0].asMemberID();
- CastMemberID maskId = cursorCasts.u.farr->arr[1].asMemberID();
+ CastMemberID cursorId = cursorCasts.u.farr->arr[0].asMemberID();
CastMember *cursorCast = g_director->getCurrentMovie()->getCastMember(cursorId);
- CastMember *maskCast = g_director->getCurrentMovie()->getCastMember(maskId);
-
if (!cursorCast || cursorCast->_type != kCastBitmap) {
warning("Cursor::readFromCast: No bitmap cast for cursor");
return;
- } else if (!maskCast || maskCast->_type != kCastBitmap) {
- warning("Cursor::readFromCast: No bitmap mask for cursor");
- return;
}
+ CastMember *maskCast = nullptr;
+ CastMemberID maskId;
+ if (cursorCasts.u.farr->arr.size() > 1) {
+ maskId = cursorCasts.u.farr->arr[1].asMemberID();
+ maskCast = g_director->getCurrentMovie()->getCastMember(maskId);
+ if (!maskCast || maskCast->_type != kCastBitmap) {
+ warning("Cursor::readFromCast: Invalid bitmap mask for cursor, ignoring");
+ maskCast = nullptr;
+ }
+ }
+
+ debugC(2, kDebugImages, "Cursor::readFromCast: setting cursor: %s, mask: %s", cursorId.asString().c_str(), maskId.asString().c_str());
+
_usePalette = false;
_keyColor = 3;
@@ -91,8 +98,11 @@ void Cursor::readFromCast(Datum cursorCasts) {
}
resetCursor(Graphics::kMacCursorCustom, true, cursorRes);
- BitmapCastMember *cursorBitmap = (BitmapCastMember *)cursorCast;
- BitmapCastMember *maskBitmap = (BitmapCastMember *)maskCast;
+ Graphics::Surface *cursorSurface = &((BitmapCastMember *)cursorCast)->_picture->_surface;
+ Graphics::Surface *maskSurface = nullptr;
+ if (maskCast) {
+ maskSurface = &((BitmapCastMember *)maskCast)->_picture->_surface;
+ }
_surface = new byte[getWidth() * getHeight()];
byte *dst = _surface;
@@ -100,24 +110,26 @@ void Cursor::readFromCast(Datum cursorCasts) {
for (int y = 0; y < 16; y++) {
const byte *cursor = nullptr, *mask = nullptr;
- if (y < cursorBitmap->_picture->_surface.h &&
- y < maskBitmap->_picture->_surface.h) {
- cursor = (const byte *)cursorBitmap->_picture->_surface.getBasePtr(0, y);
- mask = (const byte *)maskBitmap->_picture->_surface.getBasePtr(0, y);
+ if (y < cursorSurface->h &&
+ (!maskSurface || y < maskSurface->h)) {
+ cursor = (const byte *)cursorSurface->getBasePtr(0, y);
+ if (maskSurface)
+ mask = (const byte *)maskSurface->getBasePtr(0, y);
}
for (int x = 0; x < 16; x++) {
- if (x >= cursorBitmap->_picture->_surface.w ||
- x >= maskBitmap->_picture->_surface.w) {
+ if (x >= cursorSurface->w ||
+ (!maskSurface || x >= maskSurface->w)) {
cursor = mask = nullptr;
}
if (!cursor) {
*dst = 3;
} else {
- *dst = *mask ? (*cursor ? 0 : 1) : 3;
+ *dst = (!mask || *mask) ? (*cursor ? 0 : 1) : 3;
cursor++;
- mask++;
+ if (mask)
+ mask++;
}
dst++;
}
Commit: c9ca3d5706a4f01b087d3a6cd3d01db1db85c1ba
https://github.com/scummvm/scummvm/commit/c9ca3d5706a4f01b087d3a6cd3d01db1db85c1ba
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Add Gus Goes to the Kooky Carnival to detection table
Changed paths:
engines/director/detection_tables.h
diff --git a/engines/director/detection_tables.h b/engines/director/detection_tables.h
index fda3b726dc5..3446187025f 100644
--- a/engines/director/detection_tables.h
+++ b/engines/director/detection_tables.h
@@ -4400,6 +4400,8 @@ static const DirectorGameDescription gameDescriptions[] = {
MACGAME1("gusbuds", "", "MMV Product Demos for PowerMac", "r:692f6732b6d7deaa00c9b3df57bb30ce", 60068, 404),
WINGAME1("gusbuds", "", "MMVDEMOS.EXE", "d:71d4ad9e9dc92a81561476d4d9813492", 692037, 404),
+ MACGAME1("guscarn", "", "Gus Goes to the Kooky Carnival", "r:e6833f1ce3b022f0128e4c80a55bcd46", 285310, 404),
+ WINGAME1("guscarn", "", "CARNIVAL.EXE", "t:d0babe1503cdec2b3c45674f91911c13", 690553, 404),
WINGAME1_l("guscarn", "", "PRETPARK.EXE", "t:d0babe1503cdec2b3c45674f91911c13", 690553, Common::NL_NLD, 404),
MACDEMO1("guscarn", "Demo", "Carnival Demo 4 you", "r:67f572196550aedb1f9523d782022be0", 481226, 404),
Commit: b1ccc9bec9c8e9e581ee835d524948aa10de512d
https://github.com/scummvm/scummvm/commit/b1ccc9bec9c8e9e581ee835d524948aa10de512d
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Add guardrail for empty RTE1 block
Changed paths:
engines/director/castmember/richtext.cpp
diff --git a/engines/director/castmember/richtext.cpp b/engines/director/castmember/richtext.cpp
index de3d21fce1a..277e536c6b0 100644
--- a/engines/director/castmember/richtext.cpp
+++ b/engines/director/castmember/richtext.cpp
@@ -99,7 +99,8 @@ void RichTextCastMember::load() {
}
if (_cast->_loadedRTE1s.contains(rte1id)) {
const RTE1 *rte1 = _cast->_loadedRTE1s.getVal(rte1id);
- _plainText = Common::U32String((const char *)&rte1->data[0], rte1->data.size(), g_director->getPlatformEncoding());
+ if (!rte1->data.empty())
+ _plainText = Common::U32String((const char *)&rte1->data[0], rte1->data.size(), g_director->getPlatformEncoding());
} else {
warning("RichTextCastMember::load(): rte1tid %i isn't loaded, no plain text!", rte1id);
}
Commit: f1451082ee940b782940b841bafc54cc94ca836f
https://github.com/scummvm/scummvm/commit/f1451082ee940b782940b841bafc54cc94ca836f
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Add guardrail for copying from a zero-sized bitmap
Fixes crash in the shooting minigame in Gus Goes to the Kooky Carnival.
Changed paths:
engines/director/castmember/bitmap.cpp
engines/director/images.cpp
diff --git a/engines/director/castmember/bitmap.cpp b/engines/director/castmember/bitmap.cpp
index 485e63f1e42..2b625c9f0fb 100644
--- a/engines/director/castmember/bitmap.cpp
+++ b/engines/director/castmember/bitmap.cpp
@@ -304,14 +304,21 @@ Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox, Channel
Graphics::MacWidget *widget = new Graphics::MacWidget(g_director->getCurrentWindow(), bbox.left, bbox.top, bbox.width(), bbox.height(), g_director->_wm, false);
- // scale for drawing a different size sprite
- copyStretchImg(
- _ditheredImg ? _ditheredImg : &_picture->_surface,
- widget->getSurface()->surfacePtr(),
- _initialRect,
- bbox,
- pal
- );
+ Graphics::Surface *srcSurface = _ditheredImg ? _ditheredImg : &_picture->_surface;
+ if ((srcSurface->w <= 0) || (srcSurface->h <= 0)) {
+ // We're copying from a zero-sized surface; fill widget with white so transparent ink works
+ Common::Rect dims = widget->getDimensions();
+ widget->getSurface()->fillRect(Common::Rect(dims.width(), dims.height()), g_director->_wm->_colorWhite);
+ } else {
+ // scale for drawing a different size sprite
+ copyStretchImg(
+ srcSurface,
+ widget->getSurface()->surfacePtr(),
+ _initialRect,
+ bbox,
+ pal
+ );
+ }
return widget;
}
@@ -666,8 +673,10 @@ void BitmapCastMember::load() {
} else {
img = new Image::BitmapDecoder();
}
+ } else if (pic->size() == 0) {
+ // zero-length bitmap
} else {
- warning("BitmapCastMember::load(): Bitmap image %d not found", imgId);
+ warning("BitmapCastMember::load(): Bitmap image %d has invalid size", imgId);
}
break;
diff --git a/engines/director/images.cpp b/engines/director/images.cpp
index c3b0b5a3964..11b196eb49a 100644
--- a/engines/director/images.cpp
+++ b/engines/director/images.cpp
@@ -326,6 +326,10 @@ bool BITDDecoder::loadStream(Common::SeekableReadStream &stream) {
void copyStretchImg(const Graphics::Surface *srcSurface, Graphics::Surface *targetSurface, const Common::Rect &srcRect, const Common::Rect &targetRect, const byte *pal) {
if (!(srcSurface) || !(targetSurface))
return;
+ if ((srcSurface->h <= 0) || (srcSurface->w <= 0)) {
+ // Source area is nonexistant
+ return;
+ }
Graphics::Surface *temp1 = nullptr;
Graphics::Surface *temp2 = nullptr;
Commit: 77365baab4c26b154cf8f009b7f5ff57bdf3770a
https://github.com/scummvm/scummvm/commit/77365baab4c26b154cf8f009b7f5ff57bdf3770a
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Set default palette as soon as the first movie loads
Prevents a ~1 frame gap with the incorrect palette.
Changed paths:
engines/director/window.cpp
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index fbb11616699..04a86e59025 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -578,6 +578,9 @@ bool Window::step() {
debug(0, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
bool goodMovie = _currentMovie->loadArchive();
+ // If we've just started, switch to the default palette
+ if (g_director->_firstMovie)
+ g_director->setPalette(_currentMovie->getCast()->_defaultPalette);
// If we came in a loop, then skip as requested
if (!_nextMovie.frameS.empty()) {
Commit: 61b0ab070b46a44fd5ec9ba20ad546a629af406c
https://github.com/scummvm/scummvm/commit/61b0ab070b46a44fd5ec9ba20ad546a629af406c
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: RichTextCastMember fixes
The RLE format does support specifying what the foreground colour is,
but by default it uses the one in the RichTextCastMember metadata. So
you need to hold off on generating the bitmap until you know what that
is. We now use the PixelFormat to give us the correct colour
values instead of doing bad maths.
Changed paths:
engines/director/castmember/richtext.cpp
engines/director/castmember/richtext.h
engines/director/detection_tables.h
engines/director/rte.cpp
engines/director/rte.h
diff --git a/engines/director/castmember/richtext.cpp b/engines/director/castmember/richtext.cpp
index 277e536c6b0..9673c8823cc 100644
--- a/engines/director/castmember/richtext.cpp
+++ b/engines/director/castmember/richtext.cpp
@@ -37,18 +37,28 @@ namespace Director {
RichTextCastMember::RichTextCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version)
: CastMember(cast, castId, stream) {
+ _pf32 = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
+
if (version >= kFileVer500 && version < kFileVer600) {
- _initialRect = Movie::readRect(stream);
- _boundingRect = Movie::readRect(stream);
if (debugChannelSet(5, kDebugLoading)) {
- debugC(5, kDebugLoading, "RichTextCastMember(): unk");
- stream.hexdump(8);
+ debugC(5, kDebugLoading, "RichTextCastMember():");
+ stream.hexdump(stream.size());
}
+
+ _initialRect = Movie::readRect(stream);
+ _boundingRect = Movie::readRect(stream);
stream.seek(8, SEEK_CUR);
- _foreColor = stream.readUint32BE();
- _bgColor = (stream.readUint16BE() >> 8) << 16;
- _bgColor |= (stream.readUint16BE() >> 8) << 8;
- _bgColor |= (stream.readUint16BE() >> 8);
+ uint8 r = 0, g = 0, b = 0;
+ stream.readByte();
+ r = stream.readByte();
+ g = stream.readByte();
+ b = stream.readByte();
+ _foreColor = _pf32.RGBToColor(r, g, b);
+
+ r = (stream.readUint16BE() >> 8);
+ g = (stream.readUint16BE() >> 8);
+ b = (stream.readUint16BE() >> 8);
+ _bgColor = _pf32.RGBToColor(r, g, b);
} else {
warning("RichTextCastMember(): >D5 isn't handled");
}
@@ -105,17 +115,14 @@ void RichTextCastMember::load() {
warning("RichTextCastMember::load(): rte1tid %i isn't loaded, no plain text!", rte1id);
}
if (_cast->_loadedRTE2s.contains(rte2id)) {
- const RTE2 *rte2 = _cast->_loadedRTE2s.getVal(rte2id);
- // Create a 24-bit temporary surface, no alpha.
- Graphics::ManagedSurface temp;
- temp.create((int16)rte2->width, (int16)rte2->height, Graphics::PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0));
- // Fill it with the background colour
- temp.fillRect(Common::Rect((int16)rte2->width, (int16)rte2->height), _bgColor);
- // Blit the alpha text map
- temp.blitFrom(*rte2->_surface, nullptr);
_picture = new Picture();
- _picture->_surface.copyFrom(temp);
- temp.free();
+ const RTE2 *rte2 = _cast->_loadedRTE2s.getVal(rte2id);
+ Graphics::ManagedSurface *surface = rte2->createSurface(_foreColor, _bgColor, _pf32);
+ if (surface) {
+ _picture->_surface.copyFrom(surface->rawSurface());
+ surface->free();
+ delete surface;
+ }
} else {
warning("RichTextCastMember::load(): rte2tid %i isn't loaded, no bitmap text!", rte2id);
}
diff --git a/engines/director/castmember/richtext.h b/engines/director/castmember/richtext.h
index 0728bdab70e..fdfa12a5f06 100644
--- a/engines/director/castmember/richtext.h
+++ b/engines/director/castmember/richtext.h
@@ -22,6 +22,8 @@
#ifndef DIRECTOR_CASTMEMBER_RICHTEXT_H
#define DIRECTOR_CASTMEMBER_RICHTEXT_H
+#include "graphics/pixelformat.h"
+
#include "director/types.h"
#include "director/castmember/castmember.h"
@@ -47,6 +49,7 @@ public:
private:
Common::U32String _plainText;
+ Graphics::PixelFormat _pf32;
uint32 _foreColor;
uint32 _bgColor;
Picture *_picture;
diff --git a/engines/director/detection_tables.h b/engines/director/detection_tables.h
index 3446187025f..0f792ccbf8c 100644
--- a/engines/director/detection_tables.h
+++ b/engines/director/detection_tables.h
@@ -6564,8 +6564,8 @@ static const DirectorGameDescription gameDescriptions[] = {
WINGAME1("compconf", "Windows 3.1", "CCWIN311.EXE", "t:d2f5116b14bb8aaeaeae3d3d7e55d40b", 918905, 500),
WINGAME1("compconf", "Windows 95", "CCWIN95.EXE", "t:4cb9a6383932f6f11946a5692d82bcf0", 1395275, 500),
- WINGAME2t("cracking", "", "crack.exe", "c2093c2b5dc9d3dc5b491e4df027e202", 1842361,
- "ufog8.dxr", "7c8222a010d40b59dd96a97f0b4fa974", 542472, 500),
+ WINGAME2tf("cracking", "", "crack.exe", "c2093c2b5dc9d3dc5b491e4df027e202", 1842361,
+ "ufog8.dxr", "7c8222a010d40b59dd96a97f0b4fa974", 542472, 500, GF_32BPP),
// Mac versions require installation
// Original Mac german filename is Kreuzzüge
diff --git a/engines/director/rte.cpp b/engines/director/rte.cpp
index a13697f8870..824b89bac88 100644
--- a/engines/director/rte.cpp
+++ b/engines/director/rte.cpp
@@ -21,7 +21,7 @@
#include "common/debug.h"
#include "common/stream.h"
-#include "common/substream.h"
+#include "common/memstream.h"
#include "director/director.h"
#include "director/cast.h"
@@ -55,24 +55,33 @@ RTE2::RTE2(Cast *cast, Common::SeekableReadStreamEndian &stream) : _cast(cast) {
debugC(5, kDebugLoading, "RTE2:");
stream.hexdump(stream.size());
}
- _surface = nullptr;
+ _width = 0;
+ _height = 0;
+ _bpp = 0;
if (!stream.size())
return;
- width = stream.readUint16BE();
- height = stream.readUint16BE();
- bpp = stream.readUint16BE();
- int checkMax = (1 << bpp) - 1;
- debugC(5, kDebugLoading, "RTE2: width: %d, height: %d, bpp: %d", width, height, bpp);
+ _width = stream.readUint16BE();
+ _height = stream.readUint16BE();
+ _bpp = stream.readUint16BE();
+ int rleCount = stream.size() - stream.pos();
+ _rle.resize(rleCount, 0x00);
+ stream.read(_rle.data(), rleCount);
+ debugC(5, kDebugLoading, "RTE2: _width: %d, _height: %d, _bpp: %d, _rle: %d bytes", _width, _height, _bpp, rleCount);
+}
+
+Graphics::ManagedSurface *RTE2::createSurface(uint32 foreColor, uint32 bgColor, const Graphics::PixelFormat &pf) const {
+ if (_rle.empty())
+ return nullptr;
+ Common::MemoryReadStream stream(_rle.data(), _rle.size());
// Create a 32-bit alpha surface for the decoded image
- _surface = new Graphics::Surface();
- _surface->create((int16)width, (int16)height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
- uint8 r = 0;
- uint8 g = 0;
- uint8 b = 0;
- uint8 a = 0;
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width;) {
+ Graphics::Surface surface;
+ surface.create((int16)_width, (int16)_height, pf);
+ int checkMax = (1 << _bpp) - 1;
+ uint8 r = 0, g = 0, b = 0, a = 0;
+ pf.colorToRGB(foreColor, r, g, b);
+ for (int y = 0; y < _height; y++) {
+ for (int x = 0; x < _width;) {
uint32 pos = stream.pos();
byte check = stream.readByte();
if (check == 0x1f) {
@@ -82,39 +91,44 @@ RTE2::RTE2(Cast *cast, Common::SeekableReadStreamEndian &stream) : _cast(cast) {
debugC(9, kDebugLoading, "[%04x] (%d, %d): color %d %d %d", pos, x, y, r, g, b);
continue;
}
- a = ((uint32)check*0xff/((1 << bpp) - 1));
+ a = ((uint32)check*0xff/((1 << _bpp) - 1));
if (check == 0 || check == checkMax) {
byte count = stream.readByte();
debugC(9, kDebugLoading, "[%04x] (%d, %d): %02x, count %d", pos, x, y, check, count);
if (count == 0x00 && check == 0x00) {
// end of line, fill the remaining colour
a = 0;
- while (x < width) {
- *(uint32 *)_surface->getBasePtr(x, y) = ((uint32)r << 24) + ((uint32)g << 16) + ((uint32)b << 8) + a;
+ while (x < _width) {
+ *(uint32 *)surface.getBasePtr(x, y) = pf.ARGBToColor(a, r, g, b);
x += 1;
}
break;
}
for (byte j = 0; j < count; j++) {
- *(uint32 *)_surface->getBasePtr(x, y) = ((uint32)r << 24) + ((uint32)g << 16) + ((uint32)b << 8) + a;
+ *(uint32 *)surface.getBasePtr(x, y) = pf.ARGBToColor(a, r, g, b);
x += 1;
- if (x >= width)
+ if (x >= _width)
break;
}
} else {
debugC(9, kDebugLoading, "[%04x] (%d, %d): %02x", pos, x, y, check);
- *(uint32 *)_surface->getBasePtr(x, y) = ((uint32)r << 24) + ((uint32)g << 16) + ((uint32)b << 8) + a;
+ *(uint32 *)surface.getBasePtr(x, y) = pf.ARGBToColor(a, r, g, b);
x += 1;
}
}
}
+ Graphics::ManagedSurface *result = new Graphics::ManagedSurface();
+ result->create((int16)_width, (int16)_height, pf);
+ // Fill it with the background colour
+ result->fillRect(Common::Rect(_width, _height), bgColor);
+ // Blit the alpha text map
+ result->blitFrom(surface, nullptr);
+
+ surface.free();
+ return result;
}
RTE2::~RTE2() {
- if (_surface) {
- _surface->free();
- delete _surface;
- }
}
} // End of namespace Director
diff --git a/engines/director/rte.h b/engines/director/rte.h
index 7d67fc7767d..0c193b6f114 100644
--- a/engines/director/rte.h
+++ b/engines/director/rte.h
@@ -24,12 +24,15 @@
#include "common/array.h"
#include "common/stream.h"
-#include "graphics/surface.h"
namespace Common {
class SeekableReadStreamEndian;
}
+namespace Graphics {
+class ManagedSurface;
+}
+
namespace Director {
class Cast;
@@ -55,11 +58,13 @@ public:
RTE2(Cast *cast, Common::SeekableReadStreamEndian &stream);
~RTE2();
+ Graphics::ManagedSurface *createSurface(uint32 foreColor, uint32 bgColor, const Graphics::PixelFormat &pf) const;
+
Cast *_cast;
- uint16 width;
- uint16 height;
- uint32 bpp;
- Graphics::Surface *_surface;
+ uint16 _width;
+ uint16 _height;
+ uint32 _bpp;
+ Common::Array<byte> _rle;
};
} // End of namespace Director
Commit: 4364392b93d99b2db09c1dfa9f2efde0c4a44e81
https://github.com/scummvm/scummvm/commit/4364392b93d99b2db09c1dfa9f2efde0c4a44e81
Author: Scott Percival (code at moral.net.au)
Date: 2025-05-09T06:18:28+08:00
Commit Message:
DIRECTOR: Wire up D5 rightMouseDown and rightMouseUp handlers
Changed paths:
engines/director/events.cpp
engines/director/lingo/lingo-events.cpp
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index f485e8ff539..6fa300b6cb7 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/events.h"
#include "common/system.h"
#include "common/translation.h"
@@ -197,6 +198,7 @@ bool Movie::processEvent(Common::Event &event) {
} else {
pos = event.mouse;
+ // FIXME: Check if these are tracked with the right mouse button
_lastEventTime = g_director->getMacTicks();
_lastClickTime2 = _lastClickTime;
_lastClickTime = _lastEventTime;
@@ -204,20 +206,34 @@ bool Movie::processEvent(Common::Event &event) {
if (_timeOutMouse)
_lastTimeOut = _lastEventTime;
+ LEvent ev = kEventMouseDown;
+ // In D5 and up, right mouse clicks don't trigger the mouseDown handler.
+ // They are caught by the rightMouseDown handler only.
+ if ((g_director->getVersion() >= 500) && event.type == Common::EVENT_RBUTTONDOWN)
+ ev = kEventRightMouseDown;
+
debugC(3, kDebugEvents, "Movie::processEvent(): Button Down @(%d, %d), movie '%s'", pos.x, pos.y, _macName.c_str());
- queueInputEvent(kEventMouseDown, 0, pos);
+ queueInputEvent(ev, 0, pos);
}
return true;
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
- pos = event.mouse;
+ {
+ pos = event.mouse;
- debugC(3, kDebugEvents, "Movie::processEvent(): Button Up @(%d, %d), movie '%s'", pos.x, pos.y, _macName.c_str());
+ debugC(3, kDebugEvents, "Movie::processEvent(): Button Up @(%d, %d), movie '%s'", pos.x, pos.y, _macName.c_str());
- queueInputEvent(kEventMouseUp, 0, pos);
- sc->renderCursor(pos);
+ LEvent ev = kEventMouseUp;
+ // In D5 and up, right mouse clicks don't trigger the mouseUp handler.
+ // They are caught by the rightMouseUp handler only.
+ if ((g_director->getVersion() >= 500) && event.type == Common::EVENT_RBUTTONUP)
+ ev = kEventRightMouseUp;
+
+ queueInputEvent(ev, 0, pos);
+ sc->renderCursor(pos);
+ }
return true;
case Common::EVENT_KEYDOWN:
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 29a4691410c..afc6445c9ed 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -136,7 +136,7 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
// mouseDown/mouseUp events will have one of each of the source types queued.
// run these steps at the very beginning (i.e. before the first source type).
if (event.eventHandlerSourceType == kPrimaryHandler) {
- if (event.event == kEventMouseDown) {
+ if ((event.event == kEventMouseDown) || (event.event == kEventRightMouseDown)) {
if (!spriteId && _isBeepOn) {
g_lingo->func_beep(1);
}
@@ -171,7 +171,7 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
_currentMouseDownCastID = CastMemberID();
}
- } else if (event.event == kEventMouseUp) {
+ } else if ((event.event == kEventMouseUp) || (event.event == kEventRightMouseUp)) {
if (_currentHiliteChannelId && _score->_channels[_currentHiliteChannelId]) {
g_director->getCurrentWindow()->setDirty(true);
g_director->getCurrentWindow()->addDirtyRect(_score->_channels[_currentHiliteChannelId]->getBbox());
@@ -266,7 +266,7 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
// A bit unhinged, but we have a test that proves Director does this,
// so we have to do it too.
CastMemberID targetCast = _currentMouseDownCastID;
- if (event.event == kEventMouseDown) {
+ if ((event.event == kEventMouseDown) || (event.event == kEventRightMouseDown)) {
if (!spriteId)
return;
Sprite *sprite = _score->getSpriteById(spriteId);
@@ -375,6 +375,8 @@ void Movie::queueEvent(Common::Queue<LingoEvent> &queue, LEvent event, int targe
switch (event) {
case kEventMouseDown:
case kEventMouseUp:
+ case kEventRightMouseDown:
+ case kEventRightMouseUp:
case kEventKeyUp:
case kEventKeyDown:
case kEventTimeout:
@@ -440,6 +442,8 @@ void Movie::queueEvent(Common::Queue<LingoEvent> &queue, LEvent event, int targe
case kEventKeyDown:
case kEventMouseUp:
case kEventMouseDown:
+ case kEventRightMouseUp:
+ case kEventRightMouseDown:
case kEventBeginSprite:
queue.push(LingoEvent(event, eventId, kSpriteHandler, false, pos));
queue.push(LingoEvent(event, eventId, kCastHandler, false, pos));
More information about the Scummvm-git-logs
mailing list