[Scummvm-git-logs] scummvm master -> 643b597b5482147b837c08a88142a0f7b6ed95a0
npjg
noreply at scummvm.org
Sun Oct 18 20:40:37 UTC 2026
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
28c92aafa7 MEDIASTATION: Implement saving game state as script value
aea6f62e04 MEDIASTATION: Fix text parameters that don't actually read anything
0ded9874d8 MEDIASTATION: Implement Barbie maze minigame
a6d5b9a66d MEDIASTATION: Fix duplicate sound state changes and event firing
1f994fed2e MEDIASTATION: Implement sound/stream locking for Pooh
643b597b54 MEDIASTATION: JANITORIAL: Fix some whitespaces
Commit: 28c92aafa7009c7b0d8edd0656b7d66a0b5218f3
https://github.com/scummvm/scummvm/commit/28c92aafa7009c7b0d8edd0656b7d66a0b5218f3
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2026-10-18T16:37:19-04:00
Commit Message:
MEDIASTATION: Implement saving game state as script value
This is not implemented further right now because only Barbie uses it.
Other games later on do use it, but these games also require a lot of
other work, so they'll be tackled later on.
Changed paths:
engines/mediastation/mediascript/function.cpp
engines/mediastation/mediascript/function.h
diff --git a/engines/mediastation/mediascript/function.cpp b/engines/mediastation/mediascript/function.cpp
index 3c7ebd154a5..08c640bd0f3 100644
--- a/engines/mediastation/mediascript/function.cpp
+++ b/engines/mediastation/mediascript/function.cpp
@@ -218,6 +218,7 @@ ScriptValue FunctionManager::call(uint functionId, Common::Array<ScriptValue> &a
break;
case kSetRegistryFunction:
+ FUNCARGCHECK(3);
script_SetRegistry(args, returnValue);
break;
@@ -589,16 +590,28 @@ void FunctionManager::script_SystemLanguagePreference(Common::Array<ScriptValue>
}
void FunctionManager::script_SetRegistry(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
- warning("STUB: %s", __func__);
+ Common::String registryName = args[0].asString();
+ Common::String registryKey = args[1].asString();
+ ScriptValue registryValue = args[2];
+
+ // TODO: Allow serializing these values to disk instead of just keeping them in memory.
+ if (!_registry.contains(registryName)) {
+ _registry[registryName] = Common::HashMap<Common::String, ScriptValue>();
+ }
+
+ _registry[registryName][registryKey] = registryValue;
}
void FunctionManager::script_GetRegistry(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
- // Even though this is basically still stubbed out, we need to set a return value or we will get errors.
- returnValue = args[2];
Common::String registryName = args[0].asString();
- if (registryName.size() != 0) {
- // TODO: Get the registry (saved game content) with this name.
- warning("STUB: %s: %s", __func__, registryName.c_str());
+ Common::String registryKey = args[1].asString();
+ ScriptValue defaultValue = args[2];
+
+ // TODO: Allow reading these values from disk.
+ if (_registry.contains(registryName) && _registry[registryName].contains(registryKey)) {
+ returnValue = _registry[registryName][registryKey];
+ } else {
+ returnValue = defaultValue;
}
}
diff --git a/engines/mediastation/mediascript/function.h b/engines/mediastation/mediascript/function.h
index bb2568df2ec..db24779187b 100644
--- a/engines/mediastation/mediascript/function.h
+++ b/engines/mediastation/mediascript/function.h
@@ -82,6 +82,7 @@ public:
private:
Common::HashMap<uint, ScriptFunction *> _functions;
uint32 _timedIntervalStartInMs = 0.0;
+ Common::HashMap<Common::String, Common::HashMap<Common::String, ScriptValue>> _registry;
void script_GetPlatform(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
void script_Random(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
Commit: aea6f62e041ad18f192c4707abc2c33dae0dc1e6
https://github.com/scummvm/scummvm/commit/aea6f62e041ad18f192c4707abc2c33dae0dc1e6
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2026-10-18T16:38:09-04:00
Commit Message:
MEDIASTATION: Fix text parameters that don't actually read anything
Changed paths:
engines/mediastation/actors/font.h
engines/mediastation/actors/text.cpp
diff --git a/engines/mediastation/actors/font.h b/engines/mediastation/actors/font.h
index ea6638aac16..27e7319731a 100644
--- a/engines/mediastation/actors/font.h
+++ b/engines/mediastation/actors/font.h
@@ -34,13 +34,12 @@ class FontCharacter : public PixMapImage {
public:
FontCharacter(Chunk &chunk, uint charCode, int horizontalSpacing, int baselineOffset, const ImageInfo &header);
- // Returns the ascent (baseline position). Falls back to full height if baseline offset is not specified.
int16 ascent() const { return (_baselineOffset != 0) ? _baselineOffset : height(); }
uint _charCode = 0;
int16 _horizontalSpacing = 0; // Additional horizontal spacing added after the glyph width to get total advance
private:
- int16 _baselineOffset = 0; // Baseline position within the glyph bitmap (ascent - distance from top edge to baseline)
+ int16 _baselineOffset = 0;
};
class FontActor : public Actor, public ChannelClient {
diff --git a/engines/mediastation/actors/text.cpp b/engines/mediastation/actors/text.cpp
index 43b18a1831a..f3da81518df 100644
--- a/engines/mediastation/actors/text.cpp
+++ b/engines/mediastation/actors/text.cpp
@@ -78,15 +78,15 @@ void TextActor::readParameter(Chunk &chunk, ActorHeaderSectionType paramType) {
break;
case kActorHeaderTextCursorIsVisible:
- _cursorIsVisible = static_cast<bool>(chunk.readTypedUint16());
+ _cursorIsVisible = true;
break;
case kActorHeaderTextConstrainToWidth:
- _constrainToWidth = static_cast<bool>(chunk.readTypedByte());
+ _constrainToWidth = true;
break;
case kActorHeaderTextOverwriteMode:
- _overwriteMode = static_cast<bool>(chunk.readTypedByte());
+ _overwriteMode = true;
break;
default:
Commit: 0ded9874d8284b2cd6ac3b55769ec0197482b72f
https://github.com/scummvm/scummvm/commit/0ded9874d8284b2cd6ac3b55769ec0197482b72f
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2026-10-18T16:38:09-04:00
Commit Message:
MEDIASTATION: Implement Barbie maze minigame
Assisted-by: claude-sonnet-5-5
Changed paths:
A engines/mediastation/minigames/barbiemaze.cpp
A engines/mediastation/minigames/barbiemaze.h
A engines/mediastation/minigames/dalmatiansmaze.cpp
A engines/mediastation/minigames/dalmatiansmaze.h
R engines/mediastation/minigames/maze.cpp
R engines/mediastation/minigames/maze.h
engines/mediastation/mediascript/function.cpp
engines/mediastation/mediascript/function.h
engines/mediastation/module.mk
diff --git a/engines/mediastation/mediascript/function.cpp b/engines/mediastation/mediascript/function.cpp
index 08c640bd0f3..5abbb8efa62 100644
--- a/engines/mediastation/mediascript/function.cpp
+++ b/engines/mediastation/mediascript/function.cpp
@@ -25,7 +25,8 @@
#include "mediastation/mediascript/function.h"
#include "mediastation/debugchannels.h"
#include "mediastation/mediastation.h"
-#include "mediastation/minigames/maze.h"
+#include "mediastation/minigames/dalmatiansmaze.h"
+#include "mediastation/minigames/barbiemaze.h"
#include "mediastation/minigames/checkers.h"
namespace MediaStation {
@@ -232,14 +233,17 @@ ScriptValue FunctionManager::call(uint functionId, Common::Array<ScriptValue> &a
break;
case kMazeGenerateFunction:
+ // Barbie only.
script_MazeGenerate(args, returnValue);
break;
case kMazeApplyMoveMaskFunction:
+ // Barbie only.
script_MazeApplyMoveMask(args, returnValue);
break;
case kMazeSolveFunction:
+ // Barbie and Dalmatians.
script_MazeSolve(args, returnValue);
break;
@@ -655,6 +659,34 @@ void FunctionManager::script_Drawing(Common::Array<ScriptValue> &args, ScriptVal
warning("STUB: %s", __func__);
}
+void FunctionManager::script_MazeSolve(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
+ if (args.size() == 0) {
+ // newMaze_clear (Dalmatians only).
+ delete _maze;
+ _maze = nullptr;
+
+ } else if (args.size() == 2) {
+ // newMaze_init (Dalmatians only).
+ delete _maze;
+ _maze = new MazeMinigame::Maze(args);
+
+ } else if (args.size() == 4) {
+ // newMaze_solve (Dalmatians only).
+ if (_maze != nullptr) {
+ _maze->solve(args, returnValue);
+ } else {
+ error("%s: Maze has not been initialized", __func__);
+ }
+
+ } else if (args.size() == 5) {
+ // Barbie only.
+ BarbieMazeMinigame::solve(args, returnValue);
+
+ } else {
+ error("%s: Got invalid number of args", __func__);
+ }
+}
+
void FunctionManager::deleteFunctionsForContext(uint contextId) {
// Collect function IDs to delete first.
Common::Array<ScriptFunction *> functionsToDelete;
diff --git a/engines/mediastation/mediascript/function.h b/engines/mediastation/mediascript/function.h
index db24779187b..2fd973b68f1 100644
--- a/engines/mediastation/mediascript/function.h
+++ b/engines/mediastation/mediascript/function.h
@@ -102,10 +102,10 @@ private:
void script_DebugPrint(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
void script_EffectTransition(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
- // 101 Dalmatians.
+ // Barbie.
void script_MazeGenerate(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
void script_MazeApplyMoveMask(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
- void script_MazeSolve(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
+ void script_MazeSolve(Common::Array<ScriptValue> &args, ScriptValue &returnValue); // Shared with Dalmatians.
void script_BeginTimedInterval(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
void script_EndTimedInterval(Common::Array<ScriptValue> &args, ScriptValue &returnValue);
diff --git a/engines/mediastation/minigames/barbiemaze.cpp b/engines/mediastation/minigames/barbiemaze.cpp
new file mode 100644
index 00000000000..c1d7336ce57
--- /dev/null
+++ b/engines/mediastation/minigames/barbiemaze.cpp
@@ -0,0 +1,317 @@
+/* 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 "mediastation/mediascript/collection.h"
+#include "mediastation/mediascript/function.h"
+#include "mediastation/mediastation.h"
+#include "mediastation/minigames/barbiemaze.h"
+
+namespace MediaStation {
+
+enum BarbieMazeDirectionMask {
+ kUp = 0x01,
+ kRight = 0x02,
+ kDown = 0x04,
+ kLeft = 0x08
+};
+
+void FunctionManager::script_MazeGenerate(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
+ if (args.size() < 2 || args.size() > 3) {
+ warning("%s: expected 2 to 3 arguments, got %d", __func__, args.size());
+ Collection *emptyCollection = new Collection();
+ returnValue.setToCollection(emptyCollection);
+ return;
+ }
+
+ // The original first creates a bitmap that shows where there is a wall,
+ // then later this bitmap is masked, so do the same here.
+ int16 width = static_cast<int16>(args[0].asFloat());
+ int16 height = static_cast<int16>(args[1].asFloat());
+ Common::Array<byte> mazeBitmap = BarbieMazeMinigame::doCreateMaze(width, height);
+
+ // Convert the maze bitmap into a mask of allowed movement directions for each cell.
+ // which is what scripts want to see.
+ Common::Array<byte> maskData = BarbieMazeMinigame::doMaskMaze(width, height, mazeBitmap);
+ Collection *result = new Collection();
+ for (byte b : maskData) {
+ ScriptValue value;
+ value.setToFloat(static_cast<double>(b));
+ result->push_back(value);
+ }
+ // Put the width and height at the end of the collection.
+ ScriptValue widthValue;
+ widthValue.setToFloat(static_cast<double>(width));
+ result->push_back(widthValue);
+ ScriptValue heightValue;
+ heightValue.setToFloat(static_cast<double>(height));
+ result->push_back(heightValue);
+
+ // The return value takes ownership of the collection.
+ returnValue.setToCollection(result);
+}
+
+void FunctionManager::script_MazeApplyMoveMask(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
+ if (args.size() != 3) {
+ warning("%s: Expected 3 arguments, got %d", __func__, args.size());
+ returnValue.setToFloat(-1.0);
+ return;
+ }
+
+ // A script told us where the user wants to move and gave us the maze direction mask
+ // at the user's current spot. Determine if the user can move to the new spot.
+ int16 xDirection = static_cast<int16>(args[0].asFloat());
+ int16 yDirection = static_cast<int16>(args[1].asFloat());
+ int16 possibleMoves = static_cast<int16>(args[2].asFloat());
+ int16 requestedMove = 0;
+ bool isHorizontalMoveRequested = (xDirection != 0);
+ if (isHorizontalMoveRequested) {
+ requestedMove |= 0x02;
+ }
+ bool isVerticalMoveRequested = (yDirection != 0);
+ if (isVerticalMoveRequested) {
+ requestedMove |= 0x04;
+ }
+
+ int16 allowedMoves = possibleMoves & requestedMove;
+ switch (allowedMoves) {
+ case 0x02:
+ // Horizontal movement allowed.
+ returnValue.setToFloat(4.0);
+ break;
+
+ case 0x04:
+ // Vertical movement allowed.
+ returnValue.setToFloat(2.0);
+ break;
+
+ case 0x06:
+ // Both horizontal and vertical allowed (diagonal).
+ returnValue.setToFloat(3.0);
+ break;
+
+ default:
+ // Movement not allowed or no movement requested.
+ returnValue.setToFloat(-1.0);
+ break;
+ }
+}
+
+Common::Array<byte> BarbieMazeMinigame::doCreateMaze(uint16 width, uint16 height) {
+ // The maze bitmap dimensions are double the playable dimensions because each wall
+ // must also be represented in the bitmap. 1 means wall, 0 means no wall.
+ uint16 mazeWidth = width * 2 + 1;
+ uint16 mazeHeight = height * 2 + 1;
+ Common::Array<byte> mazeBitmap(mazeWidth * mazeHeight);
+
+ // The outer border is always all wall.
+ for (uint16 y = 0; y < mazeHeight; y++) {
+ mazeBitmap[mazeWidth * y] = 1;
+ mazeBitmap[mazeWidth * y + (mazeWidth - 1)] = 1;
+ }
+ for (uint16 x = 0; x < mazeWidth; x++) {
+ mazeBitmap[x] = 1;
+ mazeBitmap[mazeWidth * (mazeHeight - 1) + x] = 1;
+ }
+
+ uint16 totalCellsRemaining = (height - 1) * (width - 1);
+ while (totalCellsRemaining > 0) {
+ // Pick a random unvisited cell by index.
+ uint16 targetCellIndex = g_engine->_randomSource.getRandomNumber(totalCellsRemaining - 1) + 1;
+
+ uint16 totalCellsSeen = 1;
+ for (uint16 x = 2; x < (mazeWidth - 1); x += 2) {
+ for (uint16 y = 2; y < (mazeHeight - 1); y += 2) {
+ bool isCellAlreadyVisited = (mazeBitmap[mazeWidth * y + x] != 0);
+ if (isCellAlreadyVisited) {
+ continue;
+ }
+
+ if (totalCellsSeen != targetCellIndex) {
+ totalCellsSeen++;
+ continue;
+ }
+
+ // Carve a random walk from this cell.
+ uint16 currentX = x;
+ uint16 currentY = y;
+ bool reachedVisitedCell = false;
+ while (!reachedVisitedCell) {
+ mazeBitmap[mazeWidth * currentY + currentX] = 1;
+ totalCellsRemaining--;
+
+ uint direction = g_engine->_randomSource.getRandomNumber(3);
+ switch (direction) {
+ case 0: // Right.
+ mazeBitmap[mazeWidth * currentY + currentX + 1] = 1;
+ currentX += 2;
+ break;
+
+ case 1: // Left.
+ mazeBitmap[mazeWidth * currentY + currentX - 1] = 1;
+ currentX -= 2;
+ break;
+
+ case 2: // Down.
+ mazeBitmap[mazeWidth * (currentY + 1) + currentX] = 1;
+ currentY += 2;
+ break;
+
+ default: // Up.
+ mazeBitmap[mazeWidth * (currentY - 1) + currentX] = 1;
+ currentY -= 2;
+ break;
+ }
+
+ reachedVisitedCell = (mazeBitmap[mazeWidth * currentY + currentX] != 0);
+ }
+
+ y = mazeHeight;
+ x = mazeWidth;
+ }
+ }
+ }
+ return mazeBitmap;
+}
+
+Common::Array<byte> BarbieMazeMinigame::doMaskMaze(uint16 width, uint16 height, Common::Array<byte> &mazeBitmap) {
+ uint16 maskSize = (width + 1) * (height + 1);
+ Common::Array<byte> maskData(maskSize);
+ uint16 mazeWidth = width * 2 + 1;
+
+ maskData[0] = kUp | kRight | kDown | kLeft;
+ for (uint16 y = 1; y <= height; y++) {
+ maskData[(width + 1) * y] = kUp | kDown | kLeft;
+ }
+ for (uint16 x = 1; x <= width; x++) {
+ maskData[x] = kRight | kDown | kLeft;
+ }
+
+ uint16 mazeX = 1;
+ for (uint16 x = 1; x <= width; x++) {
+ uint16 mazeY = 1;
+ for (uint16 y = 1; y <= height; y++) {
+ byte mask = 0;
+
+ if (mazeBitmap[mazeWidth * (mazeY - 1) + mazeX] == 0) {
+ mask |= kUp;
+ }
+ if (mazeBitmap[mazeWidth * mazeY + mazeX + 1] == 0) {
+ mask |= kRight;
+ }
+ if (mazeBitmap[mazeWidth * (mazeY + 1) + mazeX] == 0) {
+ mask |= kDown;
+ }
+ if (mazeBitmap[mazeWidth * mazeY + mazeX - 1] == 0) {
+ mask |= kLeft;
+ }
+
+ maskData[(width + 1) * y + x] = mask;
+ mazeY += 2;
+ }
+ mazeX += 2;
+ }
+ return maskData;
+}
+
+void BarbieMazeMinigame::solve(const Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
+ Collection *maskData = args[0].asCollection();
+ Common::Point startPos(
+ static_cast<int16>(args[1].asFloat()),
+ static_cast<int16>(args[2].asFloat()));
+ Common::Point endPos(
+ static_cast<int16>(args[3].asFloat()),
+ static_cast<int16>(args[4].asFloat()));
+ Common::Point mazeDimensions(
+ static_cast<int16>(maskData->operator[](maskData->size() - 2).asFloat() + 1),
+ static_cast<int16>(maskData->operator[](maskData->size() - 1).asFloat() + 1));
+
+ uint startIndex = startPos.y * mazeDimensions.x + startPos.x;
+ uint endIndex = endPos.y * mazeDimensions.x + endPos.x;
+
+ Collection *resultPath = new Collection;
+ if (startIndex == endIndex) {
+ ScriptValue endIndexValue;
+ endIndexValue.setToFloat(endIndex);
+ resultPath->push_back(endIndexValue);
+ } else {
+ Common::Array<uint> visitedPositions;
+ findShortestPath(*maskData, mazeDimensions, startIndex, endIndex, *resultPath, visitedPositions);
+ }
+
+ // The return value takes ownership of the collection.
+ returnValue.setToCollection(resultPath);
+}
+
+void BarbieMazeMinigame::findShortestPath(const Collection &maskData, Common::Point mazeDimensions,
+ uint startIndex, uint endIndex,
+ Collection &pathResult, Common::Array<uint> &visitedCells) {
+ for (uint visitedCellIndex : visitedCells) {
+ bool alreadyVisitedCell = (startIndex == visitedCellIndex);
+ if (alreadyVisitedCell) {
+ return;
+ }
+ }
+ visitedCells.push_back(startIndex);
+
+ bool hasReachedEnd = (startIndex == endIndex);
+ if (hasReachedEnd) {
+ bool isShorterThanBestPathSoFar = (pathResult.size() == 0 || visitedCells.size() < pathResult.size());
+ if (isShorterThanBestPathSoFar) {
+ pathResult.clear();
+ for (uint visitedIndex : visitedCells) {
+ ScriptValue nextPosIndexValue;
+ nextPosIndexValue.setToFloat(visitedIndex);
+ pathResult.push_back(nextPosIndexValue);
+ }
+ }
+
+ } else {
+ ScriptValue allowedDirectionsValue = maskData[startIndex];
+ uint16 allowedDirections = static_cast<uint16>(allowedDirectionsValue.asFloat());
+
+ if (allowedDirections & kLeft) {
+ findShortestPath(maskData, mazeDimensions,
+ startIndex - 1, endIndex,
+ pathResult, visitedCells);
+ }
+ if (allowedDirections & kDown) {
+ findShortestPath(maskData, mazeDimensions,
+ startIndex + mazeDimensions.x, endIndex,
+ pathResult, visitedCells);
+ }
+ if (allowedDirections & kRight) {
+ findShortestPath(maskData, mazeDimensions,
+ startIndex + 1, endIndex,
+ pathResult, visitedCells);
+ }
+ if (allowedDirections & kUp) {
+ findShortestPath(maskData, mazeDimensions,
+ startIndex - mazeDimensions.x, endIndex,
+ pathResult, visitedCells);
+ }
+ }
+
+ if (visitedCells.size() > 0) {
+ visitedCells.remove_at(visitedCells.size() - 1);
+ }
+}
+
+} // End of namespace MediaStation
diff --git a/engines/mediastation/minigames/barbiemaze.h b/engines/mediastation/minigames/barbiemaze.h
new file mode 100644
index 00000000000..84ce300ec49
--- /dev/null
+++ b/engines/mediastation/minigames/barbiemaze.h
@@ -0,0 +1,49 @@
+/* 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 MEDIASTATION_MINIGAMES_BARBIEMAZE_H
+#define MEDIASTATION_MINIGAMES_BARBIEMAZE_H
+
+#include "common/array.h"
+#include "common/rect.h"
+
+#include "mediastation/mediascript/scriptvalue.h"
+
+namespace MediaStation {
+
+class Collection;
+
+namespace BarbieMazeMinigame {
+
+void solve(const Common::Array<ScriptValue> &args, ScriptValue &returnValue);
+Common::Array<byte> doCreateMaze(uint16 width, uint16 height);
+Common::Array<byte> doMaskMaze(uint16 width, uint16 height, Common::Array<byte> &mazeBitmap);
+
+void findShortestPath(
+ const Collection &maskData, Common::Point mazeDimensions,
+ uint startIndex, uint endIndex,
+ Collection &pathResult, Common::Array<uint> &visitedPositions);
+
+} // End of namespace BarbieMazeMinigame
+
+} // End of namespace MediaStation
+
+#endif
diff --git a/engines/mediastation/minigames/maze.cpp b/engines/mediastation/minigames/dalmatiansmaze.cpp
similarity index 86%
rename from engines/mediastation/minigames/maze.cpp
rename to engines/mediastation/minigames/dalmatiansmaze.cpp
index 49f3ddde474..465963e95f4 100644
--- a/engines/mediastation/minigames/maze.cpp
+++ b/engines/mediastation/minigames/dalmatiansmaze.cpp
@@ -24,52 +24,10 @@
#include "mediastation/mediascript/function.h"
#include "mediastation/mediastation.h"
-#include "mediastation/minigames/maze.h"
+#include "mediastation/minigames/dalmatiansmaze.h"
namespace MediaStation {
-// Interestingly, the titles that have these maze functions don't seem to have
-// scripts that actually call them. Thus, for now only the maze functionality that
-// is known to be actually used is reimplemented, namely the overloaded script_MazeSolve
-// method and the methods it calls.
-void FunctionManager::script_MazeGenerate(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
- // Doesn't seem to be actually called by scripts.
- warning("STUB: %s", __func__);
-}
-
-void FunctionManager::script_MazeApplyMoveMask(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
- // Doesn't seem to be actually called by scripts.
- warning("STUB: %s", __func__);
-}
-
-void FunctionManager::script_MazeSolve(Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
- if (args.size() == 0) {
- // newMaze_clear
- delete _maze;
- _maze = nullptr;
-
- } else if (args.size() == 2) {
- // newMaze_init
- delete _maze;
- _maze = new MazeMinigame::Maze(args);
-
- } else if (args.size() == 4) {
- // newMaze_solve
- if (_maze != nullptr) {
- _maze->solve(args, returnValue);
- } else {
- error("%s: Maze has not been initialized", __func__);
- }
-
- } else if (args.size() == 5) {
- // Doesn't seem to be actually called by scripts.
- error("%s: This pathfinding code has not been implemented due to no known titles that use it", __func__);
-
- } else {
- error("%s: Got invalid number of args", __func__);
- }
-}
-
MazeMinigame::Maze::Maze(const Common::Array<ScriptValue> &args) {
Collection *gridDataCollection = args[0].asCollection();
// args[1] is the precomputed routing table, which we won't
diff --git a/engines/mediastation/minigames/maze.h b/engines/mediastation/minigames/dalmatiansmaze.h
similarity index 97%
rename from engines/mediastation/minigames/maze.h
rename to engines/mediastation/minigames/dalmatiansmaze.h
index 722108ad44d..5fb3cea58a3 100644
--- a/engines/mediastation/minigames/maze.h
+++ b/engines/mediastation/minigames/dalmatiansmaze.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef MEDIASTATION_MINIGAMES_MAZE_H
-#define MEDIASTATION_MINIGAMES_MAZE_H
+#ifndef MEDIASTATION_MINIGAMES_DALMATIANSMAZE_H
+#define MEDIASTATION_MINIGAMES_DALMATIANSMAZE_H
#include "mediastation/actor.h"
diff --git a/engines/mediastation/module.mk b/engines/mediastation/module.mk
index 4297c51c209..5ad64f3f5f1 100644
--- a/engines/mediastation/module.mk
+++ b/engines/mediastation/module.mk
@@ -38,11 +38,12 @@ MODULE_OBJS = \
mediascript/scriptvalue.o \
mediastation.o \
metaengine.o \
+ minigames/barbiemaze.o \
minigames/checkers.o \
+ minigames/dalmatiansmaze.o \
minigames/dotgame.o \
minigames/sophie.o \
minigames/stalkingzazu.o \
- minigames/maze.o \
profile.o
# This module can be built as a plugin
Commit: a6d5b9a66d1f300055db7704cabc9e78daa7dfc5
https://github.com/scummvm/scummvm/commit/a6d5b9a66d1f300055db7704cabc9e78daa7dfc5
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2026-10-18T16:38:09-04:00
Commit Message:
MEDIASTATION: Fix duplicate sound state changes and event firing
Changed paths:
engines/mediastation/actors/sound.cpp
diff --git a/engines/mediastation/actors/sound.cpp b/engines/mediastation/actors/sound.cpp
index 8c8c6229e73..7471cddc4a1 100644
--- a/engines/mediastation/actors/sound.cpp
+++ b/engines/mediastation/actors/sound.cpp
@@ -228,14 +228,11 @@ void SoundActor::start() {
}
openStream();
- _playState = kSoundPlayStatePlaying;
_startTime = g_engine->getTotalPlayTime();
_lastProcessedTime = 0;
setupNextScriptResponseTimer();
_sequence.start();
- ActorEvent actorEvent(_id, kSoundBeginEvent);
- g_engine->getEventLoop()->queueEvent(actorEvent);
} else {
warning("[%s] %s: Attempted to play sound before it was loaded", debugName(), __func__);
}
@@ -243,7 +240,6 @@ void SoundActor::start() {
void SoundActor::stop() {
if (_playState == kSoundPlayStatePlaying || _playState == kSoundPlayStatePaused) {
- _playState = kSoundPlayStateStopped;
_sequence.stop();
g_engine->getTimerService()->stopTimer(_timer);
}
Commit: 1f994fed2e18cd9b7b6ec6f3ecb9bcb251132f6e
https://github.com/scummvm/scummvm/commit/1f994fed2e18cd9b7b6ec6f3ecb9bcb251132f6e
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2026-10-18T16:38:09-04:00
Commit Message:
MEDIASTATION: Implement sound/stream locking for Pooh
Changed paths:
engines/mediastation/actors/diskimage.h
engines/mediastation/actors/document.cpp
engines/mediastation/actors/movie.cpp
engines/mediastation/actors/movie.h
engines/mediastation/actors/sound.cpp
engines/mediastation/actors/sound.h
engines/mediastation/clients.cpp
engines/mediastation/clients.h
engines/mediastation/mediastation.cpp
engines/mediastation/mediastation.h
diff --git a/engines/mediastation/actors/diskimage.h b/engines/mediastation/actors/diskimage.h
index d7de57f595c..98a6bffa750 100644
--- a/engines/mediastation/actors/diskimage.h
+++ b/engines/mediastation/actors/diskimage.h
@@ -25,6 +25,7 @@
#include "mediastation/actor.h"
#include "mediastation/bitmap.h"
#include "mediastation/datafile.h"
+#include "mediastation/clients.h"
#include "mediastation/mediascript/scriptvalue.h"
#include "mediastation/mediascript/scriptconstants.h"
@@ -47,13 +48,14 @@ struct StripImageNode {
// Despite the name from the original, this is not a "disk image" but
// a set of graphics (like a large background) that are streamed from
// disk in a very particular way.
-class DiskImageActor : public SpatialEntity, public ChannelClient {
+class DiskImageActor : public SpatialEntity, public ChannelClient, public ImtDeviceUser {
public:
DiskImageActor() : SpatialEntity(kActorTypeDiskImage) {};
~DiskImageActor();
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
+ virtual bool giveUpDevice() override { return false; }
virtual void onEvent(const ActorEvent &event) override;
virtual void timerEvent(const TimerEvent &event) override;
diff --git a/engines/mediastation/actors/document.cpp b/engines/mediastation/actors/document.cpp
index 8e961d598cc..2ba357182cc 100644
--- a/engines/mediastation/actors/document.cpp
+++ b/engines/mediastation/actors/document.cpp
@@ -21,6 +21,7 @@
#include "mediastation/mediastation.h"
#include "mediastation/actors/document.h"
+#include "mediastation/clients.h"
namespace MediaStation {
@@ -47,11 +48,17 @@ ScriptValue DocumentActor::callMethod(BuiltInMethod methodId, Common::Array<Scri
break;
}
- case kDocumentSetMultipleStreamsMethod:
+ case kDocumentSetMultipleStreamsMethod: {
+ ARGCOUNTCHECK(1);
+ bool allowMultipleStreams = args[0].asBool();
+ g_engine->getDeviceOwner()->setMultipleStreams(allowMultipleStreams);
+ break;
+ }
+
case kDocumentSetMultipleSoundsMethod: {
ARGCOUNTCHECK(1);
- bool value = args[0].asBool();
- warning("[%s] %s: STUB: %s: %d", debugName(), __func__, builtInMethodToStr(methodId), value);
+ bool allowMultipleSounds = args[0].asBool();
+ g_engine->getDeviceOwner()->setMultipleSounds(allowMultipleSounds);
break;
}
diff --git a/engines/mediastation/actors/movie.cpp b/engines/mediastation/actors/movie.cpp
index a15d6af4de2..3c93712f0cb 100644
--- a/engines/mediastation/actors/movie.cpp
+++ b/engines/mediastation/actors/movie.cpp
@@ -21,6 +21,7 @@
#include "mediastation/actors/movie.h"
#include "mediastation/debugchannels.h"
+#include "mediastation/clients.h"
#include "mediastation/mediastation.h"
namespace MediaStation {
@@ -91,6 +92,7 @@ MovieFrameImage::MovieFrameImage(Chunk &chunk, uint index, uint keyframeEndInMil
}
StreamMovieActor::~StreamMovieActor() {
+ g_engine->getDeviceOwner()->releaseDevice(this, kImtDeviceTypeSound);
unregisterWithStreamManager();
unregisterForSyncCalls();
if (_streamFeed != nullptr) {
@@ -337,6 +339,8 @@ ScriptValue StreamMovieActor::callMethod(BuiltInMethod methodId, Common::Array<S
void StreamMovieActor::onEvent(const ActorEvent &event) {
switch (event.type) {
case kMovieEndEvent:
+ g_engine->getDeviceOwner()->releaseDevice(this, kImtDeviceTypeSound);
+ _isPlaying = false;
triggerRemainingTimerEvents();
break;
@@ -351,6 +355,7 @@ void StreamMovieActor::onEvent(const ActorEvent &event) {
case kMovieStoppedEvent:
case kMovieAbortEvent:
case kMovieFailureEvent:
+ g_engine->getDeviceOwner()->releaseDevice(this, kImtDeviceTypeSound);
_isPlaying = false;
break;
@@ -368,16 +373,28 @@ void StreamMovieActor::timerEvent(const TimerEvent &event) {
setupNextScriptResponseTimer();
}
+bool StreamMovieActor::giveUpDevice() {
+ debugC(5, kDebugEvents, "[%s] %s: Stopping playback to give up sound device", debugName(), __func__);
+ timeStop(false);
+ return false;
+}
+
void StreamMovieActor::timePlay() {
- if (_streamFeed == nullptr) {
- _streamFeed = g_engine->getStreamFeedManager()->openStreamFeed(_id);
- _streamFeed->readData();
+ if (_isPlaying) {
+ return;
}
- if (_isPlaying) {
+ bool deviceGrantFailed = g_engine->getDeviceOwner()->grantDevice(this, kImtDeviceTypeSound);
+ if (deviceGrantFailed) {
+ warning("[%s] %s: Device grant failed", debugName(), __func__);
return;
}
+ if (_streamFeed == nullptr) {
+ _streamFeed = g_engine->getStreamFeedManager()->openStreamFeed(_id);
+ _streamFeed->readData();
+ }
+
setupNextScriptResponseTimer();
registerForSyncCalls();
_streamSound->getAudioSequence().start();
@@ -406,6 +423,7 @@ void StreamMovieActor::timeStop(bool isMovieEnd) {
}
_isPlaying = false;
+ g_engine->getDeviceOwner()->releaseDevice(this, kImtDeviceTypeSound);
_streamSound->getAudioSequence().stop();
g_engine->getTimerService()->stopTimer(_timer);
unregisterForSyncCalls();
diff --git a/engines/mediastation/actors/movie.h b/engines/mediastation/actors/movie.h
index a8f76244033..a5f9f03e10e 100644
--- a/engines/mediastation/actors/movie.h
+++ b/engines/mediastation/actors/movie.h
@@ -28,6 +28,7 @@
#include "mediastation/audio.h"
#include "mediastation/datafile.h"
#include "mediastation/bitmap.h"
+#include "mediastation/clients.h"
#include "mediastation/mediascript/scriptconstants.h"
namespace MediaStation {
@@ -128,7 +129,7 @@ private:
StreamMovieActor *_parent = nullptr;
};
-class StreamMovieActor : public SpatialEntity, public ChannelClient, public PreDisplaySyncClient {
+class StreamMovieActor : public SpatialEntity, public ChannelClient, public PreDisplaySyncClient, public ImtDeviceUser {
friend class StreamMovieActorFrames;
friend class StreamMovieActorSound;
@@ -141,6 +142,7 @@ public:
virtual void readParameter(Chunk &chunk, ActorHeaderSectionType paramType) override;
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
virtual bool isActive() const override { return _isPlaying; }
+ virtual bool giveUpDevice() override;
virtual PreDisplaySyncState preDisplaySync() override;
virtual void onEvent(const ActorEvent &event) override;
@@ -170,6 +172,8 @@ private:
Common::SortedArray<MovieFrame *, const MovieFrame *> _framesOnScreen;
// Script method implementations.
+ bool grantStreamDevice();
+ void releaseStreamDevice();
void timePlay();
void timeStop(bool isMovieEnd);
diff --git a/engines/mediastation/actors/sound.cpp b/engines/mediastation/actors/sound.cpp
index 7471cddc4a1..8b8aa2395f7 100644
--- a/engines/mediastation/actors/sound.cpp
+++ b/engines/mediastation/actors/sound.cpp
@@ -22,11 +22,16 @@
#include "mediastation/audio.h"
#include "mediastation/debugchannels.h"
#include "mediastation/actors/sound.h"
+#include "mediastation/clients.h"
#include "mediastation/mediastation.h"
namespace MediaStation {
SoundActor::~SoundActor() {
+ if (_playState == kSoundPlayStatePlaying) {
+ stop();
+ }
+
unregisterWithStreamManager();
if (_streamFeed != nullptr) {
g_engine->getStreamFeedManager()->closeStreamFeed(_streamFeed);
@@ -87,6 +92,7 @@ void SoundActor::soundPlayStateChanged(SoundPlayState state, SoundStopReason sto
case kSoundPlayStateStopped: {
_playState = kSoundPlayStateStopped;
g_engine->getTimerService()->stopTimer(_timer);
+ g_engine->getDeviceOwner()->releaseDevice(this, kImtDeviceTypeSound);
EventType eventType = kEventTypeInvalid;
switch (stopReason) {
@@ -221,17 +227,28 @@ void SoundActor::timerEvent(const TimerEvent &event) {
setupNextScriptResponseTimer();
}
+bool SoundActor::giveUpDevice() {
+ debugC(5, kDebugEvents, "[%s] %s: Stopping playback to give up sound device", debugName(), __func__);
+ stop();
+ return false;
+}
+
void SoundActor::start() {
if (_loadIsComplete) {
if (_playState == kSoundPlayStatePlaying || _playState == kSoundPlayStatePaused) {
stop();
}
- openStream();
- _startTime = g_engine->getTotalPlayTime();
- _lastProcessedTime = 0;
- setupNextScriptResponseTimer();
- _sequence.start();
+ bool deviceGrantFailed = g_engine->getDeviceOwner()->grantDevice(this, kImtDeviceTypeSound);
+ if (!deviceGrantFailed) {
+ openStream();
+ _startTime = g_engine->getTotalPlayTime();
+ _lastProcessedTime = 0;
+ setupNextScriptResponseTimer();
+ _sequence.start();
+ } else {
+ warning("[%s] %s: Device grant failed", debugName(), __func__);
+ }
} else {
warning("[%s] %s: Attempted to play sound before it was loaded", debugName(), __func__);
@@ -250,13 +267,19 @@ void SoundActor::pause() {
_sequence.pause();
_sequence.sleep();
// There don't seem to be script events to trigger in this instance.
+ g_engine->getDeviceOwner()->releaseDevice(this, kImtDeviceTypeSound);
}
}
void SoundActor::resume(bool restart) {
if (_playState == kSoundPlayStatePaused) {
- _sequence.awake();
- _sequence.resume();
+ bool deviceGrantFailed = g_engine->getDeviceOwner()->grantDevice(this, kImtDeviceTypeSound);
+ if (!deviceGrantFailed) {
+ _sequence.awake();
+ _sequence.resume();
+ } else {
+ warning("[%s] %s: Device grant failed", debugName(), __func__);
+ }
} else if (restart) {
start();
}
diff --git a/engines/mediastation/actors/sound.h b/engines/mediastation/actors/sound.h
index 7d1a5d604b8..cfb613ec374 100644
--- a/engines/mediastation/actors/sound.h
+++ b/engines/mediastation/actors/sound.h
@@ -25,12 +25,13 @@
#include "mediastation/actor.h"
#include "mediastation/audio.h"
#include "mediastation/datafile.h"
+#include "mediastation/clients.h"
#include "mediastation/mediascript/scriptvalue.h"
#include "mediastation/mediascript/scriptconstants.h"
namespace MediaStation {
-class SoundActor : public Actor, public ChannelClient, public SoundClient {
+class SoundActor : public Actor, public ChannelClient, public SoundClient, public ImtDeviceUser {
public:
SoundActor() : Actor(kActorTypeSound), _sequence(this) {};
~SoundActor();
@@ -39,6 +40,7 @@ public:
virtual ScriptValue callMethod(BuiltInMethod methodId, Common::Array<ScriptValue> &args) override;
virtual void readChunk(Chunk &chunk) override;
virtual bool isActive() const override { return _playState == kSoundPlayStatePlaying; }
+ virtual bool giveUpDevice() override;
virtual void onEvent(const ActorEvent &event) override;
virtual void timerEvent(const TimerEvent &event) override;
diff --git a/engines/mediastation/clients.cpp b/engines/mediastation/clients.cpp
index 2d1982661f6..f859a939c78 100644
--- a/engines/mediastation/clients.cpp
+++ b/engines/mediastation/clients.cpp
@@ -28,6 +28,7 @@
#include "mediastation/mediastation.h"
namespace MediaStation {
+
ParameterClient::ParameterClient() {
g_engine->getImtGod()->registerParameterClient(this);
}
@@ -36,16 +37,25 @@ ParameterClient::~ParameterClient() {
g_engine->getImtGod()->unregisterParameterClient(this);
}
+ImtDeviceOwner::ImtDeviceOwner() : ParameterClient() {
+ _deviceUsers.getOrCreateVal(kImtDeviceTypeSound);
+ _deviceUsers.getOrCreateVal(kImtDeviceTypeStream);
+}
+
bool ImtDeviceOwner::attemptToReadFromStream(Chunk &chunk, uint sectionType) {
bool handledParam = true;
switch (sectionType) {
- case kDeviceOwnerAllowMultipleSounds:
- _allowMultipleSounds = chunk.readTypedByte();
+ case kDeviceOwnerAllowMultipleSounds: {
+ bool allowMultipleSounds = (chunk.readTypedByte() == 1);
+ setMultipleSounds(allowMultipleSounds);
break;
+ }
- case kDeviceOwnerAllowMultipleStreams:
- _allowMultipleStreams = chunk.readTypedByte();
+ case kDeviceOwnerAllowMultipleStreams: {
+ bool allowMultipleStreams = (chunk.readTypedByte() == 1);
+ setMultipleStreams(allowMultipleStreams);
break;
+ }
default:
handledParam = false;
@@ -54,6 +64,90 @@ bool ImtDeviceOwner::attemptToReadFromStream(Chunk &chunk, uint sectionType) {
return handledParam;
}
+bool ImtDeviceOwner::hasExclusiveAccessTo(ImtDeviceType type) {
+ switch (type) {
+ case kImtDeviceTypeSound:
+ return _exclusiveAccessToSounds;
+
+ case kImtDeviceTypeStream:
+ return _exclusiveAccessToStreams;
+
+ default:
+ return true;
+ }
+}
+
+bool ImtDeviceOwner::grantDevice(ImtDeviceUser *user, ImtDeviceType type) {
+ // The original returns false on success, true on failure... maybe we should flip
+ // that around to be more readable, but I'm keeping it as the original had it for now.
+ if (hasExclusiveAccessTo(type)) {
+ Common::Array<ImtDeviceUser *> &deviceUsers = _deviceUsers.getVal(type);
+ for (ImtDeviceUser *existingUser : deviceUsers) {
+ if (user == existingUser) {
+ // We have already been granted this device.
+ return false;
+ }
+
+ // If the device is already in use, see if the existing user will give it up.
+ bool existingUserRejectedDeviceRelease = existingUser->giveUpDevice();
+ if (existingUserRejectedDeviceRelease) {
+ return true;
+ }
+ }
+
+ _deviceUsers[type].clear();
+ }
+
+ _deviceUsers[type].push_back(user);
+ return false;
+}
+
+void ImtDeviceOwner::releaseDevice(ImtDeviceUser *user, ImtDeviceType type) {
+ // The original does NOT call giveUpDevice here but seems like it should...
+ Common::Array<ImtDeviceUser *> &deviceUsers = _deviceUsers.getVal(type);
+ for (uint i = 0; i < deviceUsers.size(); ++i) {
+ if (deviceUsers[i] == user) {
+ deviceUsers.remove_at(i);
+ break;
+ }
+ }
+}
+
+bool ImtDeviceOwner::releaseAll() {
+ if (hasExclusiveAccessTo(kImtDeviceTypeSound) || hasExclusiveAccessTo(kImtDeviceTypeStream)) {
+ for (auto &deviceUserNode : _deviceUsers) {
+ for (ImtDeviceUser *deviceUser : deviceUserNode._value) {
+ deviceUser->giveUpDevice();
+ }
+ }
+ }
+ _deviceUsers.clear();
+ return true;
+}
+
+void ImtDeviceOwner::setMultipleSounds(bool allowMultipleSounds) {
+ if (allowMultipleSounds) {
+ _exclusiveAccessToSounds = false;
+ forceReleaseDevice(kImtDeviceTypeSound);
+ } else {
+ releaseAll();
+ _exclusiveAccessToSounds = true;
+ }
+}
+
+void ImtDeviceOwner::setMultipleStreams(bool allowMultipleStreams) {
+ if (allowMultipleStreams) {
+ _exclusiveAccessToStreams = false;
+ forceReleaseDevice(kImtDeviceTypeStream);
+ } else {
+ releaseAll();
+ _exclusiveAccessToStreams = true;
+ }
+}
+
+void ImtDeviceOwner::forceReleaseDevice(ImtDeviceType type) {
+ _deviceUsers[type].clear();
+}
bool Document::attemptToReadFromStream(Chunk &chunk, uint sectionType) {
bool handledParam = true;
@@ -73,6 +167,10 @@ bool Document::attemptToReadFromStream(Chunk &chunk, uint sectionType) {
return handledParam;
}
+bool Document::giveUpDevice() {
+ return true;
+}
+
void Document::readStartupInformation(Chunk &chunk) {
DocumentSectionType sectionType = static_cast<DocumentSectionType>(chunk.readTypedUint16());
debugC(5, kDebugLoading, "%s: sectionType = 0x%x", __func__, static_cast<uint>(sectionType));
diff --git a/engines/mediastation/clients.h b/engines/mediastation/clients.h
index 6b0894567ea..eb8695c8cae 100644
--- a/engines/mediastation/clients.h
+++ b/engines/mediastation/clients.h
@@ -22,6 +22,9 @@
#ifndef MEDIASTATION_CLIENTS_H
#define MEDIASTATION_CLIENTS_H
+#include "common/array.h"
+#include "common/hashmap.h"
+
#include "mediastation/datafile.h"
namespace MediaStation {
@@ -41,12 +44,44 @@ enum DeviceOwnerSectionType {
kDeviceOwnerAllowMultipleStreams = 0x36,
};
+enum ImtDeviceType {
+ kImtDeviceTypeSound = 2,
+ kImtDeviceTypeStream = 3,
+};
+
+class ImtDeviceUser {
+public:
+ virtual ~ImtDeviceUser() {};
+ virtual bool giveUpDevice() = 0;
+
+ void grantDevice(ImtDeviceType type);
+ void releaseDevice(ImtDeviceType type);
+};
+
+// Pooh scripts rely on a sound mutex to stop overlapping sounds/movies.
+// Pooh is the only known title that relies on this behavior, and no known
+// titles rely on the stream mutex behavior, but it is present in the original
+// so is implemnted here.
class ImtDeviceOwner : public ParameterClient {
public:
+ ImtDeviceOwner();
virtual bool attemptToReadFromStream(Chunk &chunk, uint sectionType) override;
- bool _allowMultipleSounds = false;
- bool _allowMultipleStreams = false;
+ bool hasExclusiveAccessTo(ImtDeviceType type);
+ bool grantDevice(ImtDeviceUser *user, ImtDeviceType type);
+ void releaseDevice(ImtDeviceUser *user, ImtDeviceType type);
+ bool releaseAll();
+
+ void setMultipleSounds(bool allowMultipleSounds);
+ void setMultipleStreams(bool allowMultipleStreams);
+
+private:
+ bool _exclusiveAccessToSounds = true;
+ bool _exclusiveAccessToStreams = true;
+
+ void forceReleaseDevice(ImtDeviceType type);
+
+ Common::HashMap<uint, Common::Array<ImtDeviceUser *>> _deviceUsers;
};
enum DocumentSectionType {
@@ -55,11 +90,12 @@ enum DocumentSectionType {
kDocumentEntryScreen = 0x2f,
};
-class Document : public ParameterClient {
+class Document : public ParameterClient, public ImtDeviceUser {
friend class Debugger;
public:
virtual bool attemptToReadFromStream(Chunk &chunk, uint sectionType) override;
+ virtual bool giveUpDevice() override;
void readStartupInformation(Chunk &chunk);
void readContextLoadComplete(Chunk &chunk);
diff --git a/engines/mediastation/mediastation.cpp b/engines/mediastation/mediastation.cpp
index 8d756103dd7..2aa7deda1e1 100644
--- a/engines/mediastation/mediastation.cpp
+++ b/engines/mediastation/mediastation.cpp
@@ -27,6 +27,7 @@
#include "mediastation/detection.h"
#include "mediastation/boot.h"
#include "mediastation/context.h"
+#include "mediastation/clients.h"
#include "mediastation/actor.h"
#include "mediastation/actors/document.h"
#include "mediastation/actors/movie.h"
diff --git a/engines/mediastation/mediastation.h b/engines/mediastation/mediastation.h
index cb75da019af..d11cc521f4d 100644
--- a/engines/mediastation/mediastation.h
+++ b/engines/mediastation/mediastation.h
@@ -58,6 +58,7 @@ class HotspotActor;
class RootStage;
class PixMapImage;
class ImtGod;
+class ImtDeviceOwner;
class EventLoop;
class Debugger;
@@ -102,6 +103,7 @@ public:
Document *getDocument() { return _document; }
TimerService *getTimerService() { return _timerService; }
ImtGod *getImtGod() { return _imtGod; }
+ ImtDeviceOwner *getDeviceOwner() { return _deviceOwner; }
void registerAudioSequence(AudioSequence *sequence);
void unregisterAudioSequence(AudioSequence *sequence);
Commit: 643b597b5482147b837c08a88142a0f7b6ed95a0
https://github.com/scummvm/scummvm/commit/643b597b5482147b837c08a88142a0f7b6ed95a0
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2026-10-18T16:38:09-04:00
Commit Message:
MEDIASTATION: JANITORIAL: Fix some whitespaces
Changed paths:
engines/mediastation/mediascript/function.h
engines/mediastation/minigames/dalmatiansmaze.cpp
engines/mediastation/minigames/stalkingzazu.cpp
diff --git a/engines/mediastation/mediascript/function.h b/engines/mediastation/mediascript/function.h
index 2fd973b68f1..72107565808 100644
--- a/engines/mediastation/mediascript/function.h
+++ b/engines/mediastation/mediascript/function.h
@@ -55,11 +55,11 @@ private:
};
namespace MazeMinigame {
- class Maze;
+class Maze;
} // End of namespace MazeMinigame
namespace CheckersMinigame {
- class Checkers;
+class Checkers;
} // End of namespace CheckersMinigame
class FunctionManager : public ParameterClient {
diff --git a/engines/mediastation/minigames/dalmatiansmaze.cpp b/engines/mediastation/minigames/dalmatiansmaze.cpp
index 465963e95f4..8f133fac5f4 100644
--- a/engines/mediastation/minigames/dalmatiansmaze.cpp
+++ b/engines/mediastation/minigames/dalmatiansmaze.cpp
@@ -93,9 +93,9 @@ MazeMinigame::CellGraphType MazeMinigame::Cell::getType() const {
default:
warning("%s: Unexpected direction mask 0x%x", __func__, _directionMask);
break;
- }
+ }
- return result;
+ return result;
}
void MazeMinigame::Maze::solve(const Common::Array<ScriptValue> &args, ScriptValue &returnValue) {
diff --git a/engines/mediastation/minigames/stalkingzazu.cpp b/engines/mediastation/minigames/stalkingzazu.cpp
index 46fa378b786..6f387adf41d 100644
--- a/engines/mediastation/minigames/stalkingzazu.cpp
+++ b/engines/mediastation/minigames/stalkingzazu.cpp
@@ -34,7 +34,7 @@ namespace MediaStation {
namespace StalkingZazuMinigame {
Direction::Direction(uint directionToken) {
- switch(directionToken) {
+ switch (directionToken) {
case 0x44c:
_value = Direction::kWest;
break;
@@ -979,8 +979,8 @@ Direction StalkingZazuActor::directionOfVector(const Common::Point &dest) {
if (angle >= 90.0) return Direction::kWest;
else if (angle >= -22.5) return Direction::kEast;
else if (angle >= -67.5) return Direction::kNorthEast;
- else if (angle >=-112.5) return Direction::kNorth;
- else if (angle >=-157.5) return Direction::kNorthWest;
+ else if (angle >= -112.5) return Direction::kNorth;
+ else if (angle >= -157.5) return Direction::kNorthWest;
else return Direction::kWest;
}
More information about the Scummvm-git-logs
mailing list