[Scummvm-git-logs] scummvm master -> 33c576982b3ddda2f9b3aaba52e51e32b13c2855
sev-
noreply at scummvm.org
Sat Jun 15 00:04:39 UTC 2024
This automated email contains information about 18 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
cfda6aaf2c DIRECTOR: Update freezing logic to match test suite
2ce1715c07 DIRECTOR: Move stepMovie handler in front of enterFrame handler
cb0aeaed94 DIRECTOR: Only check stepMovie/enterFrame for freeze recursion
1520e3c2af DIRECTOR: XOBJ: Add abort feature to MMovie
cf6ef878e4 DIRECTOR: Add nullptr guardrail in Channel::setStretch()
690cd9c6a0 DIRECTOR: Add frame and sprite script mappings to debugger 'funcs' command
86c5098169 DIRECTOR: Add separate execution freeze for "play" calls
aba127068e DIRECTOR: XOBJ: Add stubs for GenUtils
4d10b88c4b DIRECTOR: Fix c_field to work in D5 and up
7a33457718 DIRECTOR: Execute ancestor factory methods with the child object
bdc809b0cb DIRECTOR: LINGO: Add nullptr guardrails for getMenu()
b033c63068 DIRECTOR: XOBJ: Add full stubs to MovUtils
83e1d42ffa DIRECTOR: Fix Window::invertChannel in 32-bit mode
39d31fd431 DIRECTOR: Fix dissolve transitions for 32-bit mode
12918d9fbd DIRECTOR: Fix redithering 8-bit images in 32-bit mode
215e5ed29a DIRECTOR: Fix crash when suspending on a "play" call
094f207fac DIRECTOR: Fix playing video immediately after assigning to sprite
33c576982b DIRECTOR: Fix b_installMenu for D5
Commit: cfda6aaf2c6765c78d6098b6c6b2d4a54e02e538
https://github.com/scummvm/scummvm/commit/cfda6aaf2c6765c78d6098b6c6b2d4a54e02e538
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Update freezing logic to match test suite
Fixes director-tests/D4-unit/T_EVNT13.DIR to T_EVNT17.DIR
Changed paths:
engines/director/lingo/lingo.cpp
engines/director/score.cpp
engines/director/score.h
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index b8ba3456b85..351fcc5fb0b 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -645,10 +645,6 @@ bool Lingo::execute() {
score->updateWidgets(true);
g_system->updateScreen();
- if (_vm->getCurrentMovie()->getScore()->_playState == kPlayStopped) {
- _freezeState = true;
- break;
- }
}
uint current = _state->pc;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index b3718cbdf09..e7a8e570456 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -131,15 +131,17 @@ bool Score::processImmediateFrameScript(Common::String s, int id) {
return false;
}
-bool Score::processFrozenScripts() {
+bool Score::processFrozenScripts(int count) {
// Unfreeze any in-progress scripts and attempt to run them
// to completion.
- while (uint32 count = _window->frozenLingoStateCount()) {
+ bool limit = count != 0;
+ uint32 remainCount = _window->frozenLingoStateCount();
+ while (remainCount && (limit ? count > 0 : true)) {
_window->thawLingoState();
Symbol currentScript = _window->getLingoState()->callstack.front()->sp;
g_lingo->switchStateFromWindow();
bool completed = g_lingo->execute();
- if (!completed || _window->frozenLingoStateCount() >= count) {
+ if (!completed || _window->frozenLingoStateCount() >= remainCount) {
debugC(3, kDebugLingoExec, "Score::processFrozenScripts(): State froze again mid-thaw, interrupting");
return false;
} else if (currentScript == g_lingo->_currentInputEvent) {
@@ -147,6 +149,8 @@ bool Score::processFrozenScripts() {
debugC(3, kDebugEvents, "Score::processFrozenScripts(): Input event completed");
g_lingo->_currentInputEvent = Symbol();
}
+ remainCount = _window->frozenLingoStateCount();
+ count -= 1;
}
return true;
}
@@ -568,7 +572,6 @@ void Score::update() {
// the exitFrame event handler may have stopped this movie
if (_playState == kPlayStopped) {
- processFrozenScripts();
return;
}
@@ -618,6 +621,7 @@ void Score::update() {
if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
_movie->processEvent(kEventStepMovie);
}
+ // If this stepMovie call is frozen, drop the next enterFrame event
if (_window->frozenLingoStateCount() > count)
return;
diff --git a/engines/director/score.h b/engines/director/score.h
index 4530310ef6b..51197f3f026 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -144,7 +144,7 @@ private:
bool checkShotSimilarity(const Graphics::Surface *surface1, const Graphics::Surface *surface2);
bool processImmediateFrameScript(Common::String s, int id);
- bool processFrozenScripts();
+ bool processFrozenScripts(int count = 0);
public:
Common::Array<Channel *> _channels;
Commit: 2ce1715c07674eac029a236afaac22b82bde3f19
https://github.com/scummvm/scummvm/commit/2ce1715c07674eac029a236afaac22b82bde3f19
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Move stepMovie handler in front of enterFrame handler
Fixes director-tests/D4-unit/T_EVNT01.DIR
Changed paths:
engines/director/score.cpp
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index e7a8e570456..5f17fb9622c 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -604,7 +604,9 @@ void Score::update() {
if (_window->frozenLingoStateCount() > count)
return;
- // check to see if we've hit the recursion limit
+ // Check to see if we've hit the recursion limit
+ // In practice, it seems like it checks for more than 2 stepMovie/enterFrame handlers in a row, as they are
+ // the only ones capable of cascading.
if (_vm->getVersion() >= 400 && _window->frozenLingoStateCount() >= 2) {
debugC(1, kDebugEvents, "Score::update(): hitting depth limit for D4 scripts, defrosting");
processFrozenScripts();
@@ -615,16 +617,6 @@ void Score::update() {
return;
}
- // then call the stepMovie hook (if one exists)
- // skip the first frame
- count = _window->frozenLingoStateCount();
- if (!_window->_newMovieStarted && !_vm->_playbackPaused) {
- _movie->processEvent(kEventStepMovie);
- }
- // If this stepMovie call is frozen, drop the next enterFrame event
- 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
@@ -636,6 +628,17 @@ void Score::update() {
renderFrame(_curFrameNumber);
_window->_newMovieStarted = false;
+ // then call the stepMovie hook (if one exists)
+ // D4 and above only call it if _allowOutdatedLingo is enabled.
+ count = _window->frozenLingoStateCount();
+ if (!_vm->_playbackPaused && (_vm->getVersion() < 400 || _movie->_allowOutdatedLingo)) {
+ _movie->processEvent(kEventStepMovie);
+ }
+ // If this stepMovie call is frozen, drop the next enterFrame event
+ if (_window->frozenLingoStateCount() > count)
+ return;
+
+
// then call the enterFrame hook (if one exists)
count = _window->frozenLingoStateCount();
if (!_vm->_playbackPaused) {
Commit: cb0aeaed949d03af95f357048e56665267755e21
https://github.com/scummvm/scummvm/commit/cb0aeaed949d03af95f357048e56665267755e21
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Only check stepMovie/enterFrame for freeze recursion
Fixes director-tests/D4-unit/T_EVNT18.DIR
Changed paths:
engines/director/score.cpp
engines/director/score.h
engines/director/window.cpp
engines/director/window.h
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 5f17fb9622c..56e99685c0d 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -131,17 +131,17 @@ bool Score::processImmediateFrameScript(Common::String s, int id) {
return false;
}
-bool Score::processFrozenScripts(int count) {
+bool Score::processFrozenScripts(bool recursion, int count) {
// Unfreeze any in-progress scripts and attempt to run them
// to completion.
bool limit = count != 0;
- uint32 remainCount = _window->frozenLingoStateCount();
+ uint32 remainCount = recursion ? _window->frozenLingoRecursionCount() : _window->frozenLingoStateCount();
while (remainCount && (limit ? count > 0 : true)) {
_window->thawLingoState();
Symbol currentScript = _window->getLingoState()->callstack.front()->sp;
g_lingo->switchStateFromWindow();
bool completed = g_lingo->execute();
- if (!completed || _window->frozenLingoStateCount() >= remainCount) {
+ if (!completed || (recursion ? _window->frozenLingoRecursionCount() : _window->frozenLingoStateCount()) >= remainCount) {
debugC(3, kDebugLingoExec, "Score::processFrozenScripts(): State froze again mid-thaw, interrupting");
return false;
} else if (currentScript == g_lingo->_currentInputEvent) {
@@ -149,7 +149,7 @@ bool Score::processFrozenScripts(int count) {
debugC(3, kDebugEvents, "Score::processFrozenScripts(): Input event completed");
g_lingo->_currentInputEvent = Symbol();
}
- remainCount = _window->frozenLingoStateCount();
+ remainCount = recursion ? _window->frozenLingoRecursionCount() : _window->frozenLingoStateCount();
count -= 1;
}
return true;
@@ -314,7 +314,7 @@ void Score::step() {
if (_playState == kPlayStopped)
return;
- if (!_movie->_inputEventQueue.empty()) {
+ if (!_movie->_inputEventQueue.empty() && !_window->frozenLingoStateCount()) {
_lingo->processEvents(_movie->_inputEventQueue, true);
}
if (_vm->getVersion() >= 300 && !_window->_newMovieStarted && _playState != kPlayStopped) {
@@ -605,12 +605,10 @@ void Score::update() {
return;
// Check to see if we've hit the recursion limit
- // In practice, it seems like it checks for more than 2 stepMovie/enterFrame handlers in a row, as they are
- // the only ones capable of cascading.
- if (_vm->getVersion() >= 400 && _window->frozenLingoStateCount() >= 2) {
- debugC(1, kDebugEvents, "Score::update(): hitting depth limit for D4 scripts, defrosting");
- processFrozenScripts();
- return;
+ if (_vm->getVersion() >= 400 && _window->frozenLingoRecursionCount() >= 2) {
+ debugC(1, kDebugEvents, "Score::update(): hitting D4 recursion depth limit, defrosting");
+ processFrozenScripts(true);
+ // keep plowing on
} else if (_window->frozenLingoStateCount() >= 64) {
warning("Score::update(): Stopping runaway script recursion. By this point D3 will have run out of stack space");
processFrozenScripts();
diff --git a/engines/director/score.h b/engines/director/score.h
index 51197f3f026..12317acc0e0 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -144,7 +144,7 @@ private:
bool checkShotSimilarity(const Graphics::Surface *surface1, const Graphics::Surface *surface2);
bool processImmediateFrameScript(Common::String s, int id);
- bool processFrozenScripts(int count = 0);
+ bool processFrozenScripts(bool recursion = false, int count = 0);
public:
Common::Array<Channel *> _channels;
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 39cfd165723..1a8dbcd546b 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -636,19 +636,28 @@ void Window::thawLingoState() {
_frozenLingoStates.pop_back();
}
-// Check how many times previous enterFrame is called recursively, D4 will only process recursive enterFrame handlers to a depth of 2.
-// Therefore look into frozen lingo states and count previous pending enterFrame calls
-// eg. in a movie, frame 1 has an enterFrame handler that calls go(2), frame 2 has an enterFrame handler that calls go(3), now after
-// each frame is processed and it encounters a frame jump instruction (like go, open), it freezes the lingo state and then processes
-// the next frame. How do we know number of times enterFrame is called? Simple look into frozen lingo states for enterFrame calls.
-int Window::recursiveEnterFrameCount() {
- int count = 0;
-
- for (int i = _frozenLingoStates.size() - 1; i >= 0; i--) {
+// Check how many times enterFrame/stepMovie have been called recursively.
+// When Lingo encounters a go() call, it freezes the execution state and starts
+// processing the next frame. In the case of enterFrame/stepMovie, it is possible
+// to keep recursing without reaching a point where the frozen contexts are finished.
+// D4 and higher will only process recursive handlers to a depth of 2.
+// e.g. in a movie:
+// - frame 1 has an enterFrame handler that calls go(2)
+// - frame 2 has an enterFrame handler that calls go(3)
+// - frame 3 has an enterFrame handler that calls go(4)
+// The third enterFrame handler will be eaten and not called.
+// We can count the number of frozen states which started from enterFrame/stepMovie.
+uint32 Window::frozenLingoRecursionCount() {
+ uint32 count = 0;
+
+ for (int i = (int)_frozenLingoStates.size() - 1; i >= 0; i--) {
LingoState *state = _frozenLingoStates[i];
- CFrame *frame = state->callstack.back();
- if (frame->sp.name->equalsIgnoreCase("enterFrame")) {
+ CFrame *frame = state->callstack.front();
+ if (frame->sp.name->equalsIgnoreCase("enterFrame") ||
+ frame->sp.name->equalsIgnoreCase("stepMovie")) {
count++;
+ } else {
+ break;
}
}
diff --git a/engines/director/window.h b/engines/director/window.h
index 4881649c5a6..b3e6498c84c 100644
--- a/engines/director/window.h
+++ b/engines/director/window.h
@@ -159,10 +159,10 @@ public:
LingoState *getLingoState() { return _lingoState; };
uint32 frozenLingoStateCount() { return _frozenLingoStates.size(); };
+ uint32 frozenLingoRecursionCount();
void freezeLingoState();
void thawLingoState();
LingoState *getLastFrozenLingoState() { return _frozenLingoStates.empty() ? nullptr : _frozenLingoStates[_frozenLingoStates.size() - 1]; }
- int recursiveEnterFrameCount();
// events.cpp
bool processEvent(Common::Event &event) override;
Commit: 1520e3c2af9c41e8d391558b556cc304e6c62ef5
https://github.com/scummvm/scummvm/commit/1520e3c2af9c41e8d391558b556cc304e6c62ef5
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: XOBJ: Add abort feature to MMovie
Changed paths:
engines/director/lingo/xlibs/mmovie.cpp
diff --git a/engines/director/lingo/xlibs/mmovie.cpp b/engines/director/lingo/xlibs/mmovie.cpp
index 4b955d69bd7..4e2ab870582 100644
--- a/engines/director/lingo/xlibs/mmovie.cpp
+++ b/engines/director/lingo/xlibs/mmovie.cpp
@@ -186,6 +186,13 @@ int MMovieXObject::updateScreenBlocking() {
if (_abortOnClick) {
result = MMovieError::MMOVIE_ABORT_DOUBLE_CLICK;
keepPlaying = false;
+ } else if (_shiftAbort) {
+ if (event.type == Common::EVENT_RBUTTONDOWN ||
+ (event.type == Common::EVENT_LBUTTONDOWN &&
+ (g_system->getEventManager()->getModifierState() & Common::KBD_SHIFT))) {
+ result = MMovieError::MMOVIE_ABORT_DOUBLE_CLICK;
+ keepPlaying = false;
+ }
}
break;
default:
Commit: cf6ef878e43fa77f8fb1644b8f0af1c5b4374b47
https://github.com/scummvm/scummvm/commit/cf6ef878e43fa77f8fb1644b8f0af1c5b4374b47
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Add nullptr guardrail in Channel::setStretch()
Changed paths:
engines/director/channel.cpp
diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index 1f796578770..0a65116f606 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -474,9 +474,11 @@ void Channel::setStretch(bool enabled) {
g_director->getCurrentWindow()->addDirtyRect(getBbox());
_dirty = true;
- Common::Rect bbox = _sprite->_cast->getBbox();
- _sprite->setWidth(bbox.width());
- _sprite->setHeight(bbox.height());
+ if (_sprite->_cast) {
+ Common::Rect bbox = _sprite->_cast->getBbox();
+ _sprite->setWidth(bbox.width());
+ _sprite->setHeight(bbox.height());
+ }
}
_sprite->_stretch = enabled;
}
Commit: 690cd9c6a04bdacaca8dc36ab11e495d662a2440
https://github.com/scummvm/scummvm/commit/690cd9c6a04bdacaca8dc36ab11e495d662a2440
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Add frame and sprite script mappings to debugger 'funcs' command
Changed paths:
engines/director/debugger.cpp
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index d4489a0a3a6..35e85c4984a 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -338,7 +338,7 @@ bool Debugger::cmdChannels(int argc, const char **argv) {
if (frameId >= 1 && frameId <= maxSize) {
debugPrintf("Channel info for frame %d of %d\n", frameId, maxSize);
- Frame *frame = score->getFrameData(frameId);
+ Frame *frame = score->_scoreCache[frameId - 1];
if (frame) {
debugPrintf("%s\n", frame->formatChannelInfo().c_str());
delete frame;
@@ -468,6 +468,27 @@ bool Debugger::cmdFuncs(int argc, const char **argv) {
debugPrintf(" [empty]\n");
}
debugPrintf("\n");
+ debugPrintf("Frame script mappings:\n");
+ for (int i = 0; i < (int)score->_scoreCache.size(); i++) {
+ Frame *frame = score->_scoreCache[i];
+ if (frame && frame->_mainChannels.actionId.member) {
+ debugPrintf(" %d: %s\n", i + 1, frame->_mainChannels.actionId.asString().c_str());
+ }
+ }
+ debugPrintf("Sprite script mappings:\n");
+ for (int i = 0; i < (int)score->_scoreCache.size(); i++) {
+ Frame *frame = score->_scoreCache[i];
+ if (frame) {
+ for (int j = 0; j < (int)frame->_sprites.size(); j++) {
+ Sprite *sprite = frame->_sprites[j];
+ if (sprite->_scriptId.member) {
+ debugPrintf(" %d, sprite %d: %s\n", i + 1, j, sprite->_scriptId.asString().c_str());
+ }
+ }
+ }
+ }
+
+
return true;
}
Commit: 86c5098169584609fa1f1d883915116436ded74c
https://github.com/scummvm/scummvm/commit/86c5098169584609fa1f1d883915116436ded74c
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Add separate execution freeze for "play" calls
According to the Director documentation, "play" acts in a very different
way to "go". Instead of freezing execution of the handler as part of the
stack, it will freeze the handler and defer it until "play done" is
called by something else. This adds a method for doing this, plus
workarounds to not impact the event processing pipeline.
Fixes picking up most of the time trumpets in Virtual Nightclub
(1580:winASWarp in shared.dxr).
Changed paths:
engines/director/lingo/lingo-code.cpp
engines/director/lingo/lingo-funcs.cpp
engines/director/lingo/lingo.cpp
engines/director/lingo/lingo.h
engines/director/score.cpp
engines/director/window.cpp
engines/director/window.h
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index a91a9ef40eb..27194b2431a 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -375,6 +375,12 @@ void Lingo::freezeState() {
switchStateFromWindow();
}
+void Lingo::freezePlayState() {
+ Window *window = _vm->getCurrentWindow();
+ window->freezeLingoPlayState();
+ switchStateFromWindow();
+}
+
void LC::c_constpush() {
Common::String name(g_lingo->readString());
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index d748084a3db..5292fb1cb0a 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -148,7 +148,9 @@ void Lingo::func_play(Datum &frame, Datum &movie) {
warning("Lingo::func_play: unknown symbol: #%s", frame.u.s->c_str());
return;
}
+ _playDone = true;
if (stage->_movieStack.empty()) { // No op if no nested movies
+
return;
}
ref = stage->_movieStack.back();
@@ -189,6 +191,7 @@ void Lingo::func_play(Datum &frame, Datum &movie) {
stage->_movieStack.push_back(ref);
func_goto(frame, movie);
+ _freezePlay = true;
}
void Lingo::func_cursor(Datum cursorDatum) {
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 351fcc5fb0b..a082432efed 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -176,6 +176,8 @@ Lingo::Lingo(DirectorEngine *vm) : _vm(vm) {
_currentChannelId = -1;
_globalCounter = 0;
_freezeState = false;
+ _freezePlay = false;
+ _playDone = false;
_abort = false;
_expectError = false;
_caughtError = false;
@@ -687,7 +689,10 @@ bool Lingo::execute() {
}
bool result = !_freezeState;
- if (_freezeState) {
+ if (_freezePlay) {
+ debugC(5, kDebugLingoExec, "Lingo::execute(): Called play, pausing execution to the play buffer");
+ freezePlayState();
+ } else if (_freezeState) {
debugC(5, kDebugLingoExec, "Lingo::execute(): Context is frozen, pausing execution");
freezeState();
} else if (_abort || _vm->getCurrentMovie()->getScore()->_playState == kPlayStopped) {
@@ -698,6 +703,7 @@ bool Lingo::execute() {
}
_abort = false;
_freezeState = false;
+ _freezePlay = false;
g_debugger->stepHook();
// return true if execution finished, false if the context froze for later
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 4f787f97041..43d95e97ab5 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -407,6 +407,7 @@ public:
bool execute();
void switchStateFromWindow();
void freezeState();
+ void freezePlayState();
void pushContext(const Symbol funcSym, bool allowRetVal, Datum defaultRetVal, int paramCount);
void popContext(bool aborting = false);
void cleanLocalVars();
@@ -500,6 +501,8 @@ public:
int _currentChannelId;
bool _freezeState;
+ bool _freezePlay;
+ bool _playDone;
bool _abort;
bool _expectError;
bool _caughtError;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 56e99685c0d..ee9150f5ff1 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -132,17 +132,41 @@ bool Score::processImmediateFrameScript(Common::String s, int id) {
}
bool Score::processFrozenScripts(bool recursion, int count) {
+ // Unfreeze the play script if the special flag is set
+ if (g_lingo->_playDone) {
+ g_lingo->_playDone = false;
+ _window->thawLingoPlayState();
+ Symbol currentScript = _window->getLingoState()->callstack.front()->sp;
+ g_lingo->switchStateFromWindow();
+ bool completed = g_lingo->execute();
+ if (!completed) {
+ debugC(3, kDebugLingoExec, "Score::processFrozenScripts(): State froze again mid-thaw, interrupting");
+ return false;
+ } else if (currentScript == g_lingo->_currentInputEvent) {
+ // script that just completed was the current input event, clear the flag
+ debugC(3, kDebugEvents, "Score::processFrozenScripts(): Input event completed");
+ g_lingo->_currentInputEvent = Symbol();
+ }
+ }
+
// Unfreeze any in-progress scripts and attempt to run them
// to completion.
bool limit = count != 0;
uint32 remainCount = recursion ? _window->frozenLingoRecursionCount() : _window->frozenLingoStateCount();
while (remainCount && (limit ? count > 0 : true)) {
_window->thawLingoState();
- Symbol currentScript = _window->getLingoState()->callstack.front()->sp;
+ LingoState *state = _window->getLingoState();
+ Symbol currentScript = state->callstack.front()->sp;
g_lingo->switchStateFromWindow();
bool completed = g_lingo->execute();
if (!completed || (recursion ? _window->frozenLingoRecursionCount() : _window->frozenLingoStateCount()) >= remainCount) {
debugC(3, kDebugLingoExec, "Score::processFrozenScripts(): State froze again mid-thaw, interrupting");
+ // Workaround for if a state gets moved to to the play state
+ if (currentScript == g_lingo->_currentInputEvent && state == _window->getLingoPlayState()) {
+ debugC(3, kDebugEvents, "Score::processFrozenScripts(): Input event got moved to the play state, clearing block");
+ g_lingo->_currentInputEvent = Symbol();
+ }
+
return false;
} else if (currentScript == g_lingo->_currentInputEvent) {
// script that just completed was the current input event, clear the flag
@@ -657,7 +681,7 @@ void Score::update() {
// Attempt to thaw and continue any frozen execution after startMovie and enterFrame.
// If they don't complete (i.e. another freezing event like a "go to frame"),
// force another cycle of Score::update().
- if (!processFrozenScripts())
+ if (!_nextFrame && !processFrozenScripts())
return;
if (!_vm->_playbackPaused) {
@@ -1613,9 +1637,7 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
// Calculate number of frames and their positions
// numOfFrames in the header is often incorrect
for (_numFrames = 1; loadFrame(_numFrames, false); _numFrames++) {
- if (debugChannelSet(-1, kDebugImGui)) {
- _scoreCache.push_back(new Frame(*_currentFrame));
- }
+ _scoreCache.push_back(new Frame(*_currentFrame));
}
debugC(1, kDebugLoading, "Score::loadFrames(): Calculated, total number of frames %d!", _numFrames);
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 1a8dbcd546b..88a92cbba20 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -49,6 +49,7 @@ Window::Window(int id, bool scrollable, bool resizable, bool editable, Graphics:
_puppetTransition = nullptr;
_soundManager = new DirectorSound(this);
_lingoState = new LingoState;
+ _lingoPlayState = nullptr;
_currentMovie = nullptr;
_mainArchive = nullptr;
@@ -68,6 +69,8 @@ Window::Window(int id, bool scrollable, bool resizable, bool editable, Graphics:
Window::~Window() {
delete _lingoState;
+ if (_lingoPlayState)
+ delete _lingoPlayState;
delete _soundManager;
delete _currentMovie;
for (uint i = 0; i < _frozenLingoStates.size(); i++)
@@ -636,6 +639,32 @@ void Window::thawLingoState() {
_frozenLingoStates.pop_back();
}
+void Window::freezeLingoPlayState() {
+ if (_lingoPlayState) {
+ warning("FIXME: Just clobbered the play state");
+ delete _lingoPlayState;
+ }
+ _lingoPlayState = _lingoState;
+ _lingoState = new LingoState;
+ debugC(kDebugLingoExec, 3, "Freezing Lingo play state");
+}
+
+void Window::thawLingoPlayState() {
+ if (!_lingoPlayState) {
+ warning("Tried to thaw when there's no frozen play state, ignoring");
+ return;
+ }
+ if (!_lingoState->callstack.empty()) {
+ warning("Can't thaw a Lingo state in mid-execution, ignoring");
+ return;
+ }
+ delete _lingoState;
+ debugC(kDebugLingoExec, 3, "Thawing Lingo play state");
+ _lingoState = _lingoPlayState;
+ _lingoPlayState = nullptr;
+}
+
+
// Check how many times enterFrame/stepMovie have been called recursively.
// When Lingo encounters a go() call, it freezes the execution state and starts
// processing the next frame. In the case of enterFrame/stepMovie, it is possible
diff --git a/engines/director/window.h b/engines/director/window.h
index b3e6498c84c..4f8f1fef761 100644
--- a/engines/director/window.h
+++ b/engines/director/window.h
@@ -158,10 +158,13 @@ public:
Common::Path getSharedCastPath();
LingoState *getLingoState() { return _lingoState; };
+ LingoState *getLingoPlayState() { return _lingoPlayState; };
uint32 frozenLingoStateCount() { return _frozenLingoStates.size(); };
uint32 frozenLingoRecursionCount();
void freezeLingoState();
void thawLingoState();
+ void freezeLingoPlayState();
+ void thawLingoPlayState();
LingoState *getLastFrozenLingoState() { return _frozenLingoStates.empty() ? nullptr : _frozenLingoStates[_frozenLingoStates.size() - 1]; }
// events.cpp
@@ -207,6 +210,7 @@ private:
DirectorSound *_soundManager;
LingoState *_lingoState;
Common::Array<LingoState *> _frozenLingoStates;
+ LingoState *_lingoPlayState;
bool _isStage;
Archive *_mainArchive;
Movie *_currentMovie;
Commit: aba127068e34782991ef2f7a252ab995bf5d15ad
https://github.com/scummvm/scummvm/commit/aba127068e34782991ef2f7a252ab995bf5d15ad
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: XOBJ: Add stubs for GenUtils
Changed paths:
A engines/director/lingo/xlibs/genutils.cpp
A engines/director/lingo/xlibs/genutils.h
engines/director/lingo/lingo-object.cpp
engines/director/module.mk
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index 03f4b7b5ac1..fd7a39ce3be 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -67,6 +67,7 @@
#include "director/lingo/xlibs/findwin.h"
#include "director/lingo/xlibs/flushxobj.h"
#include "director/lingo/xlibs/fplayxobj.h"
+#include "director/lingo/xlibs/genutils.h"
#include "director/lingo/xlibs/getscreenrectsxfcn.h"
#include "director/lingo/xlibs/getscreensizexfcn.h"
#include "director/lingo/xlibs/gpid.h"
@@ -233,6 +234,7 @@ static struct XLibProto {
{ FinderEventsXCMD::fileNames, FinderEventsXCMD::open, FinderEventsXCMD::close, kXObj, 400 }, // D4
{ FlushXObj::fileNames, FlushXObj::open, FlushXObj::close, kXObj, 300 }, // D3
{ FPlayXObj::fileNames, FPlayXObj::open, FPlayXObj::close, kXObj, 200 }, // D2
+ { GenUtilsXObj::fileNames, GenUtilsXObj::open, GenUtilsXObj::close, kXObj, 400 }, // D4
{ GetScreenRectsXFCN::fileNames, GetScreenRectsXFCN::open, GetScreenRectsXFCN::close, kXObj, 300 }, // D3
{ GetScreenSizeXFCN::fileNames, GetScreenSizeXFCN::open, GetScreenSizeXFCN::close, kXObj, 300 }, // D3
{ GpidXObj::fileNames, GpidXObj::open, GpidXObj::close, kXObj, 400 }, // D4
diff --git a/engines/director/lingo/xlibs/genutils.cpp b/engines/director/lingo/xlibs/genutils.cpp
new file mode 100644
index 00000000000..189554343bf
--- /dev/null
+++ b/engines/director/lingo/xlibs/genutils.cpp
@@ -0,0 +1,106 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/system.h"
+
+#include "director/director.h"
+#include "director/lingo/lingo.h"
+#include "director/lingo/lingo-object.h"
+#include "director/lingo/lingo-utils.h"
+#include "director/lingo/xlibs/genutils.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * Isis
+ *
+ **************************************************/
+
+/*
+-- GenUtils External Factory. 16Feb93 PTM
+--GenUtils
+I mNew --Creates a new instance of the XObject
+X mDispose --Disposes of XObject instance
+S mName --Returns the XObject name (GenUtils)
+I mStatus --Returns an integer status code
+S mGetWindowsFolder --Retrieves the location of the windows folder
+I mFlushEvents --Clears the event queue.
+III mMoveCursor --Moves the cursor to x,y
+III mClickCursor --Moves the cursor to x,y and clicks it.
+
+ */
+
+namespace Director {
+
+const char *GenUtilsXObj::xlibName = "GenUtils";
+const char *GenUtilsXObj::fileNames[] = {
+ "GENUTILS",
+ nullptr
+};
+
+static MethodProto xlibMethods[] = {
+ { "new", GenUtilsXObj::m_new, 0, 0, 400 },
+ { "dispose", GenUtilsXObj::m_dispose, 0, 0, 400 },
+ { "name", GenUtilsXObj::m_name, 0, 0, 400 },
+ { "status", GenUtilsXObj::m_status, 0, 0, 400 },
+ { "getWindowsFolder", GenUtilsXObj::m_getWindowsFolder, 0, 0, 400 },
+ { "flushEvents", GenUtilsXObj::m_flushEvents, 0, 0, 400 },
+ { "moveCursor", GenUtilsXObj::m_moveCursor, 2, 2, 400 },
+ { "clickCursor", GenUtilsXObj::m_clickCursor, 2, 2, 400 },
+ { nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+ { nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+GenUtilsXObject::GenUtilsXObject(ObjectType ObjectType) :Object<GenUtilsXObject>("GenUtils") {
+ _objType = ObjectType;
+}
+
+void GenUtilsXObj::open(ObjectType type, const Common::Path &path) {
+ GenUtilsXObject::initMethods(xlibMethods);
+ GenUtilsXObject *xobj = new GenUtilsXObject(type);
+ g_lingo->exposeXObject(xlibName, xobj);
+ g_lingo->initBuiltIns(xlibBuiltins);
+}
+
+void GenUtilsXObj::close(ObjectType type) {
+ GenUtilsXObject::cleanupMethods();
+ g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void GenUtilsXObj::m_new(int nargs) {
+ g_lingo->printSTUBWithArglist("GenUtilsXObj::m_new", nargs);
+ g_lingo->dropStack(nargs);
+ g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUBNR(GenUtilsXObj::m_dispose)
+XOBJSTUB(GenUtilsXObj::m_name, "")
+XOBJSTUB(GenUtilsXObj::m_status, 0)
+XOBJSTUB(GenUtilsXObj::m_getWindowsFolder, "")
+XOBJSTUB(GenUtilsXObj::m_flushEvents, 0)
+XOBJSTUB(GenUtilsXObj::m_moveCursor, 0)
+XOBJSTUB(GenUtilsXObj::m_clickCursor, 0)
+
+}
diff --git a/engines/director/lingo/xlibs/genutils.h b/engines/director/lingo/xlibs/genutils.h
new file mode 100644
index 00000000000..14647e949d5
--- /dev/null
+++ b/engines/director/lingo/xlibs/genutils.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DIRECTOR_LINGO_XLIBS_GENUTILS_H
+#define DIRECTOR_LINGO_XLIBS_GENUTILS_H
+
+namespace Director {
+
+class GenUtilsXObject : public Object<GenUtilsXObject> {
+public:
+ GenUtilsXObject(ObjectType objType);
+};
+
+namespace GenUtilsXObj {
+
+extern const char *xlibName;
+extern const char *fileNames[];
+
+void open(ObjectType type, const Common::Path &path);
+void close(ObjectType type);
+
+void m_new(int nargs);
+void m_dispose(int nargs);
+void m_name(int nargs);
+void m_status(int nargs);
+void m_getWindowsFolder(int nargs);
+void m_flushEvents(int nargs);
+void m_moveCursor(int nargs);
+void m_clickCursor(int nargs);
+
+} // End of namespace GenUtilsXObj
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 647ec854420..0d818d28789 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -96,6 +96,7 @@ MODULE_OBJS = \
lingo/xlibs/findwin.o \
lingo/xlibs/flushxobj.o \
lingo/xlibs/fplayxobj.o \
+ lingo/xlibs/genutils.o \
lingo/xlibs/getscreenrectsxfcn.o \
lingo/xlibs/getscreensizexfcn.o \
lingo/xlibs/gpid.o \
Commit: 4d10b88c4b0e0de885f6bb575b2c0b5d03e30ecf
https://github.com/scummvm/scummvm/commit/4d10b88c4b0e0de885f6bb575b2c0b5d03e30ecf
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Fix c_field to work in D5 and up
Changed paths:
engines/director/lingo/lingo-code.cpp
engines/director/lingo/lingo.cpp
engines/director/lingo/lingo.h
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index 27194b2431a..e32ee2339a5 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -1899,8 +1899,11 @@ void LC::c_hilite() {
}
void LC::c_fieldref() {
- Datum d = g_lingo->pop();
- Datum res = d.asMemberID();
+ Datum castLib;
+ if (g_director->getVersion() >= 500)
+ castLib = g_lingo->pop();
+ Datum member = g_lingo->pop();
+ Datum res = member.asMemberID(kCastTypeAny, castLib.asInt());
res.type = FIELDREF;
g_lingo->push(res);
}
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index a082432efed..dbbf69d24fd 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -1256,11 +1256,11 @@ Common::String Datum::asString(bool printonly) const {
return s;
}
-CastMemberID Datum::asMemberID(CastType castType) const {
+CastMemberID Datum::asMemberID(CastType castType, int castLib) const {
if (type == CASTREF || type == FIELDREF)
return *u.cast;
- return g_lingo->resolveCastMember(*this, DEFAULT_CAST_LIB, castType);
+ return g_lingo->resolveCastMember(*this, castLib, castType);
}
Common::Point Datum::asPoint() const {
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index 43d95e97ab5..af63064a29b 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -167,7 +167,7 @@ struct Datum { /* interpreter stack type */
double asFloat() const;
int asInt() const;
Common::String asString(bool printonly = false) const;
- CastMemberID asMemberID(CastType castType = kCastTypeAny) const;
+ CastMemberID asMemberID(CastType castType = kCastTypeAny, int castLib = 0) const;
Common::Point asPoint() const;
bool isRef() const;
Commit: 7a3345771899a4444df18bfef17e18e2547d37d8
https://github.com/scummvm/scummvm/commit/7a3345771899a4444df18bfef17e18e2547d37d8
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Execute ancestor factory methods with the child object
Ancestor object methods can access properties that are only defined
on a child object. Yay inheritance.
Fixes the start sequence of AMBER: Journeys Beyond.
Changed paths:
engines/director/lingo/lingo-code.cpp
engines/director/lingo/lingo-object.cpp
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index e32ee2339a5..a63ab5d7546 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -1571,7 +1571,7 @@ void LC::call(const Common::String &name, int nargs, bool allowRetVal) {
}
funcSym = target->getMethod(name);
if (funcSym.type != VOIDSYM) {
- g_lingo->_stack[g_lingo->_stack.size() - nargs] = funcSym.target; // Set first arg to target
+ g_lingo->_stack[g_lingo->_stack.size() - nargs] = target; // Set first arg to target
call(funcSym, nargs, allowRetVal);
return;
}
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index fd7a39ce3be..a083eda9a0b 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -474,8 +474,9 @@ Symbol ScriptContext::getMethod(const Common::String &methodName) {
if (_properties.contains("ancestor") && _properties["ancestor"].type == OBJECT
&& (_properties["ancestor"].u.obj->getObjType() & (kScriptObj | kXtraObj))) {
// ancestor method
- debugC(3, kDebugLingoExec, "Calling method '%s' on ancestor: <%s>", methodName.c_str(), _properties["ancestor"].asString(true).c_str());
- return _properties["ancestor"].u.obj->getMethod(methodName);
+ sym = _properties["ancestor"].u.obj->getMethod(methodName);
+ if (sym.type != VOIDSYM)
+ debugC(3, kDebugLingoExec, "Calling method '%s' on ancestor: <%s>", methodName.c_str(), _properties["ancestor"].asString(true).c_str());
}
}
Commit: bdc809b0cb739f3d41e8b89f4de75d6c03a2baa5
https://github.com/scummvm/scummvm/commit/bdc809b0cb739f3d41e8b89f4de75d6c03a2baa5
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: LINGO: Add nullptr guardrails for getMenu()
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 8af10295156..18751c27fe7 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -591,6 +591,11 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
d = 32 * 1024 * 1024; // Let's have 32 Mbytes
break;
case kTheMenu:
+ if (!g_director->_wm->getMenu()) {
+ warning("Lingo::getTheEntity(): Menu does not exist!");
+ break;
+ }
+
d.type = STRING;
Graphics::MacMenuItem *menuRef;
menuRef = nullptr;
@@ -604,6 +609,10 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
*d.u.s = g_director->_wm->getMenu()->getName(menuRef);
break;
case kTheMenuItem:
+ if (!g_director->_wm->getMenu()) {
+ warning("Lingo::getTheEntity(): Menu does not exist!");
+ break;
+ }
Graphics::MacMenuItem *menu, *menuItem;
menu = nullptr, menuItem = nullptr;
@@ -1028,7 +1037,7 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
menu = nullptr, menuItem = nullptr;
if (!g_director->_wm->getMenu()) {
- warning("Lingo::setTheEntity() : Menu does not exist!");
+ warning("Lingo::setTheEntity(): Menu does not exist!");
break;
}
@@ -1238,6 +1247,11 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
}
int Lingo::getMenuNum() {
+ if (!g_director->_wm->getMenu()) {
+ warning("Lingo::getMenuNum(): Menu does not exist!");
+ return 0;
+ }
+
return g_director->_wm->getMenu()->numberOfMenus();
}
@@ -1264,7 +1278,7 @@ int Lingo::getMenuItemsNum(Datum &d) {
Graphics::MacMenuItem *menu = nullptr;
if (!g_director->_wm->getMenu()) {
- warning("Lingo::getMenuItemsNum() : Menu does not exist!");
+ warning("Lingo::getMenuItemsNum(): Menu does not exist!");
return 0;
}
Commit: b033c6306849288e9f96df46a58e787e761b7c98
https://github.com/scummvm/scummvm/commit/b033c6306849288e9f96df46a58e787e761b7c98
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: XOBJ: Add full stubs to MovUtils
Changed paths:
engines/director/lingo/xlibs/movutils.cpp
engines/director/lingo/xlibs/movutils.h
diff --git a/engines/director/lingo/xlibs/movutils.cpp b/engines/director/lingo/xlibs/movutils.cpp
index b730198d2a7..65314badb3c 100644
--- a/engines/director/lingo/xlibs/movutils.cpp
+++ b/engines/director/lingo/xlibs/movutils.cpp
@@ -19,148 +19,352 @@
*
*/
-/*************************************
+#include "common/util.h"
+
+#include "director/director.h"
+#include "director/lingo/lingo.h"
+#include "director/lingo/lingo-object.h"
+#include "director/lingo/lingo-utils.h"
+#include "director/lingo/xlibs/movutils.h"
+
+/**************************************************
*
* USED IN:
+ * AMBER: Journeys Beyond
* Gahan Wilson's Ultimate Haunted House
* Momi no Ki no Shita de: The Day of St. Claus
* Virtual Nightclub
*
- *************************************/
+ **************************************************/
/*
- * -- MovieUtilities External Factory, v. 1.0.7 by David Jackson Shields
- * MovUtils
- * I mNew --Create new XObject instance
- * X mDispose --Dispose of XObject instance
- * S mName --Return the XObject name (MovUtils)
- * SS mGetVolName --Return name of disk drive (volume) from path
- * S mGetSystemPath --Return system directory path as a string
- * S mGetWindowsPath --Return Windows directory path as a string
- * IS mSetDefaultPath --Set current drive:irectory path
- * SS mGetChildWindowNames --Return string of all Child window names,
- * -- given a Parent window name
- * IS mGetNamedWindowHdl --Return the ID handle to the named window
- * -- (needed for MCI commands)
- * XSLLII mDrawLine --Draw line in the named window from point A
- * -- to point B, at specified pen width and color
- * ISLI mDrawOval --Draw filled oval (ellipse) in the named window,
- * -- the bounds RECT, using specified fill color
- * ISLI mDrawRect --Draw filled RECT in the named window, within the bounds
- * -- RECT, using specified fill color
- * ISLII mDrawRoundRect --Draw filled rounded RECT in the named window, within bounds
- * -- RECT, with specified curvature and fill color
- * ISLI mDrawPoly --Draw filled polygon in named window from a linear
- * -- list of coordinates, using specified fill color
- * ISLIII mDrawPie --Draw filled arc in named window, within bounds RECT, from
- * -- start angle to arc angle, using specified fill color
- * I mPrintLandscape --Print the Stage in Landscape orientation using dithered grays
- * SS mNoPunct --Remove all punctuation chars from text
- * SS mToUpperCase --Convert text to all upperCase chars
- * SS mToLowerCase --Convert text to all lowerCase chars
- * SS mTrimWhiteChars --Remove leading and trailing 'white space' chars from text
- * SS mDollarFormat --Convert number string to US currency format
- * ISI mGetWordStart --Find number of chars to start of specified word
- * ISI mGetWordEnd --Find number of chars to end of specified word
- * ISI mGetLineStart --Find number of chars to start of specified line
- * ISI mGetLineEnd --Find number of chars to end of specified line
- * IS mIsAlphaNum --Return Boolean whether char is alphaNumeric
- * IS mIsAlpha --Return Boolean whether char is alphabetic
- * IS mIsUpper --Return Boolean whether char is upperCase alphabetic
- * IS mIsLower --Return Boolean whether char is lowerCase alphabetic
- * IS mIsDigit --Return Boolean whether char is a decimal digit
- * IS mIsPunctuation --Return Boolean whether char is punctuation
- * IS mIsWhiteSpace --Return Boolean whether char is a 'white space' char
- * IS mIsPrintable --Return Boolean whether char is printable
- * IS mIsGraphic --Return Boolean whether char is graphic
- * IS mIsControl --Return Boolean whether char is a control char
- * IS mIsHex --Return Boolean whether char is a hexadecimal digit
- * III mBitSet --Set specified bit within a long integer
- * III mBitTest --Test specified bit within a long integer
- * III mBitClear --Clear specified bit within a long integer
- * II mBitShiftL --Shift specified bit left within a long integer
- * II mBitShiftR --Shift specified bit right within a long integer
- * III mBitAnd --Perform logical AND operation of two long integers
- * III mBitOr --Perform logical OR operation of two long integers
- * III mBitXOr --Perform logical XOR operation of two long integers
- * II mBitNot --Perform logical NOT operation on a long integer
- * IS mBitStringToNumber --Translate string of '1's and '0's to a long integer
- * PL mStageToCast --Returns a picture handle to the image in the Rect on Stage
- * ISL mStageToDIB --Save, to a named bitmap file, the image in the Rect on Stage
- * ISL mStageToPICT --Save, to a Mac PICT file, the image in the Rect on Stage
- * SS mCRtoCRLF --Add a LineFeed to each Return char within Macintosh text
- * SS mCRLFtoCR --Remove LineFeed from each end of line within Windows text
- * III mGetMessage --Get mouse/key messages from the application message queue
+-- MovieUtilities External Factory, v. 1.0.7 by David Jackson Shields
+--MovUtils
+I mNew --Create new XObject instance
+X mDispose --Dispose of XObject instance
+S mName --Return the XObject name (MovUtils)
+SS mGetVolName --Return name of disk drive (volume) from path
+S mGetSystemPath --Return system directory path as a string
+S mGetWindowsPath --Return Windows directory path as a string
+IS mSetDefaultPath --Set current drive:irectory path
+SS mGetChildWindowNames --Return string of all Child window names,
+-- given a Parent window name
+IS mGetNamedWindowHdl --Return the ID handle to the named window
+-- (needed for MCI commands)
+XSLLII mDrawLine --Draw line in the named window from point A
+-- to point B, at specified pen width and color
+ISLI mDrawOval --Draw filled oval (ellipse) in the named window,
+-- the bounds RECT, using specified fill color
+ISLI mDrawRect --Draw filled RECT in the named window, within the bounds
+-- RECT, using specified fill color
+ISLII mDrawRoundRect --Draw filled rounded RECT in the named window, within bounds
+-- RECT, with specified curvature and fill color
+ISLI mDrawPoly --Draw filled polygon in named window from a linear
+-- list of coordinates, using specified fill color
+ISLIII mDrawPie --Draw filled arc in named window, within bounds RECT, from
+-- start angle to arc angle, using specified fill color
+I mPrintLandscape --Print the Stage in Landscape orientation using dithered grays
+SS mNoPunct --Remove all punctuation chars from text
+SS mToUpperCase --Convert text to all upperCase chars
+SS mToLowerCase --Convert text to all lowerCase chars
+SS mTrimWhiteChars --Remove leading and trailing 'white space' chars from text
+SS mDollarFormat --Convert number string to US currency format
+ISI mGetWordStart --Find number of chars to start of specified word
+ISI mGetWordEnd --Find number of chars to end of specified word
+ISI mGetLineStart --Find number of chars to start of specified line
+ISI mGetLineEnd --Find number of chars to end of specified line
+IS mIsAlphaNum --Return Boolean whether char is alphaNumeric
+IS mIsAlpha --Return Boolean whether char is alphabetic
+IS mIsUpper --Return Boolean whether char is upperCase alphabetic
+IS mIsLower --Return Boolean whether char is lowerCase alphabetic
+IS mIsDigit --Return Boolean whether char is a decimal digit
+IS mIsPunctuation --Return Boolean whether char is punctuation
+IS mIsWhiteSpace --Return Boolean whether char is a 'white space' char
+IS mIsPrintable --Return Boolean whether char is printable
+IS mIsGraphic --Return Boolean whether char is graphic
+IS mIsControl --Return Boolean whether char is a control char
+IS mIsHex --Return Boolean whether char is a hexadecimal digit
+III mBitSet --Set specified bit within a long integer
+III mBitTest --Test specified bit within a long integer
+III mBitClear --Clear specified bit within a long integer
+II mBitShiftL --Shift specified bit left within a long integer
+II mBitShiftR --Shift specified bit right within a long integer
+III mBitAnd --Perform logical AND operation of two long integers
+III mBitOr --Perform logical OR operation of two long integers
+III mBitXOr --Perform logical XOR operation of two long integers
+II mBitNot --Perform logical NOT operation on a long integer
+IS mBitStringToNumber --Translate string of '1's and '0's to a long integer
+PL mStageToCast --Returns a picture handle to the image in the Rect on Stage
+ISL mStageToDIB --Save, to a named bitmap file, the image in the Rect on Stage
+ISL mStageToPICT --Save, to a Mac PICT file, the image in the Rect on Stage
+SS mCRtoCRLF --Add a LineFeed to each Return char within Macintosh text
+SS mCRLFtoCR --Remove LineFeed from each end of line within Windows text
+III mGetMessage --Get mouse/key messages from the application message queue
*/
-#include "director/director.h"
-#include "director/lingo/lingo.h"
-#include "director/lingo/lingo-object.h"
-#include "director/lingo/xlibs/movutils.h"
-
-
namespace Director {
-const char *MovUtilsXObj::xlibNames[] = {
- "movutils",
- "MovieUtilities",
- nullptr
-};
-
+const char *MovUtilsXObj::xlibName = "MovUtils";
const char *MovUtilsXObj::fileNames[] = {
"MOVUTILS",
- "MovieUtilities",
- "MovieUtilities.XObj",
nullptr
};
static MethodProto xlibMethods[] = {
- { "new", MovUtilsXObj::m_new, 0, 0, 400 }, // D4
- { "GetWindowsPath", MovUtilsXObj::m_getWindowsPath, 0, 0, 400 }, // D4
- { "getSystemPath", MovUtilsXObj::m_getSystemPath, 0, 0, 400 }, // D4
+ { "new", MovUtilsXObj::m_new, 0, 0, 400 },
+ { "dispose", MovUtilsXObj::m_dispose, 0, 0, 400 },
+ { "name", MovUtilsXObj::m_name, 0, 0, 400 },
+ { "getVolName", MovUtilsXObj::m_getVolName, 1, 1, 400 },
+ { "getSystemPath", MovUtilsXObj::m_getSystemPath, 0, 0, 400 },
+ { "getWindowsPath", MovUtilsXObj::m_getWindowsPath, 0, 0, 400 },
+ { "setDefaultPath", MovUtilsXObj::m_setDefaultPath, 1, 1, 400 },
+ { "getChildWindowNames", MovUtilsXObj::m_getChildWindowNames, 1, 1, 400 },
+ { "getNamedWindowHdl", MovUtilsXObj::m_getNamedWindowHdl, 1, 1, 400 },
+ { "drawLine", MovUtilsXObj::m_drawLine, 5, 5, 400 },
+ { "drawOval", MovUtilsXObj::m_drawOval, 3, 3, 400 },
+ { "drawRect", MovUtilsXObj::m_drawRect, 3, 3, 400 },
+ { "drawRoundRect", MovUtilsXObj::m_drawRoundRect, 4, 4, 400 },
+ { "drawPoly", MovUtilsXObj::m_drawPoly, 3, 3, 400 },
+ { "drawPie", MovUtilsXObj::m_drawPie, 5, 5, 400 },
+ { "printLandscape", MovUtilsXObj::m_printLandscape, 0, 0, 400 },
+ { "noPunct", MovUtilsXObj::m_noPunct, 1, 1, 400 },
+ { "toUpperCase", MovUtilsXObj::m_toUpperCase, 1, 1, 400 },
+ { "toLowerCase", MovUtilsXObj::m_toLowerCase, 1, 1, 400 },
+ { "trimWhiteChars", MovUtilsXObj::m_trimWhiteChars, 1, 1, 400 },
+ { "dollarFormat", MovUtilsXObj::m_dollarFormat, 1, 1, 400 },
+ { "getWordStart", MovUtilsXObj::m_getWordStart, 2, 2, 400 },
+ { "getWordEnd", MovUtilsXObj::m_getWordEnd, 2, 2, 400 },
+ { "getLineStart", MovUtilsXObj::m_getLineStart, 2, 2, 400 },
+ { "getLineEnd", MovUtilsXObj::m_getLineEnd, 2, 2, 400 },
+ { "isAlphaNum", MovUtilsXObj::m_isAlphaNum, 1, 1, 400 },
+ { "isAlpha", MovUtilsXObj::m_isAlpha, 1, 1, 400 },
+ { "isUpper", MovUtilsXObj::m_isUpper, 1, 1, 400 },
+ { "isLower", MovUtilsXObj::m_isLower, 1, 1, 400 },
+ { "isDigit", MovUtilsXObj::m_isDigit, 1, 1, 400 },
+ { "isPunctuation", MovUtilsXObj::m_isPunctuation, 1, 1, 400 },
+ { "isWhiteSpace", MovUtilsXObj::m_isWhiteSpace, 1, 1, 400 },
+ { "isPrintable", MovUtilsXObj::m_isPrintable, 1, 1, 400 },
+ { "isGraphic", MovUtilsXObj::m_isGraphic, 1, 1, 400 },
+ { "isControl", MovUtilsXObj::m_isControl, 1, 1, 400 },
+ { "isHex", MovUtilsXObj::m_isHex, 1, 1, 400 },
+ { "bitSet", MovUtilsXObj::m_bitSet, 2, 2, 400 },
+ { "bitTest", MovUtilsXObj::m_bitTest, 2, 2, 400 },
+ { "bitClear", MovUtilsXObj::m_bitClear, 2, 2, 400 },
+ { "bitShiftL", MovUtilsXObj::m_bitShiftL, 1, 1, 400 },
+ { "bitShiftR", MovUtilsXObj::m_bitShiftR, 1, 1, 400 },
+ { "bitAnd", MovUtilsXObj::m_bitAnd, 2, 2, 400 },
+ { "bitOr", MovUtilsXObj::m_bitOr, 2, 2, 400 },
+ { "bitXOr", MovUtilsXObj::m_bitXOr, 2, 2, 400 },
+ { "bitNot", MovUtilsXObj::m_bitNot, 1, 1, 400 },
+ { "bitStringToNumber", MovUtilsXObj::m_bitStringToNumber, 1, 1, 400 },
+ { "stageToCast", MovUtilsXObj::m_stageToCast, 1, 1, 400 },
+ { "stageToDIB", MovUtilsXObj::m_stageToDIB, 2, 2, 400 },
+ { "stageToPICT", MovUtilsXObj::m_stageToPICT, 2, 2, 400 },
+ { "cRtoCRLF", MovUtilsXObj::m_cRtoCRLF, 1, 1, 400 },
+ { "cRLFtoCR", MovUtilsXObj::m_cRLFtoCR, 1, 1, 400 },
+ { "getMessage", MovUtilsXObj::m_getMessage, 2, 2, 400 },
{ nullptr, nullptr, 0, 0, 0 }
};
+static BuiltinProto xlibBuiltins[] = {
+ { nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+MovUtilsXObject::MovUtilsXObject(ObjectType ObjectType) :Object<MovUtilsXObject>("MovUtils") {
+ _objType = ObjectType;
+}
+
void MovUtilsXObj::open(ObjectType type, const Common::Path &path) {
- if (type == kXObj) {
- MovieUtilsXObject::initMethods(xlibMethods);
- MovieUtilsXObject *xobj = new MovieUtilsXObject(kXObj);
- for (uint i = 0; xlibNames[i]; i++) {
- g_lingo->exposeXObject(xlibNames[i], xobj);
- }
- }
+ MovUtilsXObject::initMethods(xlibMethods);
+ MovUtilsXObject *xobj = new MovUtilsXObject(type);
+ g_lingo->exposeXObject(xlibName, xobj);
+ g_lingo->initBuiltIns(xlibBuiltins);
}
void MovUtilsXObj::close(ObjectType type) {
- if (type == kXObj) {
- MovieUtilsXObject::cleanupMethods();
- for (uint i = 0; xlibNames[i]; i++) {
- g_lingo->_globalvars[xlibNames[i]] = Datum();
- }
- }
-}
+ MovUtilsXObject::cleanupMethods();
+ g_lingo->_globalvars[xlibName] = Datum();
-MovieUtilsXObject::MovieUtilsXObject(ObjectType ObjectType) :Object<MovieUtilsXObject>("MovUtils") {
- _objType = ObjectType;
}
void MovUtilsXObj::m_new(int nargs) {
- g_lingo->printSTUBWithArglist("MovUtilsXObj::new", nargs);
+ g_lingo->printSTUBWithArglist("MovUtilsXObj::m_new", nargs);
+ g_lingo->dropStack(nargs);
g_lingo->push(g_lingo->_state->me);
}
-void MovUtilsXObj::m_getSystemPath(int nargs) {
- g_lingo->dropStack(nargs);
- // An empty string ensures this just maps to the root of
- // ScummVM's save data path.
- g_lingo->push(Datum(""));
+XOBJSTUBNR(MovUtilsXObj::m_dispose)
+XOBJSTUB(MovUtilsXObj::m_name, "")
+XOBJSTUB(MovUtilsXObj::m_getVolName, "")
+XOBJSTUB(MovUtilsXObj::m_getSystemPath, "")
+XOBJSTUB(MovUtilsXObj::m_getWindowsPath, "")
+XOBJSTUB(MovUtilsXObj::m_setDefaultPath, 0)
+XOBJSTUB(MovUtilsXObj::m_getChildWindowNames, "")
+XOBJSTUB(MovUtilsXObj::m_getNamedWindowHdl, 0)
+XOBJSTUBNR(MovUtilsXObj::m_drawLine)
+XOBJSTUB(MovUtilsXObj::m_drawOval, 0)
+XOBJSTUB(MovUtilsXObj::m_drawRect, 0)
+XOBJSTUB(MovUtilsXObj::m_drawRoundRect, 0)
+XOBJSTUB(MovUtilsXObj::m_drawPoly, 0)
+XOBJSTUB(MovUtilsXObj::m_drawPie, 0)
+XOBJSTUB(MovUtilsXObj::m_printLandscape, 0)
+XOBJSTUB(MovUtilsXObj::m_noPunct, "")
+XOBJSTUB(MovUtilsXObj::m_toUpperCase, "")
+XOBJSTUB(MovUtilsXObj::m_toLowerCase, "")
+XOBJSTUB(MovUtilsXObj::m_trimWhiteChars, "")
+XOBJSTUB(MovUtilsXObj::m_dollarFormat, "")
+XOBJSTUB(MovUtilsXObj::m_getWordStart, 0)
+XOBJSTUB(MovUtilsXObj::m_getWordEnd, 0)
+XOBJSTUB(MovUtilsXObj::m_getLineStart, 0)
+XOBJSTUB(MovUtilsXObj::m_getLineEnd, 0)
+
+void MovUtilsXObj::m_isAlphaNum(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isAlphaNum(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isAlnum(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
}
-void MovUtilsXObj::m_getWindowsPath(int nargs) {
- g_lingo->dropStack(nargs);
- // An empty string ensures this just maps to the root of
- // ScummVM's save data path.
- g_lingo->push(Datum(""));
+void MovUtilsXObj::m_isAlpha(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isAlpha(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isAlpha(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
}
-} // End of namespace Director
+void MovUtilsXObj::m_isUpper(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isUpper(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isUpper(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+void MovUtilsXObj::m_isLower(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isLower(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isLower(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+void MovUtilsXObj::m_isDigit(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isDigit(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isDigit(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+void MovUtilsXObj::m_isPunctuation(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isPunctuation(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isPunct(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+void MovUtilsXObj::m_isWhiteSpace(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isWhiteSpace(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isSpace(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+void MovUtilsXObj::m_isPrintable(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isPrintable(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isPrint(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+void MovUtilsXObj::m_isGraphic(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isGraphic(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isGraph(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+void MovUtilsXObj::m_isControl(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isControl(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isCntrl(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+void MovUtilsXObj::m_isHex(int nargs) {
+ Datum result(0);
+ if (nargs != 1) {
+ warning("MovUtilsXObj::m_isHex(): expected 1 arg");
+ g_lingo->dropStack(nargs);
+ } else {
+ char test = g_lingo->pop().asString().firstChar();
+ result = Datum(Common::isXDigit(test) ? 1 : 0);
+ }
+ g_lingo->push(result);
+}
+
+XOBJSTUB(MovUtilsXObj::m_bitSet, 0)
+XOBJSTUB(MovUtilsXObj::m_bitTest, 0)
+XOBJSTUB(MovUtilsXObj::m_bitClear, 0)
+XOBJSTUB(MovUtilsXObj::m_bitShiftL, 0)
+XOBJSTUB(MovUtilsXObj::m_bitShiftR, 0)
+XOBJSTUB(MovUtilsXObj::m_bitAnd, 0)
+XOBJSTUB(MovUtilsXObj::m_bitOr, 0)
+XOBJSTUB(MovUtilsXObj::m_bitXOr, 0)
+XOBJSTUB(MovUtilsXObj::m_bitNot, 0)
+XOBJSTUB(MovUtilsXObj::m_bitStringToNumber, 0)
+XOBJSTUB(MovUtilsXObj::m_stageToCast, 0)
+XOBJSTUB(MovUtilsXObj::m_stageToDIB, 0)
+XOBJSTUB(MovUtilsXObj::m_stageToPICT, 0)
+XOBJSTUB(MovUtilsXObj::m_cRtoCRLF, "")
+XOBJSTUB(MovUtilsXObj::m_cRLFtoCR, "")
+XOBJSTUB(MovUtilsXObj::m_getMessage, 0)
+
+}
diff --git a/engines/director/lingo/xlibs/movutils.h b/engines/director/lingo/xlibs/movutils.h
index 0f73247c289..fdc1a86964d 100644
--- a/engines/director/lingo/xlibs/movutils.h
+++ b/engines/director/lingo/xlibs/movutils.h
@@ -1,47 +1,94 @@
/* ScummVM - Graphic Adventure Engine
-*
-* ScummVM is the legal property of its developers, whose names
-* are too numerous to list here. Please refer to the COPYRIGHT
-* file distributed with this source distribution.
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, either version 3 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <http://www.gnu.org/licenses/>.
-*
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
-
#ifndef DIRECTOR_LINGO_XLIBS_MOVUTILS_H
#define DIRECTOR_LINGO_XLIBS_MOVUTILS_H
namespace Director {
-class MovieUtilsXObject : public Object<MovieUtilsXObject> {
+class MovUtilsXObject : public Object<MovUtilsXObject> {
public:
- MovieUtilsXObject(ObjectType objType);
+ MovUtilsXObject(ObjectType objType);
};
namespace MovUtilsXObj {
-extern const char *xlibNames[];
+extern const char *xlibName;
extern const char *fileNames[];
void open(ObjectType type, const Common::Path &path);
void close(ObjectType type);
void m_new(int nargs);
-void m_clear(int nargs);
+void m_dispose(int nargs);
+void m_name(int nargs);
+void m_getVolName(int nargs);
void m_getSystemPath(int nargs);
void m_getWindowsPath(int nargs);
+void m_setDefaultPath(int nargs);
+void m_getChildWindowNames(int nargs);
+void m_getNamedWindowHdl(int nargs);
+void m_drawLine(int nargs);
+void m_drawOval(int nargs);
+void m_drawRect(int nargs);
+void m_drawRoundRect(int nargs);
+void m_drawPoly(int nargs);
+void m_drawPie(int nargs);
+void m_printLandscape(int nargs);
+void m_noPunct(int nargs);
+void m_toUpperCase(int nargs);
+void m_toLowerCase(int nargs);
+void m_trimWhiteChars(int nargs);
+void m_dollarFormat(int nargs);
+void m_getWordStart(int nargs);
+void m_getWordEnd(int nargs);
+void m_getLineStart(int nargs);
+void m_getLineEnd(int nargs);
+void m_isAlphaNum(int nargs);
+void m_isAlpha(int nargs);
+void m_isUpper(int nargs);
+void m_isLower(int nargs);
+void m_isDigit(int nargs);
+void m_isPunctuation(int nargs);
+void m_isWhiteSpace(int nargs);
+void m_isPrintable(int nargs);
+void m_isGraphic(int nargs);
+void m_isControl(int nargs);
+void m_isHex(int nargs);
+void m_bitSet(int nargs);
+void m_bitTest(int nargs);
+void m_bitClear(int nargs);
+void m_bitShiftL(int nargs);
+void m_bitShiftR(int nargs);
+void m_bitAnd(int nargs);
+void m_bitOr(int nargs);
+void m_bitXOr(int nargs);
+void m_bitNot(int nargs);
+void m_bitStringToNumber(int nargs);
+void m_stageToCast(int nargs);
+void m_stageToDIB(int nargs);
+void m_stageToPICT(int nargs);
+void m_cRtoCRLF(int nargs);
+void m_cRLFtoCR(int nargs);
+void m_getMessage(int nargs);
} // End of namespace MovUtilsXObj
Commit: 83e1d42ffa47bb862eca7f4eda0cf6a8cb9b77d6
https://github.com/scummvm/scummvm/commit/83e1d42ffa47bb862eca7f4eda0cf6a8cb9b77d6
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Fix Window::invertChannel in 32-bit mode
Changed paths:
engines/director/window.cpp
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 88a92cbba20..b96e2633372 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -116,7 +116,7 @@ void Window::invertChannel(Channel *channel, const Common::Rect &destRect) {
for (int i = 0; i < srcRect.height(); i++) {
uint32 *src = (uint32 *)_composeSurface->getBasePtr(srcRect.left, srcRect.top + i);
- const uint32 *msk = mask ? (const uint32 *)mask->getBasePtr(xoff, yoff + i) : nullptr;
+ const byte *msk = mask ? (const byte *)mask->getBasePtr(xoff, yoff + i) : nullptr;
for (int j = 0; j < srcRect.width(); j++, src++)
if (!mask || (msk && (*msk++)))
Commit: 39d31fd431642c2d2ad9d1e4d10dbd6587c203b9
https://github.com/scummvm/scummvm/commit/39d31fd431642c2d2ad9d1e4d10dbd6587c203b9
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Fix dissolve transitions for 32-bit mode
Changed paths:
engines/director/transitions.cpp
diff --git a/engines/director/transitions.cpp b/engines/director/transitions.cpp
index ab3e0ae74de..230cb049345 100644
--- a/engines/director/transitions.cpp
+++ b/engines/director/transitions.cpp
@@ -744,10 +744,18 @@ void Window::dissolveTrans(TransParams &t, Common::Rect &clipRect, Graphics::Man
x += clipRect.left;
y += clipRect.top;
- byte *dst = (byte *)_composeSurface->getBasePtr(x, y);
- byte *src = (byte *)nextFrame->getBasePtr(x, y);
+ if (g_director->_pixelformat.bytesPerPixel == 1) {
+ byte *dst = (byte *)_composeSurface->getBasePtr(x, y);
+ byte *src = (byte *)nextFrame->getBasePtr(x, y);
- *dst = ((*dst & ~mask) | (*src & mask)) & 0xff;
+ *dst = ((*dst & ~mask) | (*src & mask)) & 0xff;
+ } else {
+ uint32 *dst = (uint32 *)_composeSurface->getBasePtr(x, y);
+ uint32 *src = (uint32 *)nextFrame->getBasePtr(x, y);
+
+ *dst = ((*dst & ~mask) | (*src & mask)) & 0xff;
+
+ }
}
}
@@ -850,18 +858,36 @@ void Window::dissolvePatternsTrans(TransParams &t, Common::Rect &clipRect, Graph
uint32 startTime = g_system->getMillis();
for (int y = clipRect.top; y < clipRect.bottom; y++) {
byte pat = dissolvePatterns[patternIndex][y % 8];
- byte *dst = (byte *)_composeSurface->getBasePtr(clipRect.left, y);
- byte *src = (byte *)nextFrame->getBasePtr(clipRect.left, y);
-
- for (int x = clipRect.left; x < clipRect.right;) {
- byte mask = 0x80;
- for (int b = 0; b < 8 && x < clipRect.right; b++, x++) {
- if (pat & mask)
- *dst = *src;
-
- dst++;
- src++;
- mask >>= 1;
+ if (g_director->_pixelformat.bytesPerPixel == 1) {
+
+ byte *dst = (byte *)_composeSurface->getBasePtr(clipRect.left, y);
+ byte *src = (byte *)nextFrame->getBasePtr(clipRect.left, y);
+
+ for (int x = clipRect.left; x < clipRect.right;) {
+ byte mask = 0x80;
+ for (int b = 0; b < 8 && x < clipRect.right; b++, x++) {
+ if (pat & mask)
+ *dst = *src;
+
+ dst++;
+ src++;
+ mask >>= 1;
+ }
+ }
+ } else {
+ uint32 *dst = (uint32 *)_composeSurface->getBasePtr(clipRect.left, y);
+ uint32 *src = (uint32 *)nextFrame->getBasePtr(clipRect.left, y);
+
+ for (int x = clipRect.left; x < clipRect.right;) {
+ byte mask = 0x80;
+ for (int b = 0; b < 8 && x < clipRect.right; b++, x++) {
+ if (pat & mask)
+ *dst = *src;
+
+ dst++;
+ src++;
+ mask >>= 1;
+ }
}
}
}
Commit: 12918d9fbd8d2784aac806a2cb5bb79be8a216a7
https://github.com/scummvm/scummvm/commit/12918d9fbd8d2784aac806a2cb5bb79be8a216a7
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Fix redithering 8-bit images in 32-bit mode
Fixes the palette on the credits screen in The Dark Eye.
Fixes the palette in AMBER: Journeys Beyond.
Changed paths:
engines/director/castmember/bitmap.cpp
diff --git a/engines/director/castmember/bitmap.cpp b/engines/director/castmember/bitmap.cpp
index 8b4b1894272..5045ac5bc8c 100644
--- a/engines/director/castmember/bitmap.cpp
+++ b/engines/director/castmember/bitmap.cpp
@@ -315,6 +315,8 @@ Graphics::Surface *BitmapCastMember::getDitherImg() {
Movie *movie = g_director->getCurrentMovie();
Cast *cast = movie->getCast();
Score *score = movie->getScore();
+ int targetBpp = g_director->_wm->_pixelformat.bytesPerPixel;
+
// Get the current score palette. Note that this is the ID of the palette in the list, not the cast member!
CastMemberID currentPaletteId = score->getCurrentPalette();
if (currentPaletteId.isNull())
@@ -333,6 +335,9 @@ Graphics::Surface *BitmapCastMember::getDitherImg() {
// Check if the palette is in the middle of a color fade event
bool isColorCycling = score->isPaletteColorCycling();
+ byte *dstPalette = targetBpp == 1 ? currentPalette->palette : nullptr;
+ int dstPaletteCount = targetBpp == 1 ? currentPalette->length : 0;
+
// First, check if the palettes are different
switch (_bitsPerPixel) {
// 1bpp - this is preconverted to 0x00 and 0xff, change nothing.
@@ -342,7 +347,7 @@ Graphics::Surface *BitmapCastMember::getDitherImg() {
case 2:
{
const PaletteV4 &srcPal = g_director->getLoaded4Palette();
- dither = _picture->_surface.convertTo(g_director->_wm->_pixelformat, srcPal.palette, srcPal.length, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
+ dither = _picture->_surface.convertTo(g_director->_wm->_pixelformat, srcPal.palette, srcPal.length, dstPalette, dstPaletteCount, Graphics::kDitherNaive);
}
break;
// 4bpp - if using a builtin palette, use one of the corresponding 4-bit ones.
@@ -353,13 +358,19 @@ Graphics::Surface *BitmapCastMember::getDitherImg() {
// I guess default to the mac palette?
CastMemberID palIndex = pals.contains(castPaletteId) ? castPaletteId : CastMemberID(kClutSystemMac, -1);
const PaletteV4 &srcPal = pals.getVal(palIndex);
- dither = _picture->_surface.convertTo(g_director->_wm->_pixelformat, srcPal.palette, srcPal.length, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
+ dither = _picture->_surface.convertTo(g_director->_wm->_pixelformat, srcPal.palette, srcPal.length, dstPalette, dstPaletteCount, Graphics::kDitherNaive);
}
break;
// 8bpp - if using a different palette, and we're not doing a color cycling operation, convert using nearest colour matching
case 8:
- // Only redither 8-bit images if we have the flag set, or it is external
- if (!movie->_remapPalettesWhenNeeded && !_external)
+ // "break" means falling back to the default of rendering the image with
+ // the current 8-bit palette. The below is only about -redithering colours-;
+ // i.e. redrawing the picture to use the current palette.
+ // Only redither 8-bit images in 8-bit mode if we have the remap palette flag set, or it is external
+ if (targetBpp == 1 && !movie->_remapPalettesWhenNeeded && !_external)
+ break;
+ // If we're in 32-bit mode, and not in puppet palette mode, then "redither" as well.
+ if (targetBpp == 4 && score->_puppetPalette && !_external)
break;
if (_external || (castPaletteId != currentPaletteId && !isColorCycling)) {
const auto pals = g_director->getLoadedPalettes();
@@ -371,7 +382,7 @@ Graphics::Surface *BitmapCastMember::getDitherImg() {
// but in the wrong palette order.
const byte *palPtr = _external ? _picture->_palette : srcPal.palette;
int palLength = _external ? _picture->getPaletteSize() : srcPal.length;
- dither = _picture->_surface.convertTo(g_director->_wm->_pixelformat, palPtr, palLength, currentPalette->palette, currentPalette->length, Graphics::kDitherNaive);
+ dither = _picture->_surface.convertTo(g_director->_wm->_pixelformat, palPtr, palLength, dstPalette, dstPaletteCount, Graphics::kDitherNaive);
}
break;
default:
@@ -382,7 +393,7 @@ Graphics::Surface *BitmapCastMember::getDitherImg() {
// Save the palette ID so we can check if a redraw is required
_ditheredTargetClut = currentPaletteId;
- if (!_external) {
+ if (!_external && targetBpp == 1) {
// Finally, the first and last colours in the palette are special. No matter what the palette remap
// does, we need to scrub those to be the same.
const Graphics::Surface *src = &_picture->_surface;
Commit: 215e5ed29adb5d9b965e265774790e4a750a31bd
https://github.com/scummvm/scummvm/commit/215e5ed29adb5d9b965e265774790e4a750a31bd
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Fix crash when suspending on a "play" call
Fixes interacting with Neow-Neow in the cave in Nikolai's Trains.
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 1547f82d18f..1e36ac4956d 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -520,7 +520,9 @@ void Lingo::processEvents(Common::Queue<LingoEvent> &queue, bool isInputEvent) {
if (isInputEvent && !completed) {
debugC(5, kDebugEvents, "Lingo::processEvents: context frozen on an input event, stopping");
LingoState *state = g_director->getCurrentWindow()->getLastFrozenLingoState();
- _currentInputEvent = state->callstack.front()->sp;
+ if (state) {
+ _currentInputEvent = state->callstack.front()->sp;
+ }
break;
}
lastEventId = el.eventId;
Commit: 094f207fac17bfc08a86471e00f7df653bc83547
https://github.com/scummvm/scummvm/commit/094f207fac17bfc08a86471e00f7df653bc83547
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Fix playing video immediately after assigning to sprite
Fixes opening the PeeK in AMBER: Journeys Beyond.
Changed paths:
engines/director/castmember/digitalvideo.cpp
diff --git a/engines/director/castmember/digitalvideo.cpp b/engines/director/castmember/digitalvideo.cpp
index c1f2cd95701..8f1de79bb76 100644
--- a/engines/director/castmember/digitalvideo.cpp
+++ b/engines/director/castmember/digitalvideo.cpp
@@ -368,8 +368,14 @@ void DigitalVideoCastMember::setMovieRate(double rate) {
if (rate < 0.0)
warning("STUB: DigitalVideoCastMember::setMovieRate(%g)", rate);
- else
+ else {
+ if (_getFirstFrame && rate != 0.0) {
+ // playback got started before we rendered the first
+ // frame in pause mode, keep going
+ _getFirstFrame = false;
+ }
_video->setRate(Common::Rational((int)(rate * 100.0), 100));
+ }
if (_video->endOfVideo())
_video->rewind();
Commit: 33c576982b3ddda2f9b3aaba52e51e32b13c2855
https://github.com/scummvm/scummvm/commit/33c576982b3ddda2f9b3aaba52e51e32b13c2855
Author: Scott Percival (code at moral.net.au)
Date: 2024-06-15T02:04:30+02:00
Commit Message:
DIRECTOR: Fix b_installMenu for D5
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 2952adfc7e6..5b9c62a9ad0 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -2288,6 +2288,7 @@ void LB::b_installMenu(int nargs) {
CastMemberID memberID = d.asMemberID(kCastText);
if (memberID.member == 0) {
+ debugC(3, kDebugLoading, "LB::b_installMenu(): removing menu");
g_director->_wm->removeMenu();
return;
}
@@ -2315,15 +2316,22 @@ void LB::b_installMenu(int nargs) {
menu->setCommandsCallback(menuCommandsCallback, g_director);
- debugC(3, kDebugLingoExec, "installMenu: '%s'", Common::toPrintable(menuStxt).c_str());
+ debugC(3, kDebugLoading, "LB::b_installMenu(): installing menu - '%s'", Common::toPrintable(menuStxt).c_str());
LingoArchive *mainArchive = movie->getMainLingoArch();
// STXT sections use Mac-style carriage returns for line breaks.
const char LINE_BREAK_CHAR = '\x0D';
// Menu definitions use the character 0xc5 to denote a code separator.
- // For Mac, this is â. For Windows, this is Ã
.
- const char CODE_SEPARATOR_CHAR = '\xC5';
+ // For Mac D4 and below, this is â. For Windows D4 and below, this is Ã
.
+ char CODE_SEPARATOR_CHAR = '\xC5';
+ char CODE_SEPARATOR_CHAR_2 = '\xC5';
+ if (g_director->getVersion() >= 500) {
+ // D5 changed this to be the pipe | character, the same in Windows and Mac.
+ CODE_SEPARATOR_CHAR = '\x7C';
+ // FIXME: For some reason there are games which use º (Mac) or ¼ (Win) and it works too?
+ CODE_SEPARATOR_CHAR_2 = '\xBC';
+ }
// Continuation character is 0xac to denote a line running over.
// For Mac, this is ¨. For Windows, this is ¬.
const char CONTINUATION_CHAR = '\xAC';
@@ -2385,6 +2393,8 @@ void LB::b_installMenu(int nargs) {
// Split the line at the code separator
size_t sepOffset = line.find(CODE_SEPARATOR_CHAR);
+ if (sepOffset == Common::String::npos)
+ sepOffset = line.find(CODE_SEPARATOR_CHAR_2);
Common::String text;
More information about the Scummvm-git-logs
mailing list