[Scummvm-git-logs] scummvm master -> 9d717b633d7bf0c2c3b8846b5ef5d51a2474788b

npjg noreply at scummvm.org
Thu Mar 13 23:18:28 UTC 2025


This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
19e086fb0c MEDIASTATION: Implement sprite frame mapping field
5e51f63e86 MEDIASTATION: Show first sprite frames properly
09bbc7e798 MEDIASTATION: Let sprites & images move under script control
3421caee82 MEDIASTATION: Make local script vars accessible to sub-chunks
c3b9cad220 MEDIASTATION: Fix hotspot refresh recursion in scripts
4d620f729a MEDIASTATION: Stub another transition type
9d717b633d MEDIASTATION: Support referencing functions in variables


Commit: 19e086fb0cfbc151dc49466615fc7bbd43c579d5
    https://github.com/scummvm/scummvm/commit/19e086fb0cfbc151dc49466615fc7bbd43c579d5
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-13T18:54:02-04:00

Commit Message:
MEDIASTATION: Implement sprite frame mapping field

This allows scripts to manually set a frame in the sprite.

Changed paths:
    engines/mediastation/assetheader.cpp
    engines/mediastation/assetheader.h
    engines/mediastation/assets/sprite.cpp
    engines/mediastation/mediascript/scriptconstants.cpp
    engines/mediastation/mediascript/scriptconstants.h


diff --git a/engines/mediastation/assetheader.cpp b/engines/mediastation/assetheader.cpp
index ce6be09a3ce..2af6e18635e 100644
--- a/engines/mediastation/assetheader.cpp
+++ b/engines/mediastation/assetheader.cpp
@@ -354,6 +354,17 @@ void AssetHeader::readSection(AssetHeaderSectionType sectionType, Chunk& chunk)
 		break;
 	}
 
