[Scummvm-git-logs] scummvm master -> 0658576196e2c767268eb77e2ee1f14c03b3762a
npjg
noreply at scummvm.org
Tue Mar 25 23:35:34 UTC 2025
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
84517ad6cb MEDIASTATION: Implement collection script methods
97ea2d6504 MEDIASTATION: Stub Unk1 document method
ca95c3596c MEDIASTATION: Don't release contexts too early
d6a62221a6 MEDIASTATION: Permit scripts to coerce some types
61859559cd MEDIASTATION: Allow movies to move under script control
0658576196 MEDIASTATION: Make path playback non-blocking
Commit: 84517ad6cbbcf819cf5dca1f563a796c5fcff680
https://github.com/scummvm/scummvm/commit/84517ad6cbbcf819cf5dca1f563a796c5fcff680
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-25T18:21:36-04:00
Commit Message:
MEDIASTATION: Implement collection script methods
Changed paths:
engines/mediastation/mediascript/codechunk.cpp
engines/mediastation/mediascript/codechunk.h
engines/mediastation/mediascript/operand.cpp
engines/mediastation/mediascript/operand.h
engines/mediastation/mediascript/variable.cpp
engines/mediastation/mediascript/variable.h
engines/mediastation/mediastation.h
diff --git a/engines/mediastation/mediascript/codechunk.cpp b/engines/mediastation/mediascript/codechunk.cpp
index 159bbadd095..810aa3f8c38 100644
--- a/engines/mediastation/mediascript/codechunk.cpp
+++ b/engines/mediastation/mediascript/codechunk.cpp
@@ -19,14 +19,13 @@
*
*/
+#include "common/ptr.h"
+
#include "mediastation/mediastation.h"
#include "mediastation/mediascript/codechunk.h"
#include "mediastation/datum.h"
#include "mediastation/debugchannels.h"
-#include "mediastation/assets/movie.h"
-#include "mediastation/assets/path.h"
-
namespace MediaStation {
CodeChunk::CodeChunk(Common::SeekableReadStream &chunk) {
@@ -362,10 +361,17 @@ Operand CodeChunk::executeNextStatement() {
return operand;
}
+ case kOperandTypeMethod: {
+ BuiltInMethod methodId = static_cast<BuiltInMethod>(Datum(*_bytecode).u.i);
+ debugC(5, kDebugScript, "%s ", builtInMethodToStr(methodId));
+ operand.putMethodId(methodId);
+ return operand;
+ }
+
case kOperandTypeFunction: {
uint functionId = Datum(*_bytecode).u.i;
debugC(5, kDebugScript, "%d ", functionId);
- operand.putFunction(functionId);
+ operand.putFunctionId(functionId);
return operand;
}
@@ -452,7 +458,7 @@ Operand CodeChunk::getVariable(uint32 id, VariableScope scope) {
}
}
-void CodeChunk::putVariable(uint32 id, VariableScope scope, Operand value) {
+void CodeChunk::putVariable(uint32 id, VariableScope scope, Operand &value) {
switch (scope) {
case kVariableScopeGlobal: {
Variable *variable = g_engine->_variables.getVal(id);
@@ -479,7 +485,7 @@ void CodeChunk::putVariable(uint32 id, VariableScope scope, Operand value) {
}
}
-Operand CodeChunk::callBuiltInMethod(BuiltInMethod method, Operand self, Common::Array<Operand> &args) {
+Operand CodeChunk::callBuiltInMethod(BuiltInMethod method, Operand &self, Common::Array<Operand> &args) {
Operand literalSelf = self.getLiteralValue();
OperandType literalType = literalSelf.getType();
switch (literalType) {
@@ -509,7 +515,7 @@ Operand CodeChunk::callBuiltInMethod(BuiltInMethod method, Operand self, Common:
}
case kOperandTypeCollection: {
- Collection *collection = literalSelf.getCollection();
+ Common::SharedPtr<Collection> collection = literalSelf.getCollection();
Operand returnValue = collection->callMethod(method, args);
return returnValue;
}
diff --git a/engines/mediastation/mediascript/codechunk.h b/engines/mediastation/mediascript/codechunk.h
index 79031b17797..c2cd09f000e 100644
--- a/engines/mediastation/mediascript/codechunk.h
+++ b/engines/mediastation/mediascript/codechunk.h
@@ -39,12 +39,13 @@ public:
Operand execute(Common::Array<Operand> *args = nullptr, Common::Array<Operand> *locals = nullptr);
+ static Operand callBuiltInMethod(BuiltInMethod method, Operand &self, Common::Array<Operand> &args);
+
private:
Operand executeNextStatement();
- Operand callBuiltInMethod(BuiltInMethod method, Operand self, Common::Array<Operand> &args);
Operand callFunction(uint functionId, uint parameterCount);
Operand getVariable(uint32 id, VariableScope scope);
- void putVariable(uint32 id, VariableScope scope, Operand value);
+ void putVariable(uint32 id, VariableScope scope, Operand &value);
bool _weOwnLocals = false;
Common::Array<Operand> *_locals = nullptr;
diff --git a/engines/mediastation/mediascript/operand.cpp b/engines/mediastation/mediascript/operand.cpp
index afe0c331fd9..631721d400e 100644
--- a/engines/mediastation/mediascript/operand.cpp
+++ b/engines/mediastation/mediascript/operand.cpp
@@ -162,7 +162,7 @@ Variable *Operand::getVariable() {
}
}
-void Operand::putFunction(uint functionId) {
+void Operand::putFunctionId(uint functionId) {
switch (_type) {
case kOperandTypeFunction: {
_u.functionId = functionId;
@@ -170,7 +170,7 @@ void Operand::putFunction(uint functionId) {
}
default:
- error("Operand::putFunction(): Attempt to put function ID into operand type %s (%d)",
+ error("Operand::putFunctionId(): Attempt to put function ID into operand type %s (%d)",
operandTypeToStr(_type), static_cast<uint>(_type));
}
}
@@ -192,6 +192,31 @@ uint Operand::getFunctionId() {
}
}
+void Operand::putMethodId(BuiltInMethod methodId) {
+ switch (_type) {
+ case kOperandTypeMethod: {
+ _u.methodId = methodId;
+ break;
+ }
+
+ default:
+ error("Operand::putFunctionId(): Attempt to put method ID into operand type %s (%d)",
+ operandTypeToStr(_type), static_cast<uint>(_type));
+ }
+}
+
+BuiltInMethod Operand::getMethodId() {
+ switch (_type) {
+ case kOperandTypeMethod: {
+ return _u.methodId;
+ }
+
+ default:
+ error("Operand::getFunction(): Attempt to get method ID from operand type %s (%d)",
+ operandTypeToStr(_type), static_cast<uint>(_type));
+ }
+}
+
void Operand::putAsset(uint32 assetId) {
switch (_type) {
case kOperandTypeAssetId: {
@@ -249,16 +274,16 @@ uint32 Operand::getAssetId() {
}
}
-void Operand::putCollection(Collection *collection) {
+void Operand::putCollection(Common::SharedPtr<Collection> collection) {
switch (_type) {
case kOperandTypeCollection: {
- _u.collection = collection;
+ _collection = collection;
break;
}
case kOperandTypeVariableDeclaration: {
assert(_u.variable->_type == kVariableTypeCollection);
- _u.variable->_value.collection = collection;
+ _u.variable->_c = collection;
break;
}
@@ -268,15 +293,15 @@ void Operand::putCollection(Collection *collection) {
}
}
-Collection *Operand::getCollection() {
+Common::SharedPtr<Collection> Operand::getCollection() {
switch (_type) {
case kOperandTypeCollection: {
- return _u.collection;
+ return _collection;
}
case kOperandTypeVariableDeclaration: {
assert(_u.variable->_type == kVariableTypeCollection);
- return _u.variable->_value.collection;
+ return _u.variable->_c;
}
default:
diff --git a/engines/mediastation/mediascript/operand.h b/engines/mediastation/mediascript/operand.h
index a9bc9387897..3adba4951bc 100644
--- a/engines/mediastation/mediascript/operand.h
+++ b/engines/mediastation/mediascript/operand.h
@@ -22,6 +22,7 @@
#ifndef MEDIASTATION_MEDIASCRIPT_OPERAND_H
#define MEDIASTATION_MEDIASCRIPT_OPERAND_H
+#include "common/ptr.h"
#include "common/str.h"
#include "mediastation/mediascript/scriptconstants.h"
@@ -52,15 +53,18 @@ public:
void putVariable(Variable *variable);
Variable *getVariable();
- void putFunction(uint functionId);
+ void putFunctionId(uint functionId);
uint getFunctionId();
+ void putMethodId(BuiltInMethod methodId);
+ BuiltInMethod getMethodId();
+
void putAsset(uint32 assetId);
Asset *getAsset();
uint32 getAssetId();
- void putCollection(Collection *collection);
- Collection *getCollection();
+ void putCollection(Common::SharedPtr<Collection> collection);
+ Common::SharedPtr<Collection> getCollection();
Operand getLiteralValue() const;
@@ -88,12 +92,13 @@ private:
union {
uint assetId = 0;
uint functionId;
+ BuiltInMethod methodId;
Common::String *string;
Variable *variable;
int i;
double d;
- Collection *collection;
} _u;
+ Common::SharedPtr<Collection> _collection;
};
} // End of namespace MediaStation
diff --git a/engines/mediastation/mediascript/variable.cpp b/engines/mediastation/mediascript/variable.cpp
index c515993b22b..8cf8c6c36d0 100644
--- a/engines/mediastation/mediascript/variable.cpp
+++ b/engines/mediastation/mediascript/variable.cpp
@@ -19,20 +19,20 @@
*
*/
+#include "mediastation/mediastation.h"
#include "mediastation/mediascript/variable.h"
+#include "mediastation/mediascript/operand.h"
+#include "mediastation/mediascript/codechunk.h"
#include "mediastation/datum.h"
#include "mediastation/debugchannels.h"
-#include "mediastation/mediascript/operand.h"
namespace MediaStation {
Operand Collection::callMethod(BuiltInMethod method, Common::Array<Operand> &args) {
switch (method) {
case kIsEmptyMethod: {
- // This is a built-in method that checks if a collection is empty.
- // We can just check the size of the collection.
Operand returnValue(kOperandTypeLiteral1);
- returnValue.putInteger(empty());
+ returnValue.putInteger(static_cast<uint>(empty()));
return returnValue;
}
@@ -48,6 +48,78 @@ Operand Collection::callMethod(BuiltInMethod method, Common::Array<Operand> &arg
return returnValue;
}
+ case kDeleteAtMethod: {
+ // Find the item in the collection, then remove and return it.
+ assert(args.size() == 1);
+ for (uint i = 0; i < size(); i++) {
+ if (args[0] == operator[](i)) {
+ Operand returnValue = remove_at(i);
+ return returnValue;
+ }
+ }
+
+ // The item wasn't found.
+ return Operand();
+ }
+
+ case kCountMethod: {
+ Operand returnValue = Operand(kOperandTypeLiteral1);
+ returnValue.putInteger(size());
+ return returnValue;
+ }
+
+ case kGetAtMethod: {
+ assert(args.size() == 1);
+ Operand returnValue = operator[](args[0].getInteger());
+ return returnValue;
+ }
+
+ case kSendMethod: {
+ // Call a method on each item in the collection.
+ BuiltInMethod methodToSend = static_cast<BuiltInMethod>(args[0].getMethodId());
+ Common::Array<Operand> sendArgs;
+ for (uint i = 0; i < size(); i++) {
+ Operand self = operator[](i);
+ CodeChunk::callBuiltInMethod(methodToSend, self, sendArgs);
+ }
+ return Operand();
+ }
+
+ case kSeekMethod: {
+ // Find the item in the collection if it exists.
+ assert(args.size() == 1);
+ for (uint i = 0; i < size(); i++) {
+ if (args[0] == operator[](i)) {
+ return operator[](i);
+ }
+ }
+
+ // The item wasn't found.
+ Operand returnValue(kOperandTypeLiteral1);
+ returnValue.putInteger(-1);
+ return returnValue;
+ }
+
+ case kJumbleMethod: {
+ // Scramble the items in the collection.
+ for (uint i = size() - 1; i > 0; --i) {
+ uint j = g_engine->_randomSource.getRandomNumber(size() - 1);
+ SWAP(operator[](i), operator[](j));
+ }
+ return Operand();
+ }
+
+ case kSortMethod: {
+ assert(args.empty());
+ Common::sort(begin(), end());
+ return Operand();
+ }
+
+ case kEmptyMethod: {
+ clear();
+ return Operand();
+ }
+
default:
error("Collection::callMethod(): Attempt to call unimplemented method %s (%d)", builtInMethodToStr(method), static_cast<uint>(method));
}
@@ -57,17 +129,18 @@ Variable::Variable(Chunk &chunk, bool readId) {
if (readId) {
_id = Datum(chunk).u.i;
}
+
_type = static_cast<VariableType>(Datum(chunk).u.i);
- debugC(1, kDebugLoading, "Variable::Variable(): id = %d, type %s (%d) (@0x%llx)",
+ debugC(7, kDebugScript, "Variable::Variable(): id = %d, type %s (%d) (@0x%llx)",
_id, variableTypeToStr(_type), static_cast<uint>(_type), static_cast<long long int>(chunk.pos()));
- switch ((VariableType)_type) {
+ switch (_type) {
case kVariableTypeCollection: {
uint totalItems = Datum(chunk).u.i;
- _value.collection = new Collection;
+ _c = Common::SharedPtr<Collection>(new Collection);
for (uint i = 0; i < totalItems; i++) {
debugC(7, kDebugLoading, "Variable::Variable(): %s: Value %d of %d", variableTypeToStr(_type), i, totalItems);
Variable variable = Variable(chunk, readId = false);
- _value.collection->push_back(variable.getValue());
+ _c->push_back(variable.getValue());
}
break;
}
@@ -119,21 +192,7 @@ Variable::Variable(Chunk &chunk, bool readId) {
}
Variable::~Variable() {
- switch (_type) {
- case kVariableTypeCollection: {
- _value.collection->clear();
- delete _value.collection;
- break;
- }
-
- case kVariableTypeString: {
- delete _value.string;
- break;
- }
-
- default:
- break;
- }
+ clear();
}
Operand Variable::getValue() {
@@ -144,7 +203,7 @@ Operand Variable::getValue() {
case kVariableTypeCollection: {
Operand returnValue(kOperandTypeCollection);
- returnValue.putCollection(_value.collection);
+ returnValue.putCollection(_c);
return returnValue;
}
@@ -190,6 +249,8 @@ Operand Variable::getValue() {
}
void Variable::putValue(Operand value) {
+ clear();
+
switch (value.getType()) {
case kOperandTypeEmpty: {
error("Variable::putValue(): Assigning an empty operand to a variable not supported");
@@ -233,10 +294,36 @@ void Variable::putValue(Operand value) {
break;
}
+ case kOperandTypeCollection: {
+ _type = kVariableTypeCollection;
+ _c = value.getCollection();
+ break;
+ }
+
default:
error("Variable::putValue(): Assigning an unknown operand type %s (%d) to a variable not supported",
operandTypeToStr(value.getType()), static_cast<uint>(value.getType()));
}
}
+void Variable::clear() {
+ switch (_type) {
+ case kVariableTypeCollection: {
+ _c.reset();
+ break;
+ }
+
+ case kVariableTypeString: {
+ delete _value.string;
+ _value.string = nullptr;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ _type = kVariableTypeEmpty;
+}
+
} // End of namespace MediaStation
diff --git a/engines/mediastation/mediascript/variable.h b/engines/mediastation/mediascript/variable.h
index a27d66c1c6f..22abd70b89f 100644
--- a/engines/mediastation/mediascript/variable.h
+++ b/engines/mediastation/mediascript/variable.h
@@ -22,6 +22,7 @@
#ifndef MEDIASTATION_MEDIASCRIPT_VARIABLE_DECLARATION_H
#define MEDIASTATION_MEDIASCRIPT_VARIABLE_DECLARATION_H
+#include "common/ptr.h"
#include "common/str.h"
#include "common/array.h"
@@ -44,19 +45,22 @@ public:
VariableType _type = kVariableTypeEmpty;
union {
Common::String *string;
- Collection *collection;
uint functionId;
int i;
double d;
uint assetId;
} _value;
+ Common::SharedPtr<Collection> _c;
Variable();
Variable(Chunk &chunk, bool readId = true);
+ ~Variable();
Operand getValue();
void putValue(Operand value);
- ~Variable();
+
+private:
+ void clear();
};
} // End of namespace MediaStation
diff --git a/engines/mediastation/mediastation.h b/engines/mediastation/mediastation.h
index dcc9b02c145..64bff78dbd9 100644
--- a/engines/mediastation/mediastation.h
+++ b/engines/mediastation/mediastation.h
@@ -89,6 +89,7 @@ public:
Operand callMethod(BuiltInMethod methodId, Common::Array<Operand> &args);
Operand callBuiltInFunction(BuiltInFunction function, Common::Array<Operand> &args);
Common::HashMap<uint32, Variable *> _variables;
+ Common::RandomSource _randomSource;
Graphics::Screen *_screen = nullptr;
Context *_currentContext = nullptr;
@@ -108,7 +109,6 @@ private:
Common::Event _event;
Common::FSNode _gameDataDir;
const ADGameDescription *_gameDescription;
- Common::RandomSource _randomSource;
// In Media Station, only the cursors are stored in the executable; everything
// else is in the Context (*.CXT) data files.
Commit: 97ea2d6504e8c35d65a9822b019907b0201c1465
https://github.com/scummvm/scummvm/commit/97ea2d6504e8c35d65a9822b019907b0201c1465
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-25T18:21:36-04:00
Commit Message:
MEDIASTATION: Stub Unk1 document method
Changed paths:
engines/mediastation/mediascript/scriptconstants.cpp
engines/mediastation/mediascript/scriptconstants.h
engines/mediastation/mediastation.cpp
diff --git a/engines/mediastation/mediascript/scriptconstants.cpp b/engines/mediastation/mediascript/scriptconstants.cpp
index be272355817..77776b9c3c9 100644
--- a/engines/mediastation/mediascript/scriptconstants.cpp
+++ b/engines/mediastation/mediascript/scriptconstants.cpp
@@ -108,6 +108,8 @@ const char *variableScopeToStr(VariableScope scope) {
const char *builtInFunctionToStr(BuiltInFunction function) {
switch (function) {
+ case kUnk1Function:
+ return "Unk1Function";
case kEffectTransitionFunction:
return "EffectTransition";
case kEffectTransitionOnSyncFunction:
diff --git a/engines/mediastation/mediascript/scriptconstants.h b/engines/mediastation/mediascript/scriptconstants.h
index 6f3d27f5b2f..20de67f078d 100644
--- a/engines/mediastation/mediascript/scriptconstants.h
+++ b/engines/mediastation/mediascript/scriptconstants.h
@@ -73,6 +73,7 @@ enum VariableScope {
const char *variableScopeToStr(VariableScope scope);
enum BuiltInFunction {
+ kUnk1Function = 10,
// TODO: Figure out if effectTransitionOnSync = 13 is consistent across titles?
kEffectTransitionFunction = 12, // PARAMS: 1
kEffectTransitionOnSyncFunction = 13,
diff --git a/engines/mediastation/mediastation.cpp b/engines/mediastation/mediastation.cpp
index 28bff731ab3..9c115d033eb 100644
--- a/engines/mediastation/mediastation.cpp
+++ b/engines/mediastation/mediastation.cpp
@@ -504,6 +504,13 @@ Operand MediaStationEngine::callBuiltInFunction(BuiltInFunction function, Common
return Operand();
}
+ case kUnk1Function: {
+ warning("MediaStationEngine::callBuiltInFunction(): Function 10 not implemented");
+ Operand returnValue = Operand(kOperandTypeLiteral1);
+ returnValue.putInteger(1);
+ return returnValue;
+ }
+
default:
error("MediaStationEngine::callBuiltInFunction(): Got unknown built-in function %s (%d)", builtInFunctionToStr(function), static_cast<uint>(function));
}
Commit: ca95c3596cdee62e95a3613fb1eda50d85446b17
https://github.com/scummvm/scummvm/commit/ca95c3596cdee62e95a3613fb1eda50d85446b17
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-25T18:21:36-04:00
Commit Message:
MEDIASTATION: Don't release contexts too early
Changed paths:
engines/mediastation/mediastation.cpp
engines/mediastation/mediastation.h
diff --git a/engines/mediastation/mediastation.cpp b/engines/mediastation/mediastation.cpp
index 9c115d033eb..1a826eb8572 100644
--- a/engines/mediastation/mediastation.cpp
+++ b/engines/mediastation/mediastation.cpp
@@ -159,6 +159,13 @@ Common::Error MediaStationEngine::run() {
break;
}
+ if (!_requestedContextReleaseId.empty()) {
+ for (uint contextId : _requestedContextReleaseId) {
+ releaseContext(contextId);
+ }
+ _requestedContextReleaseId.clear();
+ }
+
debugC(5, kDebugGraphics, "***** START SCREEN UPDATE ***");
for (auto it = _assetsPlaying.begin(); it != _assetsPlaying.end();) {
(*it)->process();
@@ -403,7 +410,7 @@ Operand MediaStationEngine::callMethod(BuiltInMethod methodId, Common::Array<Ope
case kReleaseContextMethod: {
assert(args.size() == 1);
uint32 contextId = args[0].getAssetId();
- releaseContext(contextId);
+ _requestedContextReleaseId.push_back(contextId);
return Operand();
}
@@ -452,6 +459,17 @@ void MediaStationEngine::releaseContext(uint32 contextId) {
error("MediaStationEngine::releaseContext(): Attempted to unload context %d that is not currently loaded", contextId);
}
+ // Make sure nothing is still using this context.
+ for (auto it = _loadedContexts.begin(); it != _loadedContexts.end(); ++it) {
+ uint id = it->_key;
+ ContextDeclaration *contextDeclaration = _boot->_contextDeclarations.getValOrDefault(id);
+ for (uint32 childContextId : contextDeclaration->_fileReferences) {
+ if (childContextId == contextId) {
+ return;
+ }
+ }
+ }
+
// Unload any assets currently playing from this context. They should have
// already been stopped by scripts, but this is a last check.
for (auto it = _assetsPlaying.begin(); it != _assetsPlaying.end();) {
diff --git a/engines/mediastation/mediastation.h b/engines/mediastation/mediastation.h
index 64bff78dbd9..dd11d511290 100644
--- a/engines/mediastation/mediastation.h
+++ b/engines/mediastation/mediastation.h
@@ -121,6 +121,7 @@ private:
Asset *_currentHotspot = nullptr;
uint _requestedScreenBranchId = 0;
+ Common::Array<uint> _requestedContextReleaseId;
void doBranchToScreen();
Context *loadContext(uint32 contextId);
Commit: d6a62221a698ebed8ecb1694c0388c24ff3707fd
https://github.com/scummvm/scummvm/commit/d6a62221a698ebed8ecb1694c0388c24ff3707fd
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-25T19:26:27-04:00
Commit Message:
MEDIASTATION: Permit scripts to coerce some types
Changed paths:
engines/mediastation/mediascript/operand.cpp
diff --git a/engines/mediastation/mediascript/operand.cpp b/engines/mediastation/mediascript/operand.cpp
index 631721d400e..f0a10727b32 100644
--- a/engines/mediastation/mediascript/operand.cpp
+++ b/engines/mediastation/mediascript/operand.cpp
@@ -53,6 +53,10 @@ int Operand::getInteger() {
return _u.i;
}
+ case kOperandTypeFloat1: {
+ return static_cast<int>(_u.d);
+ }
+
case kOperandTypeVariableDeclaration: {
return _u.variable->_value.i;
}
@@ -90,6 +94,11 @@ double Operand::getDouble() {
return _u.d;
}
+ case kOperandTypeLiteral1:
+ case kOperandTypeLiteral2: {
+ return static_cast<double>(_u.i);
+ }
+
case kOperandTypeVariableDeclaration: {
// TODO: Add assertion that this is the proper type.
return _u.variable->_value.d;
@@ -336,7 +345,17 @@ bool Operand::operator==(const Operand &other) const {
return lhs.getInteger() == rhs.getInteger();
case kOperandTypeAssetId:
- return lhs.getAssetId() == rhs.getAssetId();
+ if (rhs.getType() == kOperandTypeLiteral2) {
+ // This might happen if, for example, a given asset wasn't found
+ // in a collection and the script sets the return value to -1.
+ return static_cast<int>(lhs.getAssetId()) == rhs.getInteger();
+ } else {
+ // If the types are incompatiable, rhs will raise the error.
+ return lhs.getAssetId() == rhs.getAssetId();
+ }
+
+ case kOperandTypeString:
+ return *lhs.getString() == *rhs.getString();
default:
error("Operand::operator==(): Unimplemented operand types %s and %s", operandTypeToStr(lhs.getType()), operandTypeToStr(rhs.getType()));
Commit: 61859559cd8fabd26ed7ca7da073b8268cbabfe0
https://github.com/scummvm/scummvm/commit/61859559cd8fabd26ed7ca7da073b8268cbabfe0
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-25T19:26:27-04:00
Commit Message:
MEDIASTATION: Allow movies to move under script control
In Dalmatians 185.CXT, the soot "cursor" is a movie, not a
sprite as with the other larger cursors in Dalmatians.
Changed paths:
engines/mediastation/assets/movie.cpp
engines/mediastation/assets/movie.h
engines/mediastation/mediascript/scriptconstants.cpp
engines/mediastation/mediascript/scriptconstants.h
diff --git a/engines/mediastation/assets/movie.cpp b/engines/mediastation/assets/movie.cpp
index 3bf832c9876..e75f9dd5b39 100644
--- a/engines/mediastation/assets/movie.cpp
+++ b/engines/mediastation/assets/movie.cpp
@@ -212,13 +212,53 @@ Operand Movie::callMethod(BuiltInMethod methodId, Common::Array<Operand> &args)
return Operand();
}
+ case kIsVisibleMethod: {
+ assert(args.empty());
+ Operand returnValue(kOperandTypeLiteral1);
+ returnValue.putInteger(_isShowing);
+ return returnValue;
+ }
+
+ case kSpatialCenterMoveToMethod: {
+ assert(args.size() == 2);
+ spatialCenterMoveTo(args[0].getInteger(), args[1].getInteger());
+ return Operand();
+ }
+
+ case kSpatialMoveToMethod: {
+ assert(args.size() == 2);
+ spatialMoveTo(args[0].getInteger(), args[1].getInteger());
+ return Operand();
+ }
+
case kIsPlayingMethod: {
assert(args.empty());
Operand returnValue(kOperandTypeLiteral1);
- returnValue.putInteger(_isPlaying);
+ returnValue.putInteger(static_cast<uint>(_isPlaying));
return returnValue;
}
+ case kXPositionMethod: {
+ assert(args.empty());
+ Operand returnValue(kOperandTypeLiteral1);
+ returnValue.putInteger(_header->_boundingBox->left);
+ return returnValue;
+
+ }
+
+ case kYPositionMethod: {
+ assert(args.empty());
+ Operand returnValue(kOperandTypeLiteral1);
+ returnValue.putInteger(_header->_boundingBox->top);
+ return returnValue;
+ }
+
+ case kSetDissolveFactorMethod: {
+ assert(args.size() == 1);
+ warning("Movie::callMethod(): setDissolveFactor not implemented yet");
+ return Operand();
+ }
+
default:
error("Movie::callMethod(): Got unimplemented method ID %s (%d)", builtInMethodToStr(methodId), static_cast<uint>(methodId));
}
@@ -330,8 +370,52 @@ void Movie::timeStop() {
runEventHandlerIfExists(kMovieStoppedEvent);
}
+void Movie::spatialCenterMoveTo(int x, int y) {
+ // Mark the previous location dirty.
+ for (MovieFrame *frame : _framesOnScreen) {
+ Common::Rect bbox = getFrameBoundingBox(frame);
+ g_engine->_dirtyRects.push_back(bbox);
+ }
+
+ // Calculate the center of the movie, and update location.
+ int frameWidth = _header->_boundingBox->width();
+ int frameHeight = _header->_boundingBox->height();
+ int centerX = x - frameWidth / 2;
+ int centerY = y - frameHeight / 2;
+
+ debugC(5, kDebugScript, "Movie::callMethod(): (%d) Moving movie center to (%d, %d)", _header->_id, x, y);
+ // Unlike the sprites, movie bounding boxes must be moved too.
+ _header->_boundingBox->moveTo(centerX, centerY);
+
+ // Mark the new location dirty.
+ for (MovieFrame *frame : _framesOnScreen) {
+ Common::Rect bbox = getFrameBoundingBox(frame);
+ g_engine->_dirtyRects.push_back(bbox);
+ }
+}
+
+void Movie::spatialMoveTo(int x, int y) {
+ // Mark the previous location dirty.
+ for (MovieFrame *frame : _framesOnScreen) {
+ Common::Rect bbox = getFrameBoundingBox(frame);
+ g_engine->_dirtyRects.push_back(bbox);
+ }
+
+ // Update the location and mark the new location dirty.
+ debugC(5, kDebugGraphics, "Movie::callMethod(): (%d) Moving movie to (%d, %d)", _header->_id, x, y);
+ // Unlike the sprites, movie bounding boxes must be moved too.
+ _header->_boundingBox->moveTo(x, y);
+
+ for (MovieFrame *frame : _framesOnScreen) {
+ Common::Rect bbox = getFrameBoundingBox(frame);
+ g_engine->_dirtyRects.push_back(bbox);
+ }
+}
+
void Movie::process() {
- processTimeEventHandlers();
+ if (_isPlaying) {
+ processTimeEventHandlers();
+ }
updateFrameState();
}
@@ -406,7 +490,6 @@ void Movie::updateFrameState() {
return;
}
-
// Show the frames that are currently active, for debugging purposes.
for (MovieFrame *frame : _framesOnScreen) {
debugC(5, kDebugGraphics, " (time: %d ms) Frame %d (%d x %d) @ (%d, %d); start: %d ms, end: %d ms, keyframeEnd: %d ms, zIndex = %d", movieTime, frame->index(), frame->width(), frame->height(), frame->left(), frame->top(), frame->startInMilliseconds(), frame->endInMilliseconds(), frame->keyframeEndInMilliseconds(), frame->zCoordinate());
@@ -432,6 +515,7 @@ void Movie::redraw(Common::Rect &rect) {
if (!areaToRedraw.isEmpty()) {
Common::Point originOnScreen(areaToRedraw.left, areaToRedraw.top);
areaToRedraw.translate(-frame->left() - _header->_boundingBox->left, -frame->top() - _header->_boundingBox->top);
+ areaToRedraw.clip(Common::Rect(0, 0, frame->width(), frame->height()));
g_engine->_screen->simpleBlitFrom(frame->_surface, areaToRedraw, originOnScreen);
}
}
diff --git a/engines/mediastation/assets/movie.h b/engines/mediastation/assets/movie.h
index 52647d9ffa3..5b1841449b7 100644
--- a/engines/mediastation/assets/movie.h
+++ b/engines/mediastation/assets/movie.h
@@ -121,6 +121,8 @@ private:
void timeStop();
void spatialShow();
void spatialHide();
+ void spatialCenterMoveTo(int x, int y);
+ void spatialMoveTo(int x, int y);
void updateFrameState();
void showPersistentFrame();
diff --git a/engines/mediastation/mediascript/scriptconstants.cpp b/engines/mediastation/mediascript/scriptconstants.cpp
index 77776b9c3c9..4a11bc9d408 100644
--- a/engines/mediastation/mediascript/scriptconstants.cpp
+++ b/engines/mediastation/mediascript/scriptconstants.cpp
@@ -133,6 +133,8 @@ const char *builtInMethodToStr(BuiltInMethod method) {
return "SpatialMoveTo";
case kSpatialZMoveToMethod:
return "SpatialZMoveTo";
+ case kSpatialCenterMoveToMethod:
+ return "SpatialCenterMoveTo";
case kSpatialShowMethod:
return "SpatialShow";
case kTimePlayMethod:
diff --git a/engines/mediastation/mediascript/scriptconstants.h b/engines/mediastation/mediascript/scriptconstants.h
index 20de67f078d..be33460b6a0 100644
--- a/engines/mediastation/mediascript/scriptconstants.h
+++ b/engines/mediastation/mediascript/scriptconstants.h
@@ -98,6 +98,7 @@ enum BuiltInMethod {
kTimeStopMethod = 207, // PARAMS: 0
kIsPlayingMethod = 372, // PARAMS: 0
kSetDissolveFactorMethod = 241, // PARAMS: 1
+ kSpatialCenterMoveToMethod = 230,
// HOTSPOT METHODS.
kMouseActivateMethod = 210, // PARAMS: 1
Commit: 0658576196e2c767268eb77e2ee1f14c03b3762a
https://github.com/scummvm/scummvm/commit/0658576196e2c767268eb77e2ee1f14c03b3762a
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-25T19:26:27-04:00
Commit Message:
MEDIASTATION: Make path playback non-blocking
Changed paths:
engines/mediastation/assetheader.cpp
engines/mediastation/assetheader.h
engines/mediastation/assets/path.cpp
engines/mediastation/assets/path.h
diff --git a/engines/mediastation/assetheader.cpp b/engines/mediastation/assetheader.cpp
index 2af6e18635e..33196c88e86 100644
--- a/engines/mediastation/assetheader.cpp
+++ b/engines/mediastation/assetheader.cpp
@@ -365,6 +365,11 @@ void AssetHeader::readSection(AssetHeaderSectionType sectionType, Chunk& chunk)
break;
}
+ case kAssetHeaderPathTotalSteps: {
+ _totalSteps = Datum(chunk).u.i;
+ break;
+ }
+
default:
error("AssetHeader::readSection(): Unknown section type 0x%x (@0x%llx)", static_cast<uint>(sectionType), static_cast<long long int>(chunk.pos()));
}
diff --git a/engines/mediastation/assetheader.h b/engines/mediastation/assetheader.h
index 29cbbbce553..b8f327fbd55 100644
--- a/engines/mediastation/assetheader.h
+++ b/engines/mediastation/assetheader.h
@@ -108,7 +108,7 @@ enum AssetHeaderSectionType {
// PATH FIELDS.
kAssetHeaderStartPoint = 0x060e,
kAssetHeaderEndPoint = 0x060f,
- kAssetHeaderPathUnk1 = 0x0610,
+ kAssetHeaderPathTotalSteps = 0x0610,
kAssetHeaderStepRate = 0x0611,
kAssetHeaderDuration = 0x0612,
@@ -200,6 +200,7 @@ public:
Common::Point *_endPoint = nullptr;
uint32 _stepRate = 0;
uint32 _duration = 0;
+ uint _totalSteps = 0;
// EVENT HANDLER FIELDS.
Common::HashMap<uint, EventHandler *> _eventHandlers;
diff --git a/engines/mediastation/assets/path.cpp b/engines/mediastation/assets/path.cpp
index 1b3ca6205d8..c6744ceab6e 100644
--- a/engines/mediastation/assets/path.cpp
+++ b/engines/mediastation/assets/path.cpp
@@ -56,43 +56,70 @@ Operand Path::callMethod(BuiltInMethod methodId, Common::Array<Operand> &args) {
return Operand();
}
+ case kIsPlayingMethod: {
+ assert(args.empty());
+ Operand returnValue(kOperandTypeLiteral1);
+ returnValue.putInteger(_isActive);
+ return returnValue;
+ }
+
default:
error("Path::callMethod(): Got unimplemented method ID %s (%d)", builtInMethodToStr(methodId), static_cast<uint>(methodId));
}
}
void Path::timePlay() {
- // TODO: Check that itʻs zero before we reset it, since this function isn't re-entrant!
- _percentComplete = 0.0;
+ if (_isActive) {
+ warning("Path::timePlay(): Attempted to play a path that is already playing");
+ return;
+ }
if (_header->_duration == 0) {
warning("Path::timePlay(): Got zero duration");
} else if (_header->_stepRate == 0) {
error("Path::timePlay(): Got zero step rate");
}
- debugC(5, kDebugScript, "Path::timePlay(): Path playback started");
- uint totalSteps = (_header->_duration * _header->_stepRate) / 1000;
- //uint stepDurationInMilliseconds = 1000 / _header->_stepRate;
+
+ setActive();
+ _percentComplete = 0;
+ _nextPathStepTime = 0;
+ _currentStep = 0;
+ _totalSteps = (_header->_duration * _header->_stepRate) / 1000;
+ _stepDurationInMilliseconds = 1000 / _header->_stepRate;
// TODO: Run the path start event. Haven't seen one the wild yet, don't know its ID.
debugC(5, kDebugScript, "Path::timePlay(): No PathStart event handler");
+}
+
+void Path::process() {
+ uint currentTime = g_system->getMillis();
+ uint pathTime = currentTime - _startTime;
- // Step the path.
- for (uint i = 0; i < totalSteps; i++) {
- _percentComplete = (double)(i + 1) / totalSteps;
- debugC(5, kDebugScript, "Path::timePlay(): Step %d of %d", i, totalSteps);
+ bool doNextStep = pathTime >= _nextPathStepTime;
+ if (!doNextStep) {
+ return;
+ }
+
+ _percentComplete = static_cast<double>(_currentStep + 1) / _totalSteps;
+ debugC(2, kDebugScript, "Path::timePlay(): Step %d of %d", _currentStep, _totalSteps);
+
+ if (_currentStep < _totalSteps) {
// TODO: Actually step the path. It seems they mostly just use this for
// palette animation in the On Step event handler, so nothing is actually drawn on the screen now.
+ // We donʻt run a step event for the last step.
runEventHandlerIfExists(kStepEvent);
+ _nextPathStepTime = ++_currentStep * _stepDurationInMilliseconds;
+ } else {
+ setInactive();
+ _percentComplete = 0;
+ _nextPathStepTime = 0;
+ _currentStep = 0;
+ _totalSteps = 0;
+ _stepDurationInMilliseconds = 0;
+
+ runEventHandlerIfExists(kPathEndEvent);
}
-
- runEventHandlerIfExists(kPathEndEvent);
- _percentComplete = 0;
-}
-
-void Path::process() {
- // TODO: Handle this case.
}
void Path::setDuration(uint durationInMilliseconds) {
diff --git a/engines/mediastation/assets/path.h b/engines/mediastation/assets/path.h
index 07908f53592..939dfdf1e41 100644
--- a/engines/mediastation/assets/path.h
+++ b/engines/mediastation/assets/path.h
@@ -40,6 +40,10 @@ public:
private:
double _percentComplete = 0.0;
+ uint _totalSteps = 0;
+ uint _currentStep = 0;
+ uint _nextPathStepTime = 0;
+ uint _stepDurationInMilliseconds = 0;
// Method implementations.
void timePlay();
More information about the Scummvm-git-logs
mailing list