[Scummvm-git-logs] scummvm master -> fabaae75a7e180ad4a7ae35c2a272a8d8d8e835d
sev-
noreply at scummvm.org
Sun Jun 15 23:21:26 UTC 2025
This automated email contains information about 8 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
68114f4a9b DIRECTOR: XTRA: Add link for RTK information
25f3ef148f DIRECTOR: Add detection entry for finkletimes
e4172eba8d DIRECTOR: Add TextCastMember stub for the dropShadow
09458275a4 DIRECTOR: LINGO: Fix b_float to pass-through unknown data
a57bd42323 DIRECTOR: Add file quirks for finkletimes
7f45835576 DIRECTOR: LINGO: Adjust check for repeated events
4686b64473 DIRECTOR: XTRA: Add basic functionality to RolloverToolkit
fabaae75a7 DIRECTOR: LINGO: Provide argument to startRollover/endRollover
Commit: 68114f4a9b34cc51027ca13b7d7847d488c89940
https://github.com/scummvm/scummvm/commit/68114f4a9b34cc51027ca13b7d7847d488c89940
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-16T01:21:19+02:00
Commit Message:
DIRECTOR: XTRA: Add link for RTK information
Changed paths:
engines/director/lingo/xtras/rtk.cpp
diff --git a/engines/director/lingo/xtras/rtk.cpp b/engines/director/lingo/xtras/rtk.cpp
index f200c05c151..5131d67e776 100644
--- a/engines/director/lingo/xtras/rtk.cpp
+++ b/engines/director/lingo/xtras/rtk.cpp
@@ -34,6 +34,9 @@
*
**************************************************/
+// Usage instructions
+// http://web.archive.org/web/19991008052339/http://www.penworks.com/xtras/rtk/about.cgi
+
/*
-- xtra Rollover_Toolkit
-- Rollover Toolkit (tm)
Commit: 25f3ef148fb91ce2341c0540cd17633c1ae5d632
https://github.com/scummvm/scummvm/commit/25f3ef148fb91ce2341c0540cd17633c1ae5d632
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-16T01:21:19+02:00
Commit Message:
DIRECTOR: Add detection entry for finkletimes
Changed paths:
engines/director/detection_tables.h
engines/director/game-quirks.cpp
diff --git a/engines/director/detection_tables.h b/engines/director/detection_tables.h
index b1b13b7cb07..70a2a984ed8 100644
--- a/engines/director/detection_tables.h
+++ b/engines/director/detection_tables.h
@@ -168,6 +168,7 @@ static const PlainGameDescriptor directorGames[] = {
{ "fctplayer", "Felix Cartoon Player" },
{ "fff", "Four Footed Friends" },
{ "finegardening", "Fine Gardening Propagation" },
+ { "finkletimes", "Professor Finkle's Times Table Factory" },
{ "fishwish", "The Fish Who Could Wish" },
{ "flipper", "Flipper" },
{ "flipper1", "The Three Worlds of Flipper & Lopaka" },
@@ -6762,6 +6763,9 @@ static const DirectorGameDescription gameDescriptions[] = {
WINGAME2("explorespace5", "", "WIN95.EXE", "1a7acbba10a7246ba58c1d53fc7203f5", 1411387,
"PROGRAM/459MAIN.DXR", "3868e98be38c2fbff814e2b8f1663fc9", 376868, 501),
+ WINGAME1f("finkletimes", "", "TIMES_CD.EXE", "t:b425f8243195b71c03538cdc83319389", 1421421, 501, GF_32BPP),
+ MACGAME1f("finkletimes", "", "Times Table Factory", "r:3b8e9b13f6e0b81a4b03549930059af4", 705445, 501, GF_32BPP),
+
// Original filename is "ãã¡ã¼ã¹ã ï¼°ï¼£"
MACGAME1t_l("firstpc", "", "xn-- -ceu6cuc2c5my703k7ca", "ea9e1c1489dee20fe0a949facbf62c0e", 719664, Common::JA_JPN, 501),
WINGAME1t_l("firstpc", "", "FIRSTPC.EXE", "969770de110b5dcea469d4153780578b", 1411736, Common::JA_JPN, 501),
diff --git a/engines/director/game-quirks.cpp b/engines/director/game-quirks.cpp
index 1c7fe00d1e3..e6fed8c6690 100644
--- a/engines/director/game-quirks.cpp
+++ b/engines/director/game-quirks.cpp
@@ -125,7 +125,7 @@ static void quirkLimit15FPS() {
g_director->_fpsLimit = 15;
}
-static void quirkVirtualNightclub() {
+static void quirkPretend16Bit() {
g_director->_colorDepth = 16;
}
@@ -236,9 +236,11 @@ const struct Quirk {
// Pippin game that uses Unix path separators rather than Mac
{ "pipcatalog", Common::kPlatformPippin, &quirkPipCatalog },
- // Virtual Nightclub pops up a nag mesasage if the color depth isn't
- // exactly 16 bit.
- { "vnc", Common::kPlatformWindows, &quirkVirtualNightclub },
+ // Some games pop up a nag mesasage if the color depth isn't exactly 16 bit.
+ { "vnc", Common::kPlatformWindows, &quirkPretend16Bit },
+ { "vnc", Common::kPlatformMacintosh, &quirkPretend16Bit },
+ { "finkletimes", Common::kPlatformWindows, &quirkPretend16Bit },
+ { "finkletimes", Common::kPlatformMacintosh, &quirkPretend16Bit },
{ nullptr, Common::kPlatformUnknown, nullptr }
};
Commit: e4172eba8dcda1e2accdf5517e241c45c0e303c1
https://github.com/scummvm/scummvm/commit/e4172eba8dcda1e2accdf5517e241c45c0e303c1
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-16T01:21:19+02:00
Commit Message:
DIRECTOR: Add TextCastMember stub for the dropShadow
Changed paths:
engines/director/castmember/text.cpp
diff --git a/engines/director/castmember/text.cpp b/engines/director/castmember/text.cpp
index 93bfb094cc1..4466f3f3a2d 100644
--- a/engines/director/castmember/text.cpp
+++ b/engines/director/castmember/text.cpp
@@ -644,6 +644,7 @@ bool TextCastMember::hasField(int field) {
case kTheBorder:
case kTheBoxDropShadow:
case kTheBoxType:
+ case kTheDropShadow:
case kTheEditable:
case kTheLineCount:
case kTheMargin:
@@ -706,6 +707,10 @@ Datum TextCastMember::getField(int field) {
warning("STUB: TextCastMember::getField(): boxDropShadow not implemented");
d = 1;
break;
+ case kTheDropShadow:
+ warning("STUB: TextCastMember::getField(): dropShadow not implemented");
+ d = 1;
+ break;
case kTheEditable:
d = (int)_editable;
break;
@@ -813,6 +818,9 @@ bool TextCastMember::setField(int field, const Datum &d) {
case kTheBoxType:
warning("STUB: TextCastMember::setField(): boxType not implemented");
return false;
+ case kTheDropShadow:
+ warning("STUB: TextCastMember::setField(): dropShadow not implemented");
+ return false;
case kTheEditable:
_editable = d.asInt();
setModified(true);
Commit: 09458275a44ef8a97b30a7b780ab0a8c41b82491
https://github.com/scummvm/scummvm/commit/09458275a44ef8a97b30a7b780ab0a8c41b82491
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-16T01:21:19+02:00
Commit Message:
DIRECTOR: LINGO: Fix b_float to pass-through unknown data
Fixes Beat The Computer minigame in finkletimes.
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 401bcb9b299..bcae8992485 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -429,8 +429,11 @@ void LB::b_float(int nargs) {
// for some reason, float(str) will return str if it doesn't work
res = d;
}
- } else {
+ } else if (d.type == INT || d.type == FLOAT) {
res = d.asFloat();
+ } else {
+ warning("b_float: Attempted to process invalid type %s, returning same value", d.type2str());
+ res = d;
}
g_lingo->push(res);
Commit: a57bd423236f191d8e302dbab997bed6ce0a8504
https://github.com/scummvm/scummvm/commit/a57bd423236f191d8e302dbab997bed6ce0a8504
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-16T01:21:19+02:00
Commit Message:
DIRECTOR: Add file quirks for finkletimes
Changed paths:
engines/director/game-quirks.cpp
diff --git a/engines/director/game-quirks.cpp b/engines/director/game-quirks.cpp
index e6fed8c6690..a1df7ef7fa0 100644
--- a/engines/director/game-quirks.cpp
+++ b/engines/director/game-quirks.cpp
@@ -103,6 +103,17 @@ struct CachedFile {
"PATH.INI",
(const byte *)"[cd-path]\r\npath=d:\\", -1
},
+ // Professor Finkle's Times Table Factory has an installer that copies a bunch of empty files,
+ // which the game gets upset about if they don't exist.
+ {"finkletimes", Common::kPlatformWindows, "finkle.ini", (const byte *)"", 0},
+ {"finkletimes", Common::kPlatformWindows, "beatswch.txt", (const byte *)"", 0},
+ {"finkletimes", Common::kPlatformWindows, "fctrlist.txt", (const byte *)"", 0},
+ {"finkletimes", Common::kPlatformWindows, "gridscor.txt", (const byte *)"", 0},
+ {"finkletimes", Common::kPlatformWindows, "jokelist.txt", (const byte *)"", 0},
+ {"finkletimes", Common::kPlatformWindows, "lastplay.txt", (const byte *)"", 0},
+ {"finkletimes", Common::kPlatformWindows, "lernscor.txt", (const byte *)"", 0},
+ {"finkletimes", Common::kPlatformWindows, "namelist.txt", (const byte *)"", 0},
+ {"finkletimes", Common::kPlatformWindows, "userlist.txt", (const byte *)"", 0},
{ nullptr, Common::kPlatformUnknown, nullptr, nullptr, 0 }
};
Commit: 7f45835576ba9ad0b5a2975fb682e6ed6d3b55b1
https://github.com/scummvm/scummvm/commit/7f45835576ba9ad0b5a2975fb682e6ed6d3b55b1
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-16T01:21:19+02:00
Commit Message:
DIRECTOR: LINGO: Adjust check for repeated events
Currently we fire multiple copies of the same input event, to account
for possible cascading, then cancel it out by checking the last event
ID. Previously the handler could cause a context freeze, which would
trigger a different event and remove the last event ID, making e.g.
mouseUp run multiple times.
Makes mouse interactions more tolerable in Cracking the Conspiracy.
Changed paths:
engines/director/lingo/lingo-events.cpp
engines/director/movie.h
engines/director/types.h
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index afc6445c9ed..b63a984ea39 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -355,9 +355,10 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
}
void Movie::queueEvent(Common::Queue<LingoEvent> &queue, LEvent event, int targetId, Common::Point pos) {
- int eventId = _nextEventId++;
if (_nextEventId < 0)
_nextEventId = 0;
+ _nextEventId++;
+ int eventId = _nextEventId;
int oldQueueSize = queue.size();
@@ -490,7 +491,6 @@ void Lingo::processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent) {
// only one input event should be in flight at a time.
return;
}
- int lastEventId = -1;
Movie *movie = _vm->getCurrentMovie();
Score *sc = movie->getScore();
@@ -510,7 +510,8 @@ void Lingo::processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent) {
continue;
}
- if (lastEventId == el.eventId && !_passEvent) {
+ int lastEventId = movie->_lastEventId.getValOrDefault(el.event, 0);
+ if (lastEventId && lastEventId == el.eventId && !_passEvent) {
debugC(5, kDebugEvents, "Lingo::processEvents: swallowed event (%s, %s, %s, %d) because _passEvent was false",
_eventHandlerTypes[el.event], scriptType2str(el.scriptType), el.scriptId.asString().c_str(), el.channelId
);
@@ -523,6 +524,7 @@ void Lingo::processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent) {
_eventHandlerTypes[el.event], scriptType2str(el.scriptType), el.scriptId.asString().c_str(), el.channelId
);
bool completed = processEvent(el.event, el.scriptType, el.scriptId, el.channelId);
+ movie->_lastEventId[el.event] = el.eventId;
if (isInputEvent && !completed) {
debugC(5, kDebugEvents, "Lingo::processEvents: context frozen on an input event, stopping");
@@ -532,7 +534,7 @@ void Lingo::processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent) {
}
break;
}
- lastEventId = el.eventId;
+
}
}
diff --git a/engines/director/movie.h b/engines/director/movie.h
index 0dbf214a367..22d9056195e 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -192,11 +192,12 @@ public:
bool _timeOutPlay;
bool _isBeepOn;
+ Common::HashMap<LEvent, int> _lastEventId;
Common::String _script;
// A flag to disable the event processing in the Movie
- // This flag will be set when the user's interaction (mouse and key events like mouseUp, keyUp)
+ // This flag will be set when the user's interaction (mouse and key events like mouseUp, keyUp)
// shouldn't be recorded as movie event, which may cause undesirable change in the lingo script
bool _inGuiMessageBox = false;
diff --git a/engines/director/types.h b/engines/director/types.h
index 40278a2d553..357395a927b 100644
--- a/engines/director/types.h
+++ b/engines/director/types.h
@@ -483,6 +483,14 @@ struct Hash<Director::CastMemberID> {
}
};
+template<>
+struct Hash<Director::LEvent> {
+ uint operator()(const Director::LEvent &event) const {
+ return event;
+ }
+};
+
+
} // End of namespace Common
#endif
Commit: 4686b64473624c294f895647534c93e7e38b241c
https://github.com/scummvm/scummvm/commit/4686b64473624c294f895647534c93e7e38b241c
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-16T01:21:19+02:00
Commit Message:
DIRECTOR: XTRA: Add basic functionality to RolloverToolkit
This Xtra creates events which are basically the same as mouseEnter and
mouseLeave in D6, so we may as well co-opt them. From testing, the
extension does expect "pass" to work for script delegation, so we need to
use the input event queue.
This isn't 100% accurate; in real Director the handlers are fired off
during the CheckForRollovers call, whereas we reuse the input event
queue and proxy startRollover -> mouseEnter and endRollover ->
mouseExit. Maybe in the future this will be a problem, but for now this
keeps things simple and reusable.
Fixes various things in Cracking the Conspiracy.
Changed paths:
engines/director/lingo/lingo-events.cpp
engines/director/lingo/lingo.h
engines/director/lingo/xtras/rtk.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index b63a984ea39..7ca9a5776d6 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -131,37 +131,41 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
_currentActiveSpriteId = _score->getActiveSpriteIDFromPos(event.mousePos); // the clickOn
_currentMouseSpriteId = _score->getMouseSpriteIDFromPos(event.mousePos);
}
- event.channelId = spriteId;
+ // Very occasionally, we want to specify an event with a channel ID
+ // rather than infer it from the position. Allow it to override.
+ if (event.channelId == 0) {
+ event.channelId = spriteId;
+ }
// 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) || (event.event == kEventRightMouseDown)) {
- if (!spriteId && _isBeepOn) {
+ if (!event.channelId && _isBeepOn) {
g_lingo->func_beep(1);
}
- if (spriteId > 0) {
- if (_score->_channels[spriteId]->_sprite->shouldHilite()) {
- _currentHiliteChannelId = spriteId;
+ if (event.channelId > 0) {
+ if (_score->_channels[event.channelId]->_sprite->shouldHilite()) {
+ _currentHiliteChannelId = event.channelId;
g_director->_wm->_hilitingWidget = true;
g_director->getCurrentWindow()->setDirty(true);
g_director->getCurrentWindow()->addDirtyRect(_score->_channels[_currentHiliteChannelId]->getBbox());
}
- CastMember *cast = getCastMember(_score->_channels[spriteId]->_sprite->_castId);
+ CastMember *cast = getCastMember(_score->_channels[event.channelId]->_sprite->_castId);
if (cast && cast->_type == kCastButton)
_mouseDownWasInButton = true;
- if (_score->_channels[spriteId]->_sprite->_moveable) {
- _draggingSpriteOffset = _score->_channels[spriteId]->getPosition() - event.mousePos;
- _currentDraggedChannel = _score->_channels[spriteId];
+ if (_score->_channels[event.channelId]->_sprite->_moveable) {
+ _draggingSpriteOffset = _score->_channels[event.channelId]->getPosition() - event.mousePos;
+ _currentDraggedChannel = _score->_channels[event.channelId];
}
// In the case of clicking the mouse, it is possible for a mouseDown action to
// change the cast member underneath. on mouseUp should always load the cast
// script for the original cast member, not the new one.
- _currentMouseDownCastID = _score->_channels[spriteId]->_sprite->_castId;
+ _currentMouseDownCastID = _score->_channels[event.channelId]->_sprite->_castId;
} else {
_currentHiliteChannelId = 0;
@@ -185,8 +189,8 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
// Now you might think, "Wait, we don't flip this flag in the mouseDown event.
// And why any button??? This doesn't make any sense."
// No, it doesn't make sense, but it's what Director does.
- if (_mouseDownWasInButton && spriteId) {
- CastMember *cast = getCastMember(_score->_channels[spriteId]->_sprite->_castId);
+ if (_mouseDownWasInButton && event.channelId) {
+ CastMember *cast = getCastMember(_score->_channels[event.channelId]->_sprite->_castId);
if (cast && cast->_type == kCastButton)
cast->_hilite = !cast->_hilite;
}
@@ -224,11 +228,11 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
* [D4 docs] */
case kSpriteHandler:
{
- if (!spriteId)
+ if (!event.channelId)
return;
Frame *currentFrame = _score->_currentFrame;
assert(currentFrame != nullptr);
- Sprite *sprite = _score->getSpriteById(spriteId);
+ Sprite *sprite = _score->getSpriteById(event.channelId);
// Sprite (score) script
if (sprite && sprite->_scriptId.member) {
@@ -267,9 +271,9 @@ void Movie::resolveScriptEvent(LingoEvent &event) {
// so we have to do it too.
CastMemberID targetCast = _currentMouseDownCastID;
if ((event.event == kEventMouseDown) || (event.event == kEventRightMouseDown)) {
- if (!spriteId)
+ if (!event.channelId)
return;
- Sprite *sprite = _score->getSpriteById(spriteId);
+ Sprite *sprite = _score->getSpriteById(event.channelId);
targetCast = sprite->_castId;
}
@@ -362,6 +366,8 @@ void Movie::queueEvent(Common::Queue<LingoEvent> &queue, LEvent event, int targe
int oldQueueSize = queue.size();
+ uint16 channelId = 0;
+
/* When an event occurs the message [...] is first sent to a
* primary event handler: [... if exists it is executed] and the
* event is passed on to other objects unless you explicitly stop
@@ -396,6 +402,13 @@ void Movie::queueEvent(Common::Queue<LingoEvent> &queue, LEvent event, int targe
}
}
break;
+ // For mouseEnter/mouseLeave events, we want to specify exactly what sprite channel to resolve to.
+ case kEventMouseEnter:
+ case kEventMouseLeave:
+ if (targetId != 0) {
+ channelId = targetId;
+ }
+ break;
default:
break;
}
@@ -446,15 +459,17 @@ void Movie::queueEvent(Common::Queue<LingoEvent> &queue, LEvent event, int targe
case kEventRightMouseUp:
case kEventRightMouseDown:
case kEventBeginSprite:
- queue.push(LingoEvent(event, eventId, kSpriteHandler, false, pos));
- queue.push(LingoEvent(event, eventId, kCastHandler, false, pos));
+ case kEventMouseEnter:
+ case kEventMouseLeave:
+ queue.push(LingoEvent(event, eventId, kSpriteHandler, false, pos, channelId));
+ queue.push(LingoEvent(event, eventId, kCastHandler, false, pos, channelId));
// fall through
case kEventIdle:
case kEventEnterFrame:
case kEventExitFrame:
case kEventTimeout:
- queue.push(LingoEvent(event, eventId, kFrameHandler, false, pos));
+ queue.push(LingoEvent(event, eventId, kFrameHandler, false, pos, channelId));
// fall through
case kEventStartUp:
@@ -462,7 +477,7 @@ void Movie::queueEvent(Common::Queue<LingoEvent> &queue, LEvent event, int targe
case kEventStepMovie:
case kEventStopMovie:
case kEventPrepareMovie:
- queue.push(LingoEvent(event, eventId, kMovieHandler, false, pos));
+ queue.push(LingoEvent(event, eventId, kMovieHandler, false, pos, channelId));
break;
default:
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index efbee0070b4..e8126861000 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -283,13 +283,13 @@ struct LingoEvent {
mousePos = mp;
}
- LingoEvent (LEvent e, int ei, EventHandlerSourceType ehst, bool pass, Common::Point mp = Common::Point(-1, -1)) {
+ LingoEvent (LEvent e, int ei, EventHandlerSourceType ehst, bool pass, Common::Point mp = Common::Point(-1, -1), uint16 ci = 0) {
event = e;
eventId = ei;
eventHandlerSourceType = ehst;
scriptType = kNoneScript;
passByDefault = pass;
- channelId = 0;
+ channelId = ci;
scriptId = CastMemberID();
mousePos = mp;
}
@@ -530,6 +530,7 @@ public:
OpenXLibsHash _openXLibs;
OpenXLibsStateHash _openXLibsState;
Common::StringArray _openXtras;
+ OpenXLibsStateHash _openXtrasState;
Common::String _floatPrecisionFormat;
diff --git a/engines/director/lingo/xtras/rtk.cpp b/engines/director/lingo/xtras/rtk.cpp
index 5131d67e776..c755c89e277 100644
--- a/engines/director/lingo/xtras/rtk.cpp
+++ b/engines/director/lingo/xtras/rtk.cpp
@@ -22,6 +22,9 @@
#include "common/system.h"
#include "director/director.h"
+#include "director/movie.h"
+#include "director/score.h"
+#include "director/window.h"
#include "director/lingo/lingo.h"
#include "director/lingo/lingo-object.h"
#include "director/lingo/lingo-utils.h"
@@ -112,6 +115,14 @@ static BuiltinProto xlibBuiltins[] = {
{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
};
+class RolloverToolkitXtraState : public Object<RolloverToolkitXtraState>
+{
+public:
+ RolloverToolkitXtraState() : Object<RolloverToolkitXtraState>("Rollover_Toolkit") {};
+
+ int lastSprite = 0;
+};
+
RolloverToolkitXtraObject::RolloverToolkitXtraObject(ObjectType ObjectType) :Object<RolloverToolkitXtraObject>("RolloverToolkit") {
_objType = ObjectType;
}
@@ -134,6 +145,13 @@ void RolloverToolkitXtra::open(ObjectType type, const Common::Path &path) {
g_lingo->_openXtras.push_back(xlibName);
g_lingo->exposeXObject(xlibName, xobj);
g_lingo->initBuiltIns(xlibBuiltins);
+ if (!g_lingo->_openXtrasState.contains("Rollover_Toolkit")) {
+ RolloverToolkitXtraState *state = new RolloverToolkitXtraState();
+ g_lingo->_openXtrasState.setVal("Rollover_Toolkit", state);
+ }
+ // Add some extra mappings for event compatibility
+ g_lingo->_eventHandlerTypeIds["startRollover"] = kEventMouseEnter;
+ g_lingo->_eventHandlerTypeIds["endRollover"] = kEventMouseLeave;
}
void RolloverToolkitXtra::close(ObjectType type) {
@@ -148,7 +166,44 @@ void RolloverToolkitXtra::m_new(int nargs) {
g_lingo->push(g_lingo->_state->me);
}
-XOBJSTUB(RolloverToolkitXtra::m_CheckForRollovers, 0)
+void RolloverToolkitXtra::m_CheckForRollovers(int nargs) {
+ // We don't need any hints about what the current rollover is
+ g_lingo->dropStack(nargs);
+
+ // check what the current rolled over sprite is
+ // if it's new
+ // - check if there's an on endRollover handler, provide old sprite as arg 1
+ // - check if there's a on startRollover handler, provide new sprite as arg 1
+ Movie *movie = g_director->getCurrentMovie();
+ Score *score = movie->getScore();
+
+ if (!score) {
+ warning("RolloverToolkitXtra::m_CheckForRollovers: Reference to an empty score");
+ return;
+ }
+
+ if (!g_lingo->_openXtrasState.contains("Rollover_Toolkit")) {
+ warning("RolloverToolkitXtra::m_CheckForRollovers: Missing state");
+ return;
+ }
+ RolloverToolkitXtraState *state = (RolloverToolkitXtraState *)g_lingo->_openXtrasState.getVal("Rollover_Toolkit");
+
+
+ Common::Point pos = g_director->getCurrentWindow()->getMousePos();
+ int lastSprite = state->lastSprite;
+ int newSprite = score->getRollOverSpriteIDFromPos(pos);
+ if (newSprite != lastSprite && lastSprite != 0) {
+ // try and call endRollover(lastSprite)
+ movie->queueInputEvent(kEventMouseLeave, lastSprite, pos);
+ }
+ if (newSprite != lastSprite && newSprite != 0) {
+ // try and call startRollover(lastSprite)
+ movie->queueInputEvent(kEventMouseEnter, newSprite, pos);
+ }
+ state->lastSprite = newSprite;
+}
+
+
XOBJSTUB(RolloverToolkitXtra::m_CurrentRollover, 0)
XOBJSTUB(RolloverToolkitXtra::m_EndAnyRollovers, 0)
XOBJSTUB(RolloverToolkitXtra::m_ResetRollovers, 0)
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index dd2b25d224d..19d669b198d 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -1552,6 +1552,16 @@ bool Score::checkSpriteRollOver(uint16 spriteId, Common::Point pos) {
return false;
}
+uint16 Score::getRollOverSpriteIDFromPos(Common::Point pos) {
+ for (int i = _channels.size() - 1; i >= 0; i--) {
+ if (_channels[i]->getRollOverBbox().contains(pos))
+ return i;
+ }
+
+ return 0;
+}
+
+
Common::List<Channel *> Score::getSpriteIntersections(const Common::Rect &r) {
Common::List<Channel *> intersections;
Common::List<Channel *> appendix;
diff --git a/engines/director/score.h b/engines/director/score.h
index 75531ebce06..8be8414434c 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -113,6 +113,7 @@ public:
uint16 getMouseSpriteIDFromPos(Common::Point pos);
uint16 getActiveSpriteIDFromPos(Common::Point pos);
bool checkSpriteRollOver(uint16 spriteId, Common::Point pos);
+ uint16 getRollOverSpriteIDFromPos(Common::Point pos);
Common::List<Channel *> getSpriteIntersections(const Common::Rect &r);
uint16 getSpriteIdByMemberId(CastMemberID id);
bool refreshPointersForCastMemberID(CastMemberID id);
Commit: fabaae75a7e180ad4a7ae35c2a272a8d8d8e835d
https://github.com/scummvm/scummvm/commit/fabaae75a7e180ad4a7ae35c2a272a8d8d8e835d
Author: Scott Percival (code at moral.net.au)
Date: 2025-06-16T01:21:19+02:00
Commit Message:
DIRECTOR: LINGO: Provide argument to startRollover/endRollover
Changed paths:
engines/director/lingo/lingo-events.cpp
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index 7ca9a5776d6..c4452e4ea9f 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -560,11 +560,21 @@ bool Lingo::processEvent(LEvent event, ScriptType st, CastMemberID scriptId, int
error("processEvent: Unknown event %d", event);
ScriptContext *script = g_director->getCurrentMovie()->getScriptContext(st, scriptId);
+ int nargs = 0;
if (script && script->_eventHandlers.contains(event)) {
debugC(1, kDebugEvents, "Lingo::processEvent(%s, %s, %s): executing event handler", _eventHandlerTypes[event], scriptType2str(st), scriptId.asString().c_str());
g_debugger->eventHook(event);
- LC::call(script->_eventHandlers[event], 0, false);
+
+ // Normally event handlers are called with no arguments, however RolloverToolkit expects
+ // the first argument to be the sprite number.
+ if ((event == kEventMouseEnter && script->_eventHandlers[event].name->equalsIgnoreCase("startRollover")) ||
+ (event == kEventMouseLeave && script->_eventHandlers[event].name->equalsIgnoreCase("endRollover"))) {
+ push(Datum(channelId));
+ nargs = 1;
+ }
+
+ LC::call(script->_eventHandlers[event], nargs, false);
return execute();
} else {
debugC(9, kDebugEvents, "Lingo::processEvent(%s, %s, %s): no handler", _eventHandlerTypes[event], scriptType2str(st), scriptId.asString().c_str());
More information about the Scummvm-git-logs
mailing list