+	case kAssetHeaderSpriteFrameMapping: {
+		uint32 externalFrameId = Datum(chunk).u.i;
+		uint32 internalFrameId = Datum(chunk).u.i;
+		uint32 unk1 = Datum(chunk).u.i;
+		if (unk1 != internalFrameId) {
+			warning("AssetHeader::readSection(): Repeated internalFrameId doesn't match");
+		}
+		_spriteFrameMapping.setVal(externalFrameId, internalFrameId);
+		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 9d184948d2f..29cbbbce553 100644
--- a/engines/mediastation/assetheader.h
+++ b/engines/mediastation/assetheader.h
@@ -131,7 +131,10 @@ enum AssetHeaderSectionType {
 	kAssetHeaderTextPosition = 0x25f,
 	kAssetHeaderTextUnk1 = 0x262,
 	kAssetHeaderTextUnk2 = 0x263,
-	kAssetHeaderTextCharacterClass = 0x0266
+	kAssetHeaderTextCharacterClass = 0x0266,
+
+	// SPRITE FIELDS.
+	kAssetHeaderSpriteFrameMapping = 0x03e9
 };
 
 enum TextJustification {
@@ -189,6 +192,7 @@ public:
 	uint32 _stageId = 0;
 	SoundEncoding _soundEncoding;
 	uint32 _chunkCount = 0;
+	Common::HashMap<uint32, uint32> _spriteFrameMapping;
 
 	// PATH FIELDS.
 	uint32 _dissolveFactor = 0;
diff --git a/engines/mediastation/assets/sprite.cpp b/engines/mediastation/assets/sprite.cpp
index 533ef3011be..751f643f34d 100644
--- a/engines/mediastation/assets/sprite.cpp
+++ b/engines/mediastation/assets/sprite.cpp
@@ -122,6 +122,14 @@ Operand Sprite::callMethod(BuiltInMethod methodId, Common::Array<Operand> &args)
 		return Operand();
 	}
 
+	case kSetSpriteFrameByIdMethod: {
+		assert(args.size() == 1);
+		uint32 externalFrameId = args[0].getInteger();
+		uint32 internalFrameId = _header->_spriteFrameMapping.getVal(externalFrameId);
+		showFrame(_frames[internalFrameId]);
+		return Operand();
+	}
+
 	case kIsPlayingMethod: {
 		Operand returnValue(kOperandTypeLiteral1);
 		returnValue.putInteger(static_cast<int>(_isPlaying));
diff --git a/engines/mediastation/mediascript/scriptconstants.cpp b/engines/mediastation/mediascript/scriptconstants.cpp
index ee6e91000c9..7446848e9e8 100644
--- a/engines/mediastation/mediascript/scriptconstants.cpp
+++ b/engines/mediastation/mediascript/scriptconstants.cpp
@@ -161,6 +161,8 @@ const char *builtInMethodToStr(BuiltInMethod method) {
 		return "IsVisible";
 	case kMovieResetMethod:
 		return "MovieReset";
+	case kSetSpriteFrameByIdMethod:
+		return "SetSpriteFrameById";
 	case kSetCurrentClipMethod:
 		return "SetCurrentClip";
 	case kSetWorldSpaceExtentMethod:
diff --git a/engines/mediastation/mediascript/scriptconstants.h b/engines/mediastation/mediascript/scriptconstants.h
index 0228a2f047f..d03d5672fb1 100644
--- a/engines/mediastation/mediascript/scriptconstants.h
+++ b/engines/mediastation/mediascript/scriptconstants.h
@@ -113,6 +113,7 @@ enum BuiltInMethod {
 
 	// SPRITE METHODS.
 	kMovieResetMethod = 219, // PARAMS: 0
+	kSetSpriteFrameByIdMethod = 220, // PARAMS: 1
 	kSetCurrentClipMethod = 221, // PARAMS: 0-1
 
 	// STAGE METHODS.


Commit: 5e51f63e86e28d467ddb4b1b493fecd853ba84f5
    https://github.com/scummvm/scummvm/commit/5e51f63e86e28d467ddb4b1b493fecd853ba84f5
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-13T18:54:02-04:00

Commit Message:
MEDIASTATION: Show first sprite frames properly

Changed paths:
    engines/mediastation/assets/sprite.cpp
    engines/mediastation/assets/sprite.h


diff --git a/engines/mediastation/assets/sprite.cpp b/engines/mediastation/assets/sprite.cpp
index 751f643f34d..df7b17ae181 100644
--- a/engines/mediastation/assets/sprite.cpp
+++ b/engines/mediastation/assets/sprite.cpp
@@ -70,6 +70,7 @@ Sprite::Sprite(AssetHeader *header) : Asset(header) {
 	if (header->_startup == kAssetStartupActive) {
 		setActive();
 		_isShowing = true;
+		_showFirstFrame = true;
 	}
 }
 
@@ -117,7 +118,10 @@ Operand Sprite::callMethod(BuiltInMethod methodId, Common::Array<Operand> &args)
 	}
 
 	case kSetCurrentClipMethod: {
-		assert(args.empty());
+		assert(args.size() <= 1);
+		if (args.size() == 1 && args[0].getInteger() != 0) {
+			error("Sprite::callMethod(): (%d) setClip() called with unhandled arg: %d", _header->_id, args[0].getInteger());
+		}
 		setCurrentClip();
 		return Operand();
 	}
@@ -236,6 +240,12 @@ void Sprite::readChunk(Chunk &chunk) {
 }
 
 void Sprite::updateFrameState() {
+	if (_showFirstFrame) {
+		showFrame(_frames[0]);
+		_showFirstFrame = false;
+		return;
+	}
+
 	if (!_isActive) {
 		return;
 	}
diff --git a/engines/mediastation/assets/sprite.h b/engines/mediastation/assets/sprite.h
index 9156a5919fe..196bf7762d8 100644
--- a/engines/mediastation/assets/sprite.h
+++ b/engines/mediastation/assets/sprite.h
@@ -76,6 +76,7 @@ public:
 private:
 	Common::Array<SpriteFrame *> _frames;
 	SpriteFrame *_activeFrame = nullptr;
+	bool _showFirstFrame = true;
 	bool _isShowing = false;
 	bool _isPlaying = false;
 	uint _currentFrameIndex = 0;


Commit: 09bbc7e7982c21df82004df380f3f77b4d5f3a72
    https://github.com/scummvm/scummvm/commit/09bbc7e7982c21df82004df380f3f77b4d5f3a72
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-13T18:54:03-04:00

Commit Message:
MEDIASTATION: Let sprites & images move under script control

Changed paths:
    engines/mediastation/assets/hotspot.cpp
    engines/mediastation/assets/image.cpp
    engines/mediastation/assets/image.h
    engines/mediastation/assets/sprite.cpp
    engines/mediastation/assets/sprite.h
    engines/mediastation/mediastation.cpp
    engines/mediastation/mediastation.h


diff --git a/engines/mediastation/assets/hotspot.cpp b/engines/mediastation/assets/hotspot.cpp
index 87b66f3c4f5..f0ae58cd367 100644
--- a/engines/mediastation/assets/hotspot.cpp
+++ b/engines/mediastation/assets/hotspot.cpp
@@ -92,6 +92,18 @@ Operand Hotspot::callMethod(BuiltInMethod methodId, Common::Array<Operand> &args
 		return returnValue;
 	}
 
+	case kTriggerAbsXPositionMethod: {
+		Operand returnValue(kOperandTypeLiteral1);
+		returnValue.putInteger(g_engine->_mousePos.x);
+		return returnValue;
+	}
+
+	case kTriggerAbsYPositionMethod: {
+		Operand returnValue(kOperandTypeLiteral1);
+		returnValue.putInteger(g_engine->_mousePos.y);
+		return returnValue;
+	}
+
 	default:
 		error("Hotspot::callMethod(): Got unimplemented method ID %s (%d)", builtInMethodToStr(methodId), static_cast<uint>(methodId));
 	}
diff --git a/engines/mediastation/assets/image.cpp b/engines/mediastation/assets/image.cpp
index c5fc1e302d9..869f73c9dd8 100644
--- a/engines/mediastation/assets/image.cpp
+++ b/engines/mediastation/assets/image.cpp
@@ -60,6 +60,27 @@ Operand Image::callMethod(BuiltInMethod methodId, Common::Array<Operand> &args)
 		return Operand();
 	}
 
+	case kSpatialMoveToMethod: {
+		assert(args.size() == 2);
+
+		// Mark the previous location dirty.
+		Common::Rect bbox(getLeftTop(), _bitmap->width(), _bitmap->height());
+		g_engine->_dirtyRects.push_back(bbox);
+
+		// Update location and mark new location dirty.
+		int newXAdjust = args[0].getInteger();
+		int newYAdjust = args[1].getInteger();
+		if (_xAdjust != newXAdjust || _yAdjust != newYAdjust) {
+			_xAdjust = newXAdjust;
+			_yAdjust = newYAdjust;
+
+			bbox = Common::Rect(getLeftTop(), _bitmap->width(), _bitmap->height());
+			g_engine->_dirtyRects.push_back(bbox);
+		}
+
+		return Operand();
+	}
+
 	default:
 		error("Image::callMethod(): Got unimplemented method ID %s (%d)", builtInMethodToStr(methodId), static_cast<uint>(methodId));
 	}
@@ -76,6 +97,7 @@ void Image::redraw(Common::Rect &rect) {
 	if (!areaToRedraw.isEmpty()) {
 		Common::Point originOnScreen(areaToRedraw.left, areaToRedraw.top);
 		areaToRedraw.translate(-leftTop.x, -leftTop.y);
+		areaToRedraw.clip(Common::Rect(0, 0, _bitmap->width(), _bitmap->height()));
 		g_engine->_screen->simpleBlitFrom(_bitmap->_surface, areaToRedraw, originOnScreen);
 	}
 }
@@ -94,7 +116,7 @@ void Image::spatialHide() {
 }
 
 Common::Point Image::getLeftTop() {
-	return Common::Point(_header->_x + _header->_boundingBox->left, _header->_y + _header->_boundingBox->top);
+	return Common::Point(_header->_x + _header->_boundingBox->left + _xAdjust, _header->_y + _header->_boundingBox->top + _yAdjust);
 }
 
 void Image::readChunk(Chunk &chunk) {
diff --git a/engines/mediastation/assets/image.h b/engines/mediastation/assets/image.h
index 41185b4a765..4f4d502c785 100644
--- a/engines/mediastation/assets/image.h
+++ b/engines/mediastation/assets/image.h
@@ -46,6 +46,8 @@ public:
 
 private:
 	Bitmap *_bitmap = nullptr;
+	int _xAdjust = 0;
+	int _yAdjust = 0;
 
 	// Script method implementations.
 	void spatialShow();
diff --git a/engines/mediastation/assets/sprite.cpp b/engines/mediastation/assets/sprite.cpp
index df7b17ae181..c3af44070a9 100644
--- a/engines/mediastation/assets/sprite.cpp
+++ b/engines/mediastation/assets/sprite.cpp
@@ -140,6 +140,29 @@ Operand Sprite::callMethod(BuiltInMethod methodId, Common::Array<Operand> &args)
 		return returnValue;
 	}
 
+	case kSpatialMoveToMethod: {
+		assert(args.size() == 2);
+
+		// Mark the previous location dirty.
+		if (_activeFrame != nullptr) {
+			g_engine->_dirtyRects.push_back(getActiveFrameBoundingBox());
+		}
+
+		// Update the location and mark the new location dirty.
+		int newXAdjust = args[0].getInteger();
+		int newYAdjust = args[1].getInteger();
+		if (_xAdjust != newXAdjust || _yAdjust != newYAdjust) {
+			debugC(5, kDebugGraphics, "Sprite::callMethod(): (%d) Moving sprite to (%d, %d)", _header->_id, newXAdjust, newYAdjust);
+			_xAdjust = newXAdjust;
+			_yAdjust = newYAdjust;
+			if (_activeFrame != nullptr) {
+				g_engine->_dirtyRects.push_back(getActiveFrameBoundingBox());
+			}
+		}
+
+		return Operand();
+	}
+
 	default:
 		error("Sprite::callMethod(): Got unimplemented method ID %s (%d)", builtInMethodToStr(methodId), static_cast<uint>(methodId));
 	}
@@ -301,7 +324,8 @@ void Sprite::redraw(Common::Rect &rect) {
 	Common::Rect areaToRedraw = bbox.findIntersectingRect(rect);
 	if (!areaToRedraw.isEmpty()) {
 		Common::Point originOnScreen(areaToRedraw.left, areaToRedraw.top);
-		areaToRedraw.translate(-_activeFrame->left() - _header->_boundingBox->left, -_activeFrame->top() - _header->_boundingBox->top);
+		areaToRedraw.translate(-_activeFrame->left() - _header->_boundingBox->left - _xAdjust, -_activeFrame->top() - _header->_boundingBox->top - _yAdjust);
+		areaToRedraw.clip(Common::Rect(0, 0, _activeFrame->width(), _activeFrame->height()));
 		g_engine->_screen->simpleBlitFrom(_activeFrame->_surface, areaToRedraw, originOnScreen);
 	}
 }
@@ -323,7 +347,7 @@ Common::Rect Sprite::getActiveFrameBoundingBox() {
 	// The frame dimensions are relative to those of the sprite movie.
 	// So we must get the absolute coordinates.
 	Common::Rect bbox = _activeFrame->boundingBox();
-	bbox.translate(_header->_boundingBox->left, _header->_boundingBox->top);
+	bbox.translate(_header->_boundingBox->left + _xAdjust, _header->_boundingBox->top + _yAdjust);
 	return bbox;
 }
 
diff --git a/engines/mediastation/assets/sprite.h b/engines/mediastation/assets/sprite.h
index 196bf7762d8..1999ae819f5 100644
--- a/engines/mediastation/assets/sprite.h
+++ b/engines/mediastation/assets/sprite.h
@@ -82,6 +82,9 @@ private:
 	uint _currentFrameIndex = 0;
 	uint _nextFrameTime = 0;
 
+	int _xAdjust = 0;
+	int _yAdjust = 0;
+
 	// Method implementations.
 	void spatialShow();
 	void spatialHide();
diff --git a/engines/mediastation/mediastation.cpp b/engines/mediastation/mediastation.cpp
index 35b5289efd1..b84cbe56c80 100644
--- a/engines/mediastation/mediastation.cpp
+++ b/engines/mediastation/mediastation.cpp
@@ -200,14 +200,14 @@ void MediaStationEngine::processEvents() {
 		}
 
 		case Common::EVENT_MOUSEMOVE: {
+			_mousePos = g_system->getEventManager()->getMousePos();
 			refreshActiveHotspot();
 			break;
 		}
 
 		case Common::EVENT_KEYDOWN: {
 			// Even though this is a keydown event, we need to look at the mouse position.
-			Common::Point mousePos = g_system->getEventManager()->getMousePos();
-			Asset *hotspot = findAssetToAcceptMouseEvents(mousePos);
+			Asset *hotspot = findAssetToAcceptMouseEvents();
 			if (hotspot != nullptr) {
 				debugC(1, kDebugEvents, "EVENT_KEYDOWN (%d): Sent to hotspot %d", _event.kbd.ascii, hotspot->getHeader()->_id);
 				hotspot->runKeyDownEventHandlerIfExists(_event.kbd);
@@ -216,9 +216,9 @@ void MediaStationEngine::processEvents() {
 		}
 
 		case Common::EVENT_LBUTTONDOWN: {
-			Asset *hotspot = findAssetToAcceptMouseEvents(_event.mouse);
+			Asset *hotspot = findAssetToAcceptMouseEvents();
 			if (hotspot != nullptr) {
-				debugC(1, kDebugEvents, "EVENT_LBUTTONDOWN (%d, %d): Sent to hotspot %d", _event.mouse.x, _event.mouse.y, hotspot->getHeader()->_id);
+				debugC(1, kDebugEvents, "EVENT_LBUTTONDOWN (%d, %d): Sent to hotspot %d", _mousePos.x, _mousePos.y, hotspot->getHeader()->_id);
 				hotspot->runEventHandlerIfExists(kMouseDownEvent);
 			}
 			break;
@@ -252,15 +252,15 @@ void MediaStationEngine::setCursor(uint id) {
 }
 
 void MediaStationEngine::refreshActiveHotspot() {
-	Asset *hotspot = findAssetToAcceptMouseEvents(_eventMan->getMousePos());
+	Asset *hotspot = findAssetToAcceptMouseEvents();
 	if (hotspot != _currentHotspot) {
 		if (_currentHotspot != nullptr) {
 			_currentHotspot->runEventHandlerIfExists(kMouseExitedEvent);
-			debugC(5, kDebugEvents, "EVENT_MOUSEMOVE (%d, %d): Exited hotspot %d", _event.mouse.x, _event.mouse.y, _currentHotspot->getHeader()->_id);
+			debugC(5, kDebugEvents, "refreshActiveHotspot(): (%d, %d): Exited hotspot %d", _mousePos.x, _mousePos.y, _currentHotspot->getHeader()->_id);
 		}
 		_currentHotspot = hotspot;
 		if (hotspot != nullptr) {
-			debugC(5, kDebugEvents, "EVENT_MOUSEMOVE (%d, %d): Entered hotspot %d", _event.mouse.x, _event.mouse.y, hotspot->getHeader()->_id);
+			debugC(5, kDebugEvents, "refreshActiveHotspot(): (%d, %d): Entered hotspot %d", _mousePos.x, _mousePos.y, hotspot->getHeader()->_id);
 			setCursor(hotspot->getHeader()->_cursorResourceId);
 			hotspot->runEventHandlerIfExists(kMouseEnteredEvent);
 		} else {
@@ -270,7 +270,7 @@ void MediaStationEngine::refreshActiveHotspot() {
 	}
 
 	if (hotspot != nullptr) {
-		debugC(5, kDebugEvents, "EVENT_MOUSEMOVE (%d, %d): Sent to hotspot %d", _event.mouse.x, _event.mouse.y, hotspot->getHeader()->_id);
+		debugC(5, kDebugEvents, "refreshActiveHotspot(): (%d, %d): Sent to hotspot %d", _mousePos.x, _mousePos.y, hotspot->getHeader()->_id);
 		hotspot->runEventHandlerIfExists(kMouseMovedEvent);
 	}
 }
@@ -463,7 +463,7 @@ void MediaStationEngine::releaseContext(uint32 contextId) {
 	_loadedContexts.erase(contextId);
 }
 
-Asset *MediaStationEngine::findAssetToAcceptMouseEvents(Common::Point point) {
+Asset *MediaStationEngine::findAssetToAcceptMouseEvents() {
 	Asset *intersectingAsset = nullptr;
 	// The z-indices seem to be reversed, so the highest z-index number is
 	// actually the lowest asset.
@@ -471,7 +471,8 @@ Asset *MediaStationEngine::findAssetToAcceptMouseEvents(Common::Point point) {
 
 	for (Asset *asset : _assetsPlaying) {
 		if (asset->type() == kAssetTypeHotspot) {
-			if (asset->isActive() && static_cast<Hotspot *>(asset)->isInside(point)) {
+			debugC(5, kDebugGraphics, "findAssetToAcceptMouseEvents(): Hotspot %d (z-index %d)", asset->getHeader()->_id, asset->zIndex());
+			if (asset->isActive() && static_cast<Hotspot *>(asset)->isInside(_mousePos)) {
 				if (asset->zIndex() < lowestZIndex) {
 					lowestZIndex = asset->zIndex();
 					intersectingAsset = asset;
diff --git a/engines/mediastation/mediastation.h b/engines/mediastation/mediastation.h
index 563f11d7b16..bc8dc9ef299 100644
--- a/engines/mediastation/mediastation.h
+++ b/engines/mediastation/mediastation.h
@@ -93,6 +93,7 @@ public:
 	Graphics::Screen *_screen = nullptr;
 	Context *_currentContext = nullptr;
 
+	Common::Point _mousePos;
 	Common::Array<Common::Rect> _dirtyRects;
 
 	// All Media Station titles run at 640x480.
@@ -124,7 +125,7 @@ private:
 	Context *loadContext(uint32 contextId);
 	void setPaletteFromHeader(AssetHeader *header);
 	void releaseContext(uint32 contextId);
-	Asset *findAssetToAcceptMouseEvents(Common::Point point);
+	Asset *findAssetToAcceptMouseEvents();
 
 	void effectTransition(Common::Array<Operand> &args);
 };


Commit: 3421caee82e1b1cd89ed5ee6bc81d68459f74d3b
    https://github.com/scummvm/scummvm/commit/3421caee82e1b1cd89ed5ee6bc81d68459f74d3b
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-13T18:54:03-04:00

Commit Message:
MEDIASTATION: Make local script vars accessible to sub-chunks

Changed paths:
    engines/mediastation/mediascript/codechunk.cpp
    engines/mediastation/mediascript/codechunk.h


diff --git a/engines/mediastation/mediascript/codechunk.cpp b/engines/mediastation/mediascript/codechunk.cpp
index cc853b295ed..252e9d7702d 100644
--- a/engines/mediastation/mediascript/codechunk.cpp
+++ b/engines/mediastation/mediascript/codechunk.cpp
@@ -29,13 +29,14 @@
 
 namespace MediaStation {
 
-CodeChunk::CodeChunk(Common::SeekableReadStream &chunk) : _args(nullptr) {
+CodeChunk::CodeChunk(Common::SeekableReadStream &chunk) {
 	uint lengthInBytes = Datum(chunk, kDatumTypeUint32_1).u.i;
 	debugC(5, kDebugLoading, "CodeChunk::CodeChunk(): Length 0x%x (@0x%llx)", lengthInBytes, static_cast<long long int>(chunk.pos()));
 	_bytecode = chunk.readStream(lengthInBytes);
 }
 
-Operand CodeChunk::execute(Common::Array<Operand> *args) {
+Operand CodeChunk::execute(Common::Array<Operand> *args, Common::Array<Operand> *locals) {
+	_locals = locals;
 	_args = args;
 	Operand returnValue;
 	while (_bytecode->pos() < _bytecode->size()) {
@@ -51,6 +52,12 @@ Operand CodeChunk::execute(Common::Array<Operand> *args) {
 	// We don't own the args, so we will prevent a potentially out-of-scope
 	// variable from being re-accessed.
 	_args = nullptr;
+
+	if (_weOwnLocals) {
+		delete _locals;
+	}
+	_locals = nullptr;
+
 	return returnValue;
 }
 
@@ -129,7 +136,9 @@ Operand CodeChunk::executeNextStatement() {
 		case kOpcodeDeclareVariables: {
 			uint32 localVariableCount = Datum(*_bytecode).u.i;
 			debugC(5, kDebugScript, "%d", localVariableCount);
-			_locals.resize(localVariableCount);
+			assert(_locals == nullptr);
+			_locals = new Common::Array<Operand>(localVariableCount);
+			_weOwnLocals = true;
 			return Operand();
 		}
 
@@ -176,11 +185,9 @@ Operand CodeChunk::executeNextStatement() {
 			// Doesn't seem like there is a real bool type for values,
 			// ao just get an integer.
 			if (condition.getInteger()) {
-				// TODO: If locals are modified in here, they won't be
-				// propagated up since it's its own code chunk.
-				ifBlock.execute(_args);
+				ifBlock.execute(_args, _locals);
 			} else {
-				elseBlock.execute(_args);
+				elseBlock.execute(_args, _locals);
 			}
 
 			// If blocks themselves shouldn't return anything.
@@ -415,7 +422,7 @@ Operand CodeChunk::getVariable(uint32 id, VariableScope scope) {
 
 	case kVariableScopeLocal: {
 		uint index = id - 1;
-		return _locals.operator[](index);
+		return _locals->operator[](index);
 	}
 
 	case kVariableScopeParameter: {
@@ -444,7 +451,7 @@ void CodeChunk::putVariable(uint32 id, VariableScope scope, Operand value) {
 
 	case kVariableScopeLocal: {
 		uint index = id - 1;
-		_locals[index] = value;
+		_locals->operator[](index) = value;
 		break;
 	}
 
@@ -503,6 +510,11 @@ CodeChunk::~CodeChunk() {
 	// We don't own the args, so we don't need to delete it.
 	_args = nullptr;
 
+	if (_weOwnLocals) {
+		delete _locals;
+	}
+	_locals = nullptr;
+
 	delete _bytecode;
 	_bytecode = nullptr;
 }
diff --git a/engines/mediastation/mediascript/codechunk.h b/engines/mediastation/mediascript/codechunk.h
index b9b8155842e..c38ff104ba8 100644
--- a/engines/mediastation/mediascript/codechunk.h
+++ b/engines/mediastation/mediascript/codechunk.h
@@ -37,7 +37,7 @@ public:
 	CodeChunk(Common::SeekableReadStream &chunk);
 	~CodeChunk();
 
-	Operand execute(Common::Array<Operand> *args = nullptr);
+	Operand execute(Common::Array<Operand> *args = nullptr, Common::Array<Operand> *locals = nullptr);
 
 private:
 	Operand executeNextStatement();
@@ -45,9 +45,10 @@ private:
 	Operand getVariable(uint32 id, VariableScope scope);
 	void putVariable(uint32 id, VariableScope scope, Operand value);
 
-	Common::Array<Operand> _locals;
-	Common::Array<Operand> *_args;
-	Common::SeekableReadStream *_bytecode;
+	bool _weOwnLocals = false;
+	Common::Array<Operand> *_locals = nullptr;
+	Common::Array<Operand> *_args = nullptr;
+	Common::SeekableReadStream *_bytecode = nullptr;
 };
 
 } // End of namespace MediaStation


Commit: c3b9cad220afbf0a78af839d343cbe5b46d076ae
    https://github.com/scummvm/scummvm/commit/c3b9cad220afbf0a78af839d343cbe5b46d076ae
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-13T18:54:03-04:00

Commit Message:
MEDIASTATION: Fix hotspot refresh recursion in scripts

Changed paths:
    engines/mediastation/assets/hotspot.cpp
    engines/mediastation/mediastation.cpp
    engines/mediastation/mediastation.h


diff --git a/engines/mediastation/assets/hotspot.cpp b/engines/mediastation/assets/hotspot.cpp
index f0ae58cd367..d0a2a0a169c 100644
--- a/engines/mediastation/assets/hotspot.cpp
+++ b/engines/mediastation/assets/hotspot.cpp
@@ -74,14 +74,14 @@ Operand Hotspot::callMethod(BuiltInMethod methodId, Common::Array<Operand> &args
 		assert(args.empty());
 		_isActive = true;
 		g_engine->addPlayingAsset(this);
-		g_engine->refreshActiveHotspot();
+		g_engine->_needsHotspotRefresh = true;
 		return Operand();
 	}
 
 	case kMouseDeactivateMethod: {
 		assert(args.empty());
 		_isActive = false;
-		g_engine->refreshActiveHotspot();
+		g_engine->_needsHotspotRefresh = true;
 		return Operand();
 	}
 
diff --git a/engines/mediastation/mediastation.cpp b/engines/mediastation/mediastation.cpp
index b84cbe56c80..28bff731ab3 100644
--- a/engines/mediastation/mediastation.cpp
+++ b/engines/mediastation/mediastation.cpp
@@ -171,6 +171,11 @@ Common::Error MediaStationEngine::run() {
 				break;
 			}
 
+			if (_needsHotspotRefresh) {
+				refreshActiveHotspot();
+				_needsHotspotRefresh = false;
+			}
+
 			if (!(*it)->isActive()) {
 				it = _assetsPlaying.erase(it);
 			} else {
@@ -201,7 +206,7 @@ void MediaStationEngine::processEvents() {
 
 		case Common::EVENT_MOUSEMOVE: {
 			_mousePos = g_system->getEventManager()->getMousePos();
-			refreshActiveHotspot();
+			_needsHotspotRefresh = true;
 			break;
 		}
 
diff --git a/engines/mediastation/mediastation.h b/engines/mediastation/mediastation.h
index bc8dc9ef299..dcc9b02c145 100644
--- a/engines/mediastation/mediastation.h
+++ b/engines/mediastation/mediastation.h
@@ -95,6 +95,7 @@ public:
 
 	Common::Point _mousePos;
 	Common::Array<Common::Rect> _dirtyRects;
+	bool _needsHotspotRefresh = false;
 
 	// All Media Station titles run at 640x480.
 	const uint16 SCREEN_WIDTH = 640;


Commit: 4d620f729a8c3ee1f3f90c27dcdada8a816eeb77
    https://github.com/scummvm/scummvm/commit/4d620f729a8c3ee1f3f90c27dcdada8a816eeb77
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-13T18:54:03-04:00

Commit Message:
MEDIASTATION: Stub another transition type

And downgrade unknown transition types to warnings, rather than errors.

Changed paths:
    engines/mediastation/transitions.cpp


diff --git a/engines/mediastation/transitions.cpp b/engines/mediastation/transitions.cpp
index afa2381774f..267e7066806 100644
--- a/engines/mediastation/transitions.cpp
+++ b/engines/mediastation/transitions.cpp
@@ -33,7 +33,8 @@ enum TransitionType {
 	kTransitionSetToPercentOfPalette = 306,
 	kTransitionFadeToPaletteObject = 307,
 	kTransitionSetToPaletteObject = 308,
-	kTransitionSetToPercentOfPaletteObject = 309
+	kTransitionSetToPercentOfPaletteObject = 309,
+	kTransitionCircleOut = 328
 };
 
 void MediaStationEngine::effectTransition(Common::Array<Operand> &args) {
@@ -84,8 +85,13 @@ void MediaStationEngine::effectTransition(Common::Array<Operand> &args) {
 		break;
 	}
 
+	case kTransitionCircleOut: {
+		warning("MediaStationEngine::effectTransition(): Circle out transition not implemented");
+		break;
+	}
+
 	default:
-		error("MediaStationEngine::effectTransition(): Got unknown transition type %d", static_cast<uint>(transitionType));
+		warning("MediaStationEngine::effectTransition(): Got unknown transition type %d", static_cast<uint>(transitionType));
 	}
 }
 


Commit: 9d717b633d7bf0c2c3b8846b5ef5d51a2474788b
    https://github.com/scummvm/scummvm/commit/9d717b633d7bf0c2c3b8846b5ef5d51a2474788b
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2025-03-13T18:54:03-04:00

Commit Message:
MEDIASTATION: Support referencing functions in variables

Changed paths:
    engines/mediastation/mediascript/codechunk.cpp
    engines/mediastation/mediascript/codechunk.h
    engines/mediastation/mediascript/operand.cpp
    engines/mediastation/mediascript/scriptconstants.cpp
    engines/mediastation/mediascript/scriptconstants.h
    engines/mediastation/mediascript/variable.cpp
    engines/mediastation/mediascript/variable.h


diff --git a/engines/mediastation/mediascript/codechunk.cpp b/engines/mediastation/mediascript/codechunk.cpp
index 252e9d7702d..159bbadd095 100644
--- a/engines/mediastation/mediascript/codechunk.cpp
+++ b/engines/mediastation/mediascript/codechunk.cpp
@@ -88,29 +88,11 @@ Operand CodeChunk::executeNextStatement() {
 			return Operand();
 		}
 
-		case kOpcodeCallRoutine: {
+		case kOpcodeCallFunction: {
 			uint functionId = Datum(*_bytecode).u.i;
 			uint32 parameterCount = Datum(*_bytecode).u.i;
-			Common::Array<Operand> args;
 			debugC(5, kDebugScript, "%d (%d params)", functionId, parameterCount);
-			for (uint i = 0; i < parameterCount; i++) {
-				debugCN(5, kDebugScript, "  Param %d: ", i);
-				Operand arg = executeNextStatement();
-				args.push_back(arg);
-			}
-
-			Operand returnValue;
-			Function *function = g_engine->getFunctionById(functionId);
-			if (function != nullptr) {
-				// This is a title-defined function.
-				returnValue = function->execute(args);
-			} else {
-				// This is a function built in (and global to) the engine.
-				BuiltInFunction builtInFunctionId = static_cast<BuiltInFunction>(functionId);
-				debugC(5, kDebugScript, "  Function Name: %s ", builtInFunctionToStr(builtInFunctionId));
-				returnValue = g_engine->callBuiltInFunction(builtInFunctionId, args);
-			}
-			return returnValue;
+			return callFunction(functionId, parameterCount);
 		}
 
 		case kOpcodeCallMethod: {
@@ -336,6 +318,15 @@ Operand CodeChunk::executeNextStatement() {
 			return value;
 		}
 
+		case kOpcodeCallFunctionInVariable: {
+			uint parameterCount = Datum(*_bytecode).u.i;
+			Operand variable = executeNextStatement();
+			uint functionId = variable.getFunctionId();
+			debugC(5, kDebugScript, "Variable %d [function %d] (%d params)", variable.getVariable()->_id, functionId, parameterCount);
+
+			return callFunction(functionId, parameterCount);
+		}
+
 		default:
 			error("CodeChunk::getNextStatement(): Got unimplemented opcode %s (%d)", opcodeToStr(opcode), static_cast<uint>(opcode));
 		}
@@ -379,7 +370,7 @@ Operand CodeChunk::executeNextStatement() {
 		}
 
 		case kOperandTypeString: {
-			// This is indeed a raw string anot not a string wrapped in a datum!
+			// This is indeed a raw string, not a string wrapped in a datum!
 			// TODO: This copies the string. Can we read it directly from the chunk?
 			int size = Datum(*_bytecode, kDatumTypeUint16_1).u.i;
 			char *buffer = new char[size + 1];
@@ -411,6 +402,29 @@ Operand CodeChunk::executeNextStatement() {
 	}
 }
 
+Operand CodeChunk::callFunction(uint functionId, uint parameterCount) {
+	Common::Array<Operand> args;
+	for (uint i = 0; i < parameterCount; i++) {
+		debugCN(5, kDebugScript, "  Param %d: ", i);
+		Operand arg = executeNextStatement();
+		args.push_back(arg);
+	}
+
+	Operand returnValue;
+	Function *function = g_engine->getFunctionById(functionId);
+	if (function != nullptr) {
+		// This is a title-defined function.
+		returnValue = function->execute(args);
+	} else {
+		// This is a function built in (and global to) the engine.
+		BuiltInFunction builtInFunctionId = static_cast<BuiltInFunction>(functionId);
+		debugC(5, kDebugScript, "  Function Name: %s ", builtInFunctionToStr(builtInFunctionId));
+		returnValue = g_engine->callBuiltInFunction(builtInFunctionId, args);
+	}
+
+	return returnValue;
+}
+
 Operand CodeChunk::getVariable(uint32 id, VariableScope scope) {
 	switch (scope) {
 	case kVariableScopeGlobal: {
diff --git a/engines/mediastation/mediascript/codechunk.h b/engines/mediastation/mediascript/codechunk.h
index c38ff104ba8..79031b17797 100644
--- a/engines/mediastation/mediascript/codechunk.h
+++ b/engines/mediastation/mediascript/codechunk.h
@@ -42,6 +42,7 @@ public:
 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);
 
diff --git a/engines/mediastation/mediascript/operand.cpp b/engines/mediastation/mediascript/operand.cpp
index 1f65dcf33b1..afe0c331fd9 100644
--- a/engines/mediastation/mediascript/operand.cpp
+++ b/engines/mediastation/mediascript/operand.cpp
@@ -181,6 +181,11 @@ uint Operand::getFunctionId() {
 		return _u.functionId;
 	}
 
+	case kOperandTypeVariableDeclaration: {
+		assert(_u.variable->_type == kVariableTypeFunction);
+		return _u.variable->_value.functionId;
+	}
+
 	default:
 		error("Operand::getFunction(): Attempt to get function ID from operand type %s (%d)",
 			operandTypeToStr(_type), static_cast<uint>(_type));
diff --git a/engines/mediastation/mediascript/scriptconstants.cpp b/engines/mediastation/mediascript/scriptconstants.cpp
index 7446848e9e8..be272355817 100644
--- a/engines/mediastation/mediascript/scriptconstants.cpp
+++ b/engines/mediastation/mediascript/scriptconstants.cpp
@@ -74,8 +74,8 @@ const char *opcodeToStr(Opcode opcode) {
 		return "%";
 	case kOpcodeNegate:
 		return "-";
-	case kOpcodeCallRoutine:
-		return "CallRoutine";
+	case kOpcodeCallFunction:
+		return "CallFunction";
 	case kOpcodeCallMethod:
 		return "CallMethod";
 	case kOpcodeDeclareVariables:
@@ -84,6 +84,8 @@ const char *opcodeToStr(Opcode opcode) {
 		return "Return";
 	case kOpcodeUnk1:
 		return "UNKNOWN (Unk1)";
+	case kOpcodeCallFunctionInVariable:
+		return "CallFunctionInVariable";
 	case kOpcodeWhile:
 		return "While";
 	default:
@@ -332,6 +334,8 @@ const char *operandTypeToStr(OperandType type) {
 		return "Collection";
 	case kOperandTypeFunction:
 		return "Function";
+	case kOperandTypeMethod:
+		return "Method";
 	default:
 		return "UNKNOWN";
 	}
@@ -341,6 +345,8 @@ const char *variableTypeToStr(VariableType type) {
 	switch (type) {
 	case kVariableTypeEmpty:
 		return "Empty";
+	case kVariableTypeFunction:
+		return "Function";
 	case kVariableTypeCollection:
 		return "Collection";
 	case kVariableTypeString:
diff --git a/engines/mediastation/mediascript/scriptconstants.h b/engines/mediastation/mediascript/scriptconstants.h
index d03d5672fb1..6f3d27f5b2f 100644
--- a/engines/mediastation/mediascript/scriptconstants.h
+++ b/engines/mediastation/mediascript/scriptconstants.h
@@ -50,7 +50,7 @@ enum Opcode {
 	kOpcodeDivide = 216,
 	kOpcodeModulo = 217,
 	kOpcodeNegate = 218,
-	kOpcodeCallRoutine = 219,
+	kOpcodeCallFunction = 219,
 	kOpcodeCallMethod = 220,
 	// This seems to appear at the start of a function to declare the number of
 	// local variables used in the function. It seems to be the `Declare`
@@ -60,7 +60,8 @@ enum Opcode {
 	kOpcodeDeclareVariables = 221,
 	kOpcodeWhile = 224,
 	kOpcodeReturn = 222,
-	kOpcodeUnk1 = 223
+	kOpcodeUnk1 = 223,
+	kOpcodeCallFunctionInVariable = 225
 };
 const char *opcodeToStr(Opcode opcode);
 
@@ -248,8 +249,9 @@ enum OperandType {
 	kOperandTypeDollarSignVariable = 155,
 	kOperandTypeAssetId = 156,
 	kOperandTypeVariableDeclaration = 158,
-	kOperandTypeCollection = 159,
-	kOperandTypeFunction = 160
+	kOperandTypeFunction = 159,
+	kOperandTypeMethod = 160,
+	kOperandTypeCollection = 161
 };
 const char *operandTypeToStr(OperandType type);
 
@@ -257,6 +259,7 @@ enum VariableType {
 	// This is an invalid type used for initialization only.
 	kVariableTypeEmpty = 0x0000,
 
+	kVariableTypeFunction = 0x0008,
 	kVariableTypeCollection = 0x0007,
 	kVariableTypeString = 0x0006,
 	kVariableTypeAssetId = 0x0005,
diff --git a/engines/mediastation/mediascript/variable.cpp b/engines/mediastation/mediascript/variable.cpp
index 1778105a702..c515993b22b 100644
--- a/engines/mediastation/mediascript/variable.cpp
+++ b/engines/mediastation/mediascript/variable.cpp
@@ -227,6 +227,12 @@ void Variable::putValue(Operand value) {
 		break;
 	}
 
+	case kOperandTypeFunction: {
+		_type = kVariableTypeFunction;
+		_value.functionId = value.getFunctionId();
+		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()));
diff --git a/engines/mediastation/mediascript/variable.h b/engines/mediastation/mediascript/variable.h
index f11e5367b33..a27d66c1c6f 100644
--- a/engines/mediastation/mediascript/variable.h
+++ b/engines/mediastation/mediascript/variable.h
@@ -45,6 +45,7 @@ public:
 	union {
 		Common::String *string;
 		Collection *collection;
+		uint functionId;
 		int i;
 		double d;
 		uint assetId;




More information about the Scummvm-git-logs mailing list