[Scummvm-git-logs] scummvm master -> e2499efec78921f3068c6f1846f6687146df6784
mgerhardy
noreply at scummvm.org
Wed Sep 2 16:04:29 UTC 2026
This automated email contains information about 14 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
bc90aca7eb MACS2: const + removed static function variable
3dac60c683 MACS2: formatting cleanup and const
9f955ecc23 MACS2: const + extract to local variable
183e229f71 MACS2: const + formatting
d5ba0756b4 MACS2: extract to local var
794eb6fd91 MACS2: renamed method and order members to reduce size
bdca62eb7c MACS2: convert object orientation into an enum
3f2d5d909d MACS2: cleanup + const
654a6a8e71 MACS2: cleanup + const
eb8a08731b MACS2: savegame fixes
241e39db0e MACS2: removed unused method
5e961c336a MACS2: _offset is not used - _bgAnimTickCounter is the palette cycling counter
47d77eef7f MACS2: moved object names
e2499efec7 MACS2: translations are only supported for the full game
Commit: bc90aca7eb66c33e1d7c1169c2f4e51f174fee04
https://github.com/scummvm/scummvm/commit/bc90aca7eb66c33e1d7c1169c2f4e51f174fee04
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:12+02:00
Commit Message:
MACS2: const + removed static function variable
fixes issues on restarting the engine
Changed paths:
engines/macs2/macs2.cpp
engines/macs2/macs2.h
engines/macs2/music.cpp
engines/macs2/music.h
diff --git a/engines/macs2/macs2.cpp b/engines/macs2/macs2.cpp
index c56e13840c4..b39ecbd5753 100644
--- a/engines/macs2/macs2.cpp
+++ b/engines/macs2/macs2.cpp
@@ -1047,8 +1047,6 @@ bool Macs2Engine::loadSceneGraphicsV1(uint32 sceneIndex) {
const uint32 newSceneIndex = sceneIndex;
// Background image
- // [0752h] is pointing to 3000h bytes data starting at Ch + 4h in the file
- // Addressing the background image starts at l0037_25A9
_fileStream->seek(0xC + 0x4 + 0xC * newSceneIndex - 0xC, SEEK_SET);
uint32 bgImageOffset = _fileStream->readUint32LE();
uint32 sceneTableEntry2 = _fileStream->readUint32LE();
@@ -1056,8 +1054,7 @@ bool Macs2Engine::loadSceneGraphicsV1(uint32 sceneIndex) {
(void)sceneTableEntry3; // strings offset, not used here
_mapSubSceneTableFilePos = 0;
_mapImageFileOffset = 0;
- // The map image file offset is stored in the scene data block at offset +0x3C0.
- // (sceneDataOffset2 + 0x3C0 = resource_offsets(0x80) + 0x340 of additional data).
+ // The map image file offset is stored in the scene data block
if (sceneTableEntry2 != 0 && sceneTableEntry2 < (uint32)_fileStream->size()) {
_fileStream->seek(sceneTableEntry2 + 0x3C0, SEEK_SET);
uint32 mapOffset = _fileStream->readUint32LE();
@@ -1119,22 +1116,20 @@ bool Macs2Engine::loadSceneGraphicsV1(uint32 sceneIndex) {
_fileStream->readByte(); // unknownByte2
_fileStream->readByte(); // unknownByte3
- // Offset 1013h
Graphics::ManagedSurface depthRLE = readRLEImage(_fileStream->pos(), _fileStream);
// Confirmed: depth map at scene offset 0x1013
_depthMap.blitFrom(depthRLE);
_sceneDepthMap.copyFrom(_depthMap);
- // Offset 2017h
Graphics::ManagedSurface pathfindingRLE = readRLEImage(_fileStream->pos(), _fileStream);
// Walkability/pathfinding map at scene offset 0x2017
_pathfindingMap.blitFrom(pathfindingRLE);
- // Offset 301Bh - Shadow/shading intensity map for character rendering
+ // Shadow/shading intensity map for character rendering
Graphics::ManagedSurface shadowRLE = readRLEImage(_fileStream->pos(), _fileStream);
_shadowMap.blitFrom(shadowRLE);
- // Offset 401Fh - Hotspot/interaction map (320x200, pixel value = hotspot color index)
+ // Hotspot/interaction map (320x200, pixel value = hotspot color index)
Graphics::ManagedSurface bgMap = readRLEImage(_fileStream->pos(), _fileStream);
_hotspotMap.copyFrom(bgMap);
@@ -1165,7 +1160,6 @@ bool Macs2Engine::loadSceneGraphicsV1(uint32 sceneIndex) {
readBackgroundAnimations(_fileStream);
updateAllBackgroundAnimationDepthMaps();
- // Offset 51F7h
_numPathfindingPoints = _fileStream->readUint16LE();
// Offset 51F9h
@@ -1174,7 +1168,6 @@ bool Macs2Engine::loadSceneGraphicsV1(uint32 sceneIndex) {
// Offset 51FBh
_fileStream->readUint16LE();
- // Offset 51FDh - 5201h
_walkDepthThresholdY = _fileStream->readUint16LE();
_walkDepthScaleFactor = _fileStream->readUint16LE();
_walkBaseSpeedPct = _fileStream->readUint16LE();
@@ -1278,7 +1271,7 @@ bool Macs2Engine::loadSceneGraphicsV2(uint32 sceneIndex) {
current._position.x = (int16)(stream->readUint16LE() << 1);
current._position.y = (int16)(stream->readUint16LE() << 1);
uint8 adj[8];
- stream->read(adj, 8);
+ stream->read(adj, sizeof(adj));
stream->skip(8);
const uint16 numConnections = stream->readUint16LE();
current._adjacentPoints.clear();
@@ -1286,7 +1279,7 @@ bool Macs2Engine::loadSceneGraphicsV2(uint32 sceneIndex) {
current._adjacentPoints.push_back(adj[j]);
_pathfindingPoints.push_back(current);
}
- stream->skip(0x2c0 - 0x160);
+ stream->skip(352);
_numHotspots = stream->readUint16LE();
_hotspotColorTable.clear();
@@ -1759,7 +1752,7 @@ bool Macs2Engine::loadDeltaAnimResource(uint8 resourceIndex, uint16 executingObj
_fileStream->seek(address, SEEK_SET);
const uint32 size = _fileStream->readUint32LE();
char magic[8];
- if (_fileStream->read(magic, 8) != 8 || memcmp(magic, "AHFFDLTA", 8) != 0) {
+ if (_fileStream->read(magic, sizeof(magic)) != sizeof(magic) || memcmp(magic, "AHFFDLTA", sizeof(magic)) != 0) {
_fileStream->seek(oldPos, SEEK_SET);
return false;
}
@@ -2090,7 +2083,6 @@ void Macs2Engine::updateAllBackgroundAnimationDepthMaps() {
updateBackgroundAnimationDepthMap(i);
}
-// snapToWalkablePosition (1008:9be2)
// Params: (pTargetY, pTargetX, charY, charX)
// Modifies *pTargetY and *pTargetX in place.
void Macs2Engine::snapToWalkablePosition(int16 *pTargetY, int16 *pTargetX, int16 charY, int16 charX) {
@@ -2215,8 +2207,8 @@ void Macs2Engine::snapToWalkablePosition(int16 *pTargetY, int16 *pTargetX, int16
}
}
-bool Macs2Engine::getPathfindingOverride(uint16 index, uint16 &result) {
- for (auto current : _pathfindingOverrides) {
+bool Macs2Engine::getPathfindingOverride(uint16 index, uint16 &result) const {
+ for (const PathfindingAreaOverride ¤t : _pathfindingOverrides) {
if (current._index == index && current._active) {
result = current._overrideValue;
return true;
@@ -2233,7 +2225,7 @@ void Macs2Engine::setPathfindingOverride(uint16 index, uint16 overrideValue) {
_pathfindingOverrides.push_back(override);
}
-uint16 Macs2Engine::getPathfindingOverride2(uint16 index) {
+uint16 Macs2Engine::getPathfindingOverride2(uint16 index) const {
if (index < AREA_OVERRIDE_MIN || index > AREA_OVERRIDE_MAX) {
return 0;
}
@@ -2250,7 +2242,6 @@ void Macs2Engine::removePathfindingOverride(uint16 index) {
}
};
-// isPathWalkable (1008:1196)
// Params: (param_1=y1, param_2=x1, param_3=y2, param_4=x2)
// Traces from (x2,y2) toward (x1,y1). Checks walkability only on major-axis steps.
// Uses unsigned 16-bit error accumulator with wrapping arithmetic.
@@ -2294,7 +2285,7 @@ bool Macs2Engine::isPathWalkable(int16 y1, int16 x1, int16 y2, int16 x2) {
return result;
}
-// Binary euclideanDistance (1008:1390): integer Euclidean distance approximation.
+// integer Euclidean distance approximation.
// Iterates i from 0 until i^2 >= dx^2 + dy^2. Capped at 0x500.
int Macs2Engine::euclideanDistance(const Common::Point &a, const Common::Point &b) {
int32 dx = abs((int)(b.x - a.x));
@@ -2306,7 +2297,7 @@ int Macs2Engine::euclideanDistance(const Common::Point &a, const Common::Point &
return i;
}
-// Binary walkableDistance (1008:1293): distance between two nodes IF walkable, else 0x500.
+// distance between two nodes IF walkable, else 0x500.
// Uses binary search on precomputed squared-distance table (scene+0x61DC) for O(log n) sqrt.
int Macs2Engine::walkableDistance(int nodeA, int nodeB) {
const Common::Point &a = _pathfindingPoints[nodeA - 1]._position;
@@ -2330,18 +2321,14 @@ int Macs2Engine::walkableDistance(int nodeA, int nodeB) {
return result;
}
-// Binary buildPathFromNodes (1008:15a8): recursive DFS cost to reach a reachable node.
+// recursive DFS cost to reach a reachable node.
// Full recursive DFS with visited-stack cycle detection matching binary exactly.
// Terminal: returns walkableDistance(node, finalDest) when node is reachable.
// Recursive: min(computeMinCostToReachable(adj)) + walkableDistance(bestAdj, current).
int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 actorIndex, const bool *reachable, int nodeCount, const Common::Point &finalDest) {
- // Static visited stack (matches binary's stack-frame approach, max 16 nodes)
- static int visitedStack[17];
- static int visitedCount = 0;
-
// Push current node to visited stack
- visitedCount++;
- visitedStack[visitedCount] = nodeIndex;
+ _visitedCount++;
+ _visitedStack[_visitedCount] = nodeIndex;
int result;
const Common::Point &nodePos = _pathfindingPoints[nodeIndex - 1]._position;
@@ -2367,7 +2354,7 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
} while (step > 1);
result = dist;
}
- visitedCount--;
+ _visitedCount--;
return result;
}
@@ -2384,8 +2371,8 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
// Check visited stack
bool alreadyVisited = false;
- for (int j = 1; j < visitedCount; j++) {
- if (visitedStack[j] == adj) {
+ for (int j = 1; j < _visitedCount; j++) {
+ if (_visitedStack[j] == adj) {
alreadyVisited = true;
break;
}
@@ -2410,7 +2397,7 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
}
// Pop visited stack
- visitedCount--;
+ _visitedCount--;
return result;
}
@@ -2452,7 +2439,7 @@ void Macs2Engine::setBottomHudVisible(bool visible) {
}
void Macs2Engine::setCursorMode(Script::MouseMode newMode) {
- // setCursorMode (1008:3ea5): when the cursor image changes, keep the hotspot
+ // when the cursor image changes, keep the hotspot
// fixed on screen by compensating for the old/new image half-extents, clamp,
// refresh the cursor graphic, and flag the clip rect dirty.
const Script::MouseMode oldMode = _scriptExecutor->_cursorMode;
@@ -2520,7 +2507,7 @@ void Macs2Engine::setCursorMode(Script::MouseMode newMode) {
: "Unknown");
}
-uint16 Macs2Engine::getHotspotAtPoint(const Common::Point &p) {
+uint16 Macs2Engine::getHotspotAtPoint(const Common::Point &p) const {
uint16 result = 0;
if (p.x < 0 || p.x >= screenWidth() || p.y < 0 || p.y >= gameHeight() || _hotspotMap.w == 0) {
return result;
@@ -2693,7 +2680,7 @@ void Macs2Engine::getHotspotPositions(Common::Array<Graphics::HotspotInfo> &hots
const uint16 sceneIndex = (uint16)Scenes::instance()._currentSceneIndex;
const Common::String name = lookupSceneHotspotName(sceneIndex, entry.index);
const Graphics::HotspotType type = lookupSceneHotspotType(sceneIndex, entry.index);
- hotspots.push_back(Graphics::HotspotInfo(center, hotspotLabelToU32(name), type));
+ hotspots.emplace_back(Graphics::HotspotInfo(center, hotspotLabelToU32(name), type));
}
View1 *view = g_events ? (View1 *)g_events->findView("View1") : nullptr;
@@ -2713,7 +2700,7 @@ void Macs2Engine::getHotspotPositions(Common::Array<Graphics::HotspotInfo> &hots
hotspotType = Graphics::kHotspotNPC;
const Common::String &name = getObjectHotspotName(entry.index);
- hotspots.push_back(Graphics::HotspotInfo(screenPos, hotspotLabelToU32(name), hotspotType));
+ hotspots.emplace_back(Graphics::HotspotInfo(screenPos, hotspotLabelToU32(name), hotspotType));
}
}
@@ -2801,17 +2788,16 @@ uint16 Macs2Engine::getWalkabilityAt(const Common::Point &p) {
int Macs2Engine::measureString(const Common::String &s) {
int sum = 0;
GlyphData currentGlyph;
- bool found = false;
uint16 widestGlyph = 0;
for (auto current = s.begin(); current != s.end(); current++) {
- found = findGlyph(*current, currentGlyph);
+ bool found = findGlyph(*current, currentGlyph);
if (found) {
widestGlyph = MAX(widestGlyph, currentGlyph._width);
}
}
for (auto current = s.begin(); current != s.end(); current++) {
- found = findGlyph(*current, currentGlyph);
+ bool found = findGlyph(*current, currentGlyph);
if (!found) {
sum += widestGlyph;
} else {
@@ -2822,7 +2808,6 @@ int Macs2Engine::measureString(const Common::String &s) {
}
int Macs2Engine::measureStringsVertically(const Common::StringArray &sa) {
- // DOS l0037_B318: maxGlyphHeight + 2. Amiga uses absolute MXFF line pitch.
return (int)sa.size() * dialogLineHeight();
}
diff --git a/engines/macs2/macs2.h b/engines/macs2/macs2.h
index 5b1144c4f16..56944b65885 100644
--- a/engines/macs2/macs2.h
+++ b/engines/macs2/macs2.h
@@ -357,6 +357,10 @@ public:
// Assumes that the stream is at the start of the right section
void readImageResources(Common::SeekableReadStream *stream);
+ // visited stack (matches binary's stack-frame approach, max 16 nodes)
+ int _visitedStack[17] {};
+ int _visitedCount = 0;
+
public:
Macs2Engine(OSystem *osystem, const ADGameDescription *gameDesc);
~Macs2Engine() override;
@@ -401,7 +405,7 @@ public:
Common::Array<PathfindingPoint> _pathfindingPoints;
Common::Array<Common::Point> _path;
- bool getPathfindingOverride(uint16 index, uint16 &result);
+ bool getPathfindingOverride(uint16 index, uint16 &result) const;
void setPathfindingOverride(uint16 index, uint16 overrideValue);
// Walkability threshold 0xC8 uses signed 16-bit comparison in the binary (JL/JGE).
@@ -414,7 +418,7 @@ public:
}
// This one implements the lookup relative to es:[di+4EA8h] vs. the other one at es:[di+4EA5h] and es:[di+4EA6h]
- uint16 getPathfindingOverride2(uint16 index);
+ uint16 getPathfindingOverride2(uint16 index) const;
void removePathfindingOverride(uint16 index);
uint16 getWalkabilityAt(int16 y, int16 x);
@@ -683,7 +687,7 @@ public:
// full backbuffer each frame via ManagedSurface. Kept only for save/load compatibility.
bool _clipRectDirty = false;
- uint16 getHotspotAtPoint(const Common::Point &p);
+ uint16 getHotspotAtPoint(const Common::Point &p) const;
Common::Array<uint16> inventoryIconIndices;
Common::Array<uint16> containerInventoryIconIndices;
diff --git a/engines/macs2/music.cpp b/engines/macs2/music.cpp
index 77eda940e1a..f92ec2a8875 100644
--- a/engines/macs2/music.cpp
+++ b/engines/macs2/music.cpp
@@ -89,8 +89,8 @@ void Music::writeReg(byte reg, byte value) {
}
void Music::silenceAll() {
- // Key-off all 9 channels
- for (int i = 0; i <= 8; i++) {
+ // Key-off all channels
+ for (int i = 0; i < kChannels; i++) {
writeReg(i + 0xB0, readReg(i + 0xB0) & 0xDF);
}
// Silence all operator volumes
@@ -116,7 +116,7 @@ bool Music::playSongData(const Common::Array<uint8> &data) {
// Enable waveform select
writeReg(0x01, 0x20);
writeReg(0xBD, 0);
- _numOplChannels = 9;
+ _numOplChannels = kChannels;
// Reset state
memset(_voiceAge, 1, sizeof(_voiceAge));
diff --git a/engines/macs2/music.h b/engines/macs2/music.h
index b74ee6fb150..5bf25ed2853 100644
--- a/engines/macs2/music.h
+++ b/engines/macs2/music.h
@@ -102,6 +102,7 @@ public:
// Debug state for ImGui visualization
static constexpr int kDebugRingSize = 512;
+ static constexpr int kChannels = 9;
struct VoiceDebugState {
uint8 note = 0xFF;
uint8 channel = 0xFF;
@@ -109,13 +110,13 @@ public:
bool active = false;
};
struct DebugState {
- VoiceDebugState voices[9];
+ VoiceDebugState voices[kChannels];
uint8 masterVolume = 0;
uint16 activeMusicSlot = 0;
uint8 statusFlags = 0;
uint32 nextEventTimer = 0;
uint16 numOplChannels = 0;
- float regHistory[9][kDebugRingSize] = {};
+ float regHistory[kChannels][kDebugRingSize] = {};
int ringPos = 0;
};
DebugState _debug;
@@ -146,10 +147,10 @@ private:
uint8 _numOplChannels;
// Voice allocation (age-based, matching original)
- uint8 _voiceAge[9];
- uint8 _voiceMidiChannel[9];
- uint8 _voiceInstrument[9];
- uint8 _voiceNote[9];
+ uint8 _voiceAge[kChannels];
+ uint8 _voiceMidiChannel[kChannels];
+ uint8 _voiceInstrument[kChannels];
+ uint8 _voiceNote[kChannels];
// Channel state
uint8 _channelPrograms[16];
Commit: 3dac60c683f0a247b978390132c9b03f324b8f04
https://github.com/scummvm/scummvm/commit/3dac60c683f0a247b978390132c9b03f324b8f04
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:12+02:00
Commit Message:
MACS2: formatting cleanup and const
Changed paths:
engines/macs2/macs2.cpp
engines/macs2/macs2.h
engines/macs2/macs2_constants.h
engines/macs2/scriptexecutor.cpp
engines/macs2/scriptexecutor.h
diff --git a/engines/macs2/macs2.cpp b/engines/macs2/macs2.cpp
index b39ecbd5753..6c0b25ab8a9 100644
--- a/engines/macs2/macs2.cpp
+++ b/engines/macs2/macs2.cpp
@@ -1495,20 +1495,23 @@ void Macs2Engine::changeScene(uint32 newSceneIndex, bool executeScript) {
_scriptExecutor->setScript(Scenes::instance()._currentSceneScript);
_pathfindingOverrides.clear();
- for (uint i = 0; i < _hotspotOverrides.size(); i++)
+ for (uint i = 0; i < _hotspotOverrides.size(); i++) {
_hotspotOverrides[i] = 0xFFFF;
+ }
// Match DOS changeScene: when View1 is not up yet (first call from
// readAmigaResources), only load scene data. Entry init/repeat - including
// intro frameWait/changeScene - must run from View1::tick so waits can
// complete in the game loop.
- if (executeScript && currentView != nullptr)
+ if (executeScript && currentView != nullptr) {
_scriptExecutor->runSceneEntryScriptPasses();
+ }
return;
}
- if (!loadSceneGraphics(newSceneIndex))
+ if (!loadSceneGraphics(newSceneIndex)) {
error("changeScene(): Failed to load scene graphics for scene %u", newSceneIndex);
+ }
// Scene change starts with the main HUD shown. v2 scripts may hide it
// during init (overview map). v1 has no hide/show opcodes; kEnhUIUX uses
@@ -1543,9 +1546,10 @@ void Macs2Engine::changeScene(uint32 newSceneIndex, bool executeScript) {
_scriptExecutor->_inventoryActionFlag = false;
_scriptExecutor->_inventoryCombineFlag = false;
- for (auto currentCharacter : currentView->_characters) {
- if (currentCharacter->_gameObject != nullptr)
+ for (Character *currentCharacter : currentView->_characters) {
+ if (currentCharacter->_gameObject != nullptr) {
_scriptExecutor->saveWalkRuntime(currentCharacter, currentCharacter->_gameObject);
+ }
delete currentCharacter;
}
currentView->_characters.clear();
@@ -1553,8 +1557,9 @@ void Macs2Engine::changeScene(uint32 newSceneIndex, bool executeScript) {
// Binary changeScene (1008:2574): loadObjectData for scene objects except current actor.
GameObject *actorObject = GameObjects::getObjectByIndex(Scenes::instance()._currentActorIndex);
if (actorObject != nullptr && actorObject->_sceneIndex == newSceneIndex) {
- if (isV2())
+ if (isV2()) {
loadObjectData(actorObject);
+ }
Character *actorChar = new Character();
actorChar->_gameObject = actorObject;
currentView->_characters.push_back(actorChar);
@@ -1562,9 +1567,10 @@ void Macs2Engine::changeScene(uint32 newSceneIndex, bool executeScript) {
resetCharacterWalkPath(actorChar);
_scriptExecutor->saveWalkRuntime(actorChar, actorObject);
}
- for (auto currentObject : GameObjects::instance()._objects) {
- if (currentObject == nullptr)
+ for (GameObject *currentObject : GameObjects::instance()._objects) {
+ if (currentObject == nullptr) {
continue;
+ }
if (currentObject->_sceneIndex == newSceneIndex &&
currentObject->_index != Scenes::instance()._currentActorIndex &&
currentObject->_dataOffset != 0 &&
@@ -1609,19 +1615,23 @@ void Macs2Engine::changeScene(uint32 newSceneIndex, bool executeScript) {
bool Macs2Engine::resolveResourceFileOffset(uint8 resourceIndex, uint16 executingObjectId, uint32 &outOffset) const {
outOffset = 0;
- if (resourceIndex == 0 || _fileStream == nullptr)
+ if (resourceIndex == 0 || _fileStream == nullptr) {
return false;
+ }
if (executingObjectId == 0) {
- if (resourceIndex > _sceneResourceOffsets.size())
+ if (resourceIndex > _sceneResourceOffsets.size()) {
return false;
+ }
outOffset = _sceneResourceOffsets[resourceIndex - 1];
} else {
GameObject *object = GameObjects::getObjectByIndex(executingObjectId);
- if (object == nullptr || object->_dataOffset == 0)
+ if (object == nullptr || object->_dataOffset == 0) {
return false;
- if ((uint)(resourceIndex - 1) >= maxObjectResources())
+ }
+ if ((uint)(resourceIndex - 1) >= maxObjectResources()) {
return false;
+ }
outOffset = object->_resourceOffsets[resourceIndex - 1];
}
return outOffset != 0 && outOffset < (uint32)_fileStream->size();
@@ -1631,8 +1641,9 @@ bool Macs2Engine::loadSizedResourcePayload(uint8 resourceIndex, uint16 executing
Common::Array<uint8> &outPayload) {
outPayload.clear();
uint32 address = 0;
- if (!resolveResourceFileOffset(resourceIndex, executingObjectId, address))
+ if (!resolveResourceFileOffset(resourceIndex, executingObjectId, address)) {
return false;
+ }
const int64 oldPos = _fileStream->pos();
_fileStream->seek(address, SEEK_SET);
@@ -1654,21 +1665,25 @@ bool Macs2Engine::loadSizedResourcePayload(uint8 resourceIndex, uint16 executing
bool Macs2Engine::loadAhffAnimResource(uint8 resourceIndex, uint16 executingObjectId,
Common::Array<uint8> &outBlob) {
Common::Array<uint8> payload;
- if (!loadSizedResourcePayload(resourceIndex, executingObjectId, payload))
+ if (!loadSizedResourcePayload(resourceIndex, executingObjectId, payload)) {
return false;
- if (payload.size() < 12 || memcmp(payload.data(), "AHFFANIM0100", 12) != 0)
+ }
+ if (payload.size() < 12 || memcmp(payload.data(), "AHFFANIM0100", 12) != 0) {
return false;
+ }
outBlob.clear();
outBlob.resize(payload.size() - 12);
- if (!outBlob.empty())
+ if (!outBlob.empty()) {
memcpy(outBlob.data(), payload.data() + 12, outBlob.size());
+ }
return !outBlob.empty();
}
bool Macs2Engine::readMegaPicImage(Common::SeekableReadStream *stream, int width, int height,
Graphics::ManagedSurface &out) {
- if (stream == nullptr || width <= 0 || height <= 0)
+ if (stream == nullptr || width <= 0 || height <= 0) {
return false;
+ }
out.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
Common::Array<byte> rowBuf;
@@ -1676,10 +1691,12 @@ bool Macs2Engine::readMegaPicImage(Common::SeekableReadStream *stream, int width
for (int y = 0; y < height; y++) {
uint16 packedLen = stream->readUint16LE();
- if (packedLen == 0 || packedLen > 2999)
+ if (packedLen == 0 || packedLen > 2999) {
return false;
- if (stream->read(rowBuf.data(), packedLen) != packedLen)
+ }
+ if (stream->read(rowBuf.data(), packedLen) != packedLen) {
return false;
+ }
int x = 0;
uint i = 0;
@@ -1688,17 +1705,20 @@ bool Macs2Engine::readMegaPicImage(Common::SeekableReadStream *stream, int width
if (code < 0x80) {
const uint run = code;
for (uint n = 0; n < run && x < width; n++) {
- if (i >= packedLen)
+ if (i >= packedLen) {
return false;
+ }
out.setPixel(x++, y, rowBuf[i++]);
}
} else {
- if (i >= packedLen)
+ if (i >= packedLen) {
return false;
+ }
const byte value = rowBuf[i++];
const uint run = code & 0x7F;
- for (uint n = 0; n < run && x < width; n++)
+ for (uint n = 0; n < run && x < width; n++) {
out.setPixel(x++, y, value);
+ }
}
}
}
@@ -1709,8 +1729,9 @@ bool Macs2Engine::loadMaskFromResource(uint8 resourceIndex, uint16 executingObje
Graphics::ManagedSurface &dest, int megapicW, int megapicH,
bool upscaleHalfRes) {
uint32 address = 0;
- if (!resolveResourceFileOffset(resourceIndex, executingObjectId, address))
+ if (!resolveResourceFileOffset(resourceIndex, executingObjectId, address)) {
return false;
+ }
const int64 oldPos = _fileStream->pos();
_fileStream->seek(address, SEEK_SET);
@@ -1745,8 +1766,9 @@ void Macs2Engine::clearDeltaAnim() {
bool Macs2Engine::loadDeltaAnimResource(uint8 resourceIndex, uint16 executingObjectId, bool forceSkipSpeed1) {
uint32 address = 0;
- if (!resolveResourceFileOffset(resourceIndex, executingObjectId, address))
+ if (!resolveResourceFileOffset(resourceIndex, executingObjectId, address)) {
return false;
+ }
const int64 oldPos = _fileStream->pos();
_fileStream->seek(address, SEEK_SET);
@@ -1770,8 +1792,9 @@ bool Macs2Engine::loadDeltaAnimResource(uint8 resourceIndex, uint16 executingObj
}
uint16 skipSpeed = (_skipSpeed >= 1 && _skipSpeed <= 4) ? _skipSpeed : 1;
- if (forceSkipSpeed1)
+ if (forceSkipSpeed1) {
skipSpeed = 1;
+ }
Common::Array<uint32> relOffsets;
relOffsets.resize(512);
// FBlockRead(0x1000): 512 uint32 offsets (0x800) plus 0x800 trailing bytes.
@@ -1788,14 +1811,16 @@ bool Macs2Engine::loadDeltaAnimResource(uint8 resourceIndex, uint16 executingObj
readOffsetTable1000();
_fileStream->skip(0x1000);
frameCount = (uint16)(((uint32)frameCount + 1) >> 1);
- if (frameCount > 0)
+ if (frameCount > 0) {
frameCount--;
+ }
} else {
_fileStream->skip(0x2000);
readOffsetTable1000();
frameCount = (uint16)(((uint32)frameCount + 1) / 3);
- if (frameCount > 0)
+ if (frameCount > 0) {
frameCount--;
+ }
}
if (frameCount == 0 || frameCount > 512) {
_fileStream->seek(oldPos, SEEK_SET);
@@ -1815,20 +1840,23 @@ bool Macs2Engine::loadDeltaAnimResource(uint8 resourceIndex, uint16 executingObj
const uint32 base = address + 4;
for (uint16 fi = 0; fi < numFrames; fi++) {
const uint32 absOff = relOffsets[fi] + base;
- if (absOff >= (uint32)_fileStream->size())
+ if (absOff >= (uint32)_fileStream->size()) {
continue;
+ }
_fileStream->seek(absOff, SEEK_SET);
const uint16 stripCount = _fileStream->readUint16LE();
DeltaFrame &frame = _deltaAnim.frames[fi];
frame.strips.clear();
- if (stripCount == 0 || stripCount > 400)
+ if (stripCount == 0 || stripCount > 400) {
continue;
+ }
frame.strips.resize(stripCount);
for (uint16 si = 0; si < stripCount; si++) {
frame.strips[si].y = _fileStream->readUint16LE();
const uint16 rleSize = _fileStream->readUint16LE();
- if (rleSize == 0 || rleSize > 0x8000)
+ if (rleSize == 0 || rleSize > 0x8000) {
break;
+ }
frame.strips[si].rle.resize(rleSize);
if (_fileStream->read(frame.strips[si].rle.data(), rleSize) != rleSize) {
frame.strips[si].rle.clear();
@@ -1843,17 +1871,21 @@ bool Macs2Engine::loadDeltaAnimResource(uint8 resourceIndex, uint16 executingObj
}
void Macs2Engine::applyDeltaFrameToBackground(const DeltaFrame &frame) {
- if (_sceneBackground.w <= 0 || _sceneBackground.h <= 0)
+ if (_sceneBackground.w <= 0 || _sceneBackground.h <= 0) {
return;
+ }
for (const DeltaStrip &strip : frame.strips) {
const int y = (int)strip.y;
- if (y < (int)_deltaAnim.clipMiY || y > (int)_deltaAnim.clipMaY)
+ if (y < (int)_deltaAnim.clipMiY || y > (int)_deltaAnim.clipMaY) {
continue;
- if (y < 0 || y >= _sceneBackground.h)
+ }
+ if (y < 0 || y >= _sceneBackground.h) {
continue;
- if (strip.rle.empty())
+ }
+ if (strip.rle.empty()) {
continue;
+ }
const uint8 *p = strip.rle.data();
const uint8 *end = p + strip.rle.size();
@@ -1864,32 +1896,38 @@ void Macs2Engine::applyDeltaFrameToBackground(const DeltaFrame &frame) {
uint16 runLen = READ_LE_UINT16(p);
p += 2;
x += skip;
- if (runLen == 0)
+ if (runLen == 0) {
break;
+ }
while (runLen != 0 && p < end) {
uint8 code = *p++;
if (code < 0x80) {
uint16 n = code;
- if (n > runLen)
+ if (n > runLen) {
n = runLen;
+ }
for (uint16 i = 0; i < n && p < end; i++, x++) {
if (x >= (int)_deltaAnim.clipMiX && x <= (int)_deltaAnim.clipMaX &&
- x >= 0 && x < _sceneBackground.w)
+ x >= 0 && x < _sceneBackground.w) {
_sceneBackground.setPixel(x, y, *p);
+ }
p++;
}
runLen = (uint16)(runLen - n);
} else {
uint16 n = (uint16)(code - 0x80);
- if (n > runLen)
+ if (n > runLen) {
n = runLen;
- if (p >= end)
+ }
+ if (p >= end) {
break;
+ }
const uint8 val = *p++;
for (uint16 i = 0; i < n; i++, x++) {
if (x >= (int)_deltaAnim.clipMiX && x <= (int)_deltaAnim.clipMaX &&
- x >= 0 && x < _sceneBackground.w)
+ x >= 0 && x < _sceneBackground.w) {
_sceneBackground.setPixel(x, y, val);
+ }
}
runLen = (uint16)(runLen - n);
}
@@ -1900,24 +1938,29 @@ void Macs2Engine::applyDeltaFrameToBackground(const DeltaFrame &frame) {
void Macs2Engine::playDeltaFrameSfx(uint16 displayFrame) {
for (const DeltaSfxEvent &ev : _deltaAnim.sfxEvents) {
- if (ev.frameIndex != displayFrame || ev.fileName.empty())
+ if (ev.frameIndex != displayFrame || ev.fileName.empty()) {
continue;
- if (ev.duckMusic)
+ }
+ if (ev.duckMusic) {
getMusic()->setSmfDucked(true, _talkVol);
+ }
const Common::String base = Script::ScriptExecutor::stripAudioExtension(ev.fileName);
playAudioFile(Common::Path("SOUNDFX").join(base), false);
}
}
bool Macs2Engine::startDeltaPlayback(uint16 startFrame, uint16 endFrame, uint16 speedTicks, bool applyPalette) {
- if (!_deltaAnim.loaded || _deltaAnim.frameCount == 0)
+ if (!_deltaAnim.loaded || _deltaAnim.frameCount == 0) {
return false;
+ }
uint16 start = startFrame ? startFrame : 1;
uint16 end = endFrame;
- if (end == 0 || end > _deltaAnim.frameCount)
+ if (end == 0 || end > _deltaAnim.frameCount) {
end = _deltaAnim.frameCount;
- if (start > end)
+ }
+ if (start > end) {
start = end;
+ }
_deltaAnim.startFrame = (uint16)(start - 1);
_deltaAnim.endFrame = (uint16)(end - 1);
_deltaAnim.currentFrame = _deltaAnim.startFrame;
@@ -1933,26 +1976,31 @@ bool Macs2Engine::startDeltaPlayback(uint16 startFrame, uint16 endFrame, uint16
}
const uint16 displayFrame = _deltaAnim.currentFrame;
playDeltaFrameSfx(displayFrame);
- if (displayFrame < _deltaAnim.frames.size())
+ if (displayFrame < _deltaAnim.frames.size()) {
applyDeltaFrameToBackground(_deltaAnim.frames[displayFrame]);
+ }
_deltaAnim.currentFrame++;
- if (_deltaAnim.currentFrame > _deltaAnim.endFrame)
+ if (_deltaAnim.currentFrame > _deltaAnim.endFrame) {
_deltaAnim.playing = false;
+ }
return true;
}
bool Macs2Engine::tickDeltaPlayback() {
- if (!_deltaAnim.playing)
+ if (!_deltaAnim.playing) {
return false;
+ }
_deltaAnim.tickCounter++;
- if (_deltaAnim.tickCounter < _deltaAnim.speedTicks)
+ if (_deltaAnim.tickCounter < _deltaAnim.speedTicks) {
return true;
+ }
_deltaAnim.tickCounter = 0;
const uint16 displayFrame = _deltaAnim.currentFrame;
playDeltaFrameSfx(displayFrame);
- if (displayFrame < _deltaAnim.frames.size())
+ if (displayFrame < _deltaAnim.frames.size()) {
applyDeltaFrameToBackground(_deltaAnim.frames[displayFrame]);
+ }
_deltaAnim.currentFrame++;
if (_deltaAnim.currentFrame > _deltaAnim.endFrame) {
_deltaAnim.playing = false;
@@ -1963,13 +2011,15 @@ bool Macs2Engine::tickDeltaPlayback() {
}
bool Macs2Engine::loadOverlayFont(uint8 resourceIndex, uint16 executingObjectID) {
- if (isAmiga())
+ if (isAmiga()) {
return loadAmigaOverlayFont(resourceIndex);
+ }
// Original (1008:d749): resource table offset, then seek address+0x10 and loadFontData.
uint32 address = 0;
- if (!resolveResourceFileOffset(resourceIndex, executingObjectID, address))
+ if (!resolveResourceFileOffset(resourceIndex, executingObjectID, address)) {
return false;
+ }
const int64 oldPos = _fileStream->pos();
_fileStream->seek(address + 0x10, SEEK_SET);
@@ -2022,26 +2072,30 @@ uint16 Macs2Engine::getWalkabilityAt(int16 y, int16 x) {
}
void Macs2Engine::updateBackgroundAnimationDepthMap(size_t animIndex) {
- if (isV2() || _sceneDepthMap.w == 0 || animIndex >= _backgroundAnimations.size())
+ if (isV2() || _sceneDepthMap.w == 0 || animIndex >= _backgroundAnimations.size()) {
return;
+ }
BackgroundAnimation &anim = _backgroundAnimations[animIndex];
BackgroundAnimationBlob &blobEntry = _backgroundAnimationsBlobs[animIndex];
Common::Array<uint8> &blob = blobEntry.activeBlob();
- if (blob.empty())
+ if (blob.empty()) {
return;
+ }
const uint32 frameStart = BackgroundAnimationBlob::advanceAnimFrame(blob, false, 0);
- if (frameStart == 0 || frameStart + 10 > blob.size())
+ if (frameStart == 0 || frameStart + 10 > blob.size()) {
return;
+ }
const uint16 pixelFrameNum = BackgroundAnimationBlob::getCurrentPixelFrameNumber(blob);
const int16 frameOffsetX = (int16)READ_LE_UINT16(&blob[frameStart]);
const int16 frameOffsetY = (int16)READ_LE_UINT16(&blob[frameStart + 2]);
const uint16 width = READ_LE_UINT16(&blob[frameStart + 6]);
const uint16 height = READ_LE_UINT16(&blob[frameStart + 8]);
- if (width == 0 || height == 0 || frameStart + 10 + (uint32)width * height > blob.size())
+ if (width == 0 || height == 0 || frameStart + 10 + (uint32)width * height > blob.size()) {
return;
+ }
const int16 baseX = (int16)anim._x + 1 + frameOffsetX;
const int16 baseY = (int16)anim._y + frameOffsetY;
@@ -2051,12 +2105,14 @@ void Macs2Engine::updateBackgroundAnimationDepthMap(size_t animIndex) {
// First pixel frame (closed gate): restore authored depth under opaque pixels.
for (uint16 yy = 0; yy < height; yy++) {
for (uint16 xx = 0; xx < width; xx++) {
- if (pixels[yy * width + xx] == 0)
+ if (pixels[yy * width + xx] == 0) {
continue;
+ }
const int px = baseX + (int)xx;
const int py = baseY + (int)yy;
- if (px >= 0 && px < _depthMap.w && py >= 0 && py < _depthMap.h)
+ if (px >= 0 && px < _depthMap.w && py >= 0 && py < _depthMap.h) {
_depthMap.setPixel(px, py, _sceneDepthMap.getPixel(px, py));
+ }
}
}
return;
@@ -2065,22 +2121,26 @@ void Macs2Engine::updateBackgroundAnimationDepthMap(size_t animIndex) {
// Later pixel frames (open gate): walkable tiles under opaque pixels use path height.
for (uint16 yy = 0; yy < height; yy++) {
for (uint16 xx = 0; xx < width; xx++) {
- if (pixels[yy * width + xx] == 0)
+ if (pixels[yy * width + xx] == 0) {
continue;
+ }
const int px = baseX + (int)xx;
const int py = baseY + (int)yy;
- if (px < 0 || px >= _depthMap.w || py < 0 || py >= _depthMap.h)
+ if (px < 0 || px >= _depthMap.w || py < 0 || py >= _depthMap.h) {
continue;
+ }
const uint16 walkVal = getWalkabilityAt((int16)py, (int16)px);
- if (isWalkabilityWalkable(walkVal))
+ if (isWalkabilityWalkable(walkVal)) {
_depthMap.setPixel(px, py, (byte)walkVal);
+ }
}
}
}
void Macs2Engine::updateAllBackgroundAnimationDepthMaps() {
- for (size_t i = 0; i < _backgroundAnimations.size(); i++)
+ for (size_t i = 0; i < _backgroundAnimations.size(); i++) {
updateBackgroundAnimationDepthMap(i);
+ }
}
// Params: (pTargetY, pTargetX, charY, charX)
@@ -2135,19 +2195,23 @@ void Macs2Engine::snapToWalkablePosition(int16 *pTargetY, int16 *pTargetX, int16
if (charX < *pTargetX) {
while (true) {
uint16 w2 = getWalkabilityAt(*pTargetY, *pTargetX);
- if (isWalkabilityWalkable(w2))
+ if (isWalkabilityWalkable(w2)) {
break;
- if (*pTargetX <= 0)
+ }
+ if (*pTargetX <= 0) {
break;
+ }
*pTargetX = *pTargetX - 1;
}
} else {
while (true) {
uint16 w2 = getWalkabilityAt(*pTargetY, *pTargetX);
- if (isWalkabilityWalkable(w2))
+ if (isWalkabilityWalkable(w2)) {
break;
- if (*pTargetX >= maxX)
+ }
+ if (*pTargetX >= maxX) {
break;
+ }
*pTargetX = *pTargetX + 1;
}
}
@@ -2162,22 +2226,30 @@ void Macs2Engine::snapToWalkablePosition(int16 *pTargetY, int16 *pTargetX, int16
// Phase 6: Gradient-based wall push
int16 pushX = 0;
int16 pushY = 0;
- if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY, *pTargetX + 1)))
+ if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY, *pTargetX + 1))) {
pushX--;
- if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY, *pTargetX - 1)))
+ }
+ if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY, *pTargetX - 1))) {
pushX++;
- if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY + 1, *pTargetX)))
+ }
+ if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY + 1, *pTargetX))) {
pushY--;
- if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY - 1, *pTargetX)))
+ }
+ if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY - 1, *pTargetX))) {
pushY++;
- if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY, *pTargetX + 2)))
+ }
+ if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY, *pTargetX + 2))) {
pushX--;
- if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY, *pTargetX - 2)))
+ }
+ if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY, *pTargetX - 2))) {
pushX++;
- if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY + 2, *pTargetX)))
+ }
+ if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY + 2, *pTargetX))) {
pushY--;
- if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY - 2, *pTargetX)))
+ }
+ if (isWalkabilityBlocking(getWalkabilityAt(*pTargetY - 2, *pTargetX))) {
pushY++;
+ }
while (pushX != 0 || pushY != 0) {
if (pushX < 0) {
@@ -2257,28 +2329,34 @@ bool Macs2Engine::isPathWalkable(int16 y1, int16 x1, int16 y2, int16 x2) {
do {
bool steppedX;
if (error >= absDx) {
- if (y1 < y2)
+ if (y1 < y2) {
curY--;
- if (y2 < y1)
+ }
+ if (y2 < y1) {
curY++;
+ }
error -= absDx;
steppedX = false;
} else {
- if (x1 < x2)
+ if (x1 < x2) {
curX--;
- if (x2 < x1)
+ }
+ if (x2 < x1) {
curX++;
+ }
error += absDy;
steppedX = true;
}
if (absDx > absDy && steppedX) {
- if (isWalkabilityBlocking(getWalkabilityAt(curY, curX)))
+ if (isWalkabilityBlocking(getWalkabilityAt(curY, curX))) {
result = false;
+ }
}
if (absDx <= absDy && !steppedX) {
- if (isWalkabilityBlocking(getWalkabilityAt(curY, curX)))
+ if (isWalkabilityBlocking(getWalkabilityAt(curY, curX))) {
result = false;
+ }
}
} while (curX != x1 || curY != y1);
@@ -2292,8 +2370,9 @@ int Macs2Engine::euclideanDistance(const Common::Point &a, const Common::Point &
int32 dy = abs((int)(b.y - a.y));
int32 distSq = dx * dx + dy * dy;
int i = 0;
- while (i < 0x500 && (int32)i * i < distSq)
+ while (i < 0x500 && (int32)i * i < distSq) {
i++;
+ }
return i;
}
@@ -2302,8 +2381,9 @@ int Macs2Engine::euclideanDistance(const Common::Point &a, const Common::Point &
int Macs2Engine::walkableDistance(int nodeA, int nodeB) {
const Common::Point &a = _pathfindingPoints[nodeA - 1]._position;
const Common::Point &b = _pathfindingPoints[nodeB - 1]._position;
- if (!isPathWalkable(a.y, a.x, b.y, b.x))
+ if (!isPathWalkable(a.y, a.x, b.y, b.x)) {
return 0x500;
+ }
// Binary search for integer sqrt(dx^2 + dy^2), matching binary at 1008:1293
int32 dx = abs((int)(b.x - a.x));
int32 dy = abs((int)(b.y - a.y));
@@ -2366,8 +2446,9 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
if (adjCount > 0) {
for (int i = 0; i < adjCount; i++) {
int adj = pt._adjacentPoints[i];
- if (adj == prevNode)
+ if (adj == prevNode) {
continue;
+ }
// Check visited stack
bool alreadyVisited = false;
@@ -2377,8 +2458,9 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
break;
}
}
- if (alreadyVisited)
+ if (alreadyVisited) {
continue;
+ }
// Recursive call
int cost = computeMinCostToReachable(adj, nodeIndex, actorIndex, reachable, nodeCount, finalDest);
@@ -2426,12 +2508,14 @@ void Macs2Engine::setBottomHudVisible(bool visible) {
if (visible) {
if (_menuMode == MenuMode::Hidden) {
_menuMode = MenuMode::Main;
- if (_scriptExecutor)
+ if (_scriptExecutor) {
setCursorMode(_savedMenuCursorMode);
+ }
}
} else {
- if (_menuMode == MenuMode::Main && _scriptExecutor)
+ if (_menuMode == MenuMode::Main && _scriptExecutor) {
_savedMenuCursorMode = _scriptExecutor->_cursorMode;
+ }
_menuMode = MenuMode::Hidden;
}
}
@@ -2448,8 +2532,9 @@ void Macs2Engine::setCursorMode(Script::MouseMode newMode) {
auto cursorHalfSize = [this](Script::MouseMode mode, uint16 &halfW, uint16 &halfH) {
halfW = halfH = 0;
const int index = (int)mode - 1;
- if (index < 0 || index >= (int)_imageResources.size())
+ if (index < 0 || index >= (int)_imageResources.size()) {
return;
+ }
halfW = _imageResources[index]._width / 2;
halfH = _imageResources[index]._height / 2;
};
@@ -2490,11 +2575,13 @@ void Macs2Engine::setCursorMode(Script::MouseMode newMode) {
_clipRectDirty = true;
- if (view)
+ if (view) {
view->updateCursor();
+ }
- if (cursorVisible)
+ if (cursorVisible) {
_needsRedraw = true;
+ }
debugC(kDebugInput, "Cursor mode set to %i (%s)", (int)newMode,
newMode == Script::MouseMode::Talk ? "Talk" : newMode == Script::MouseMode::Look ? "Look"
@@ -2524,8 +2611,9 @@ uint16 Macs2Engine::getHotspotAtPoint(const Common::Point &p) const {
Common::Array<uint16> a = _hotspotColorTable;
do {
- if ((uint)(i - 1) >= a.size())
+ if ((uint)(i - 1) >= a.size()) {
break;
+ }
// Binary compares only the low byte: *(char*)(scene + i*2 + 0x50D3)
uint8 lookup = (uint8)a[i - 1];
if (lookup == firstLookup) {
@@ -2542,18 +2630,21 @@ uint16 Macs2Engine::getHotspotAtPoint(const Common::Point &p) const {
Common::String getObjectHotspotName(uint16 objectIndex) {
const GameObjects &objects = GameObjects::instance();
if (objectIndex > 0 && objectIndex < objects._objectNames.size() && !objects._objectNames[objectIndex].empty()) {
- if (g_engine != nullptr)
+ if (g_engine != nullptr) {
return g_engine->translateHotspotLabel(objects._objectNames[objectIndex]);
+ }
return objects._objectNames[objectIndex];
}
return Common::String();
}
Common::String lookupInteractionDisplayName(uint16 interactionId) {
- if (interactionId >= 0x800)
+ if (interactionId >= 0x800) {
return lookupSceneHotspotName((uint16)Scenes::instance()._currentSceneIndex, (uint16)(interactionId - 0x800));
- if (interactionId >= 0x400)
+ }
+ if (interactionId >= 0x400) {
return getObjectHotspotName((uint16)(interactionId - 0x400));
+ }
return Common::String();
}
@@ -2574,8 +2665,9 @@ void Macs2Engine::rebuildHotspotSnapshot() const {
for (int y = 0; y < _hotspotMap.h; ++y) {
for (int x = 0; x < _hotspotMap.w; ++x) {
const uint8 pixel = _hotspotMap.getPixel(x, y);
- if (pixel == 0)
+ if (pixel == 0) {
continue;
+ }
for (uint16 i = 0; i < _numHotspots; ++i) {
if ((uint8)_hotspotColorTable[i] == pixel) {
@@ -2589,13 +2681,15 @@ void Macs2Engine::rebuildHotspotSnapshot() const {
}
for (uint16 i = 0; i < _numHotspots; ++i) {
- if (count[i] == 0)
+ if (count[i] == 0) {
continue;
+ }
HotspotSnapshot::SceneHotspotEntry entry;
entry.index = i + 1;
- if ((uint)(i + 1) < _hotspotOverrides.size() && _hotspotOverrides[i + 1] != 0xFFFF)
+ if ((uint)(i + 1) < _hotspotOverrides.size() && _hotspotOverrides[i + 1] != 0xFFFF) {
entry.index = _hotspotOverrides[i + 1];
+ }
entry.center = Common::Point(sumX[i] / count[i], sumY[i] / count[i]);
_hotspotSnapshot.sceneHotspots.push_back(entry);
}
@@ -2605,10 +2699,12 @@ void Macs2Engine::rebuildHotspotSnapshot() const {
const uint16 sceneIndex = (uint16)Scenes::instance()._currentSceneIndex;
for (uint16 objectIndex = 1; objectIndex <= kMaxSceneObjects; ++objectIndex) {
GameObject *obj = GameObjects::getObjectByIndex(objectIndex);
- if (obj == nullptr || obj->_dataOffset == 0)
+ if (obj == nullptr || obj->_dataOffset == 0) {
continue;
- if ((int16)obj->_sceneIndex < 0 || obj->_sceneIndex != sceneIndex)
+ }
+ if ((int16)obj->_sceneIndex < 0 || obj->_sceneIndex != sceneIndex) {
continue;
+ }
HotspotSnapshot::SceneObjectEntry entry;
entry.index = objectIndex;
@@ -2630,18 +2726,21 @@ bool Macs2Engine::hotspotDirty() const {
return true;
}
- if (mapMode)
+ if (mapMode) {
return false;
+ }
View1 *view = g_events ? (View1 *)g_events->findView("View1") : nullptr;
const uint16 sceneIndex = (uint16)Scenes::instance()._currentSceneIndex;
uint snapshotIdx = 0;
for (uint16 objectIndex = 1; objectIndex <= kMaxSceneObjects; ++objectIndex) {
GameObject *obj = GameObjects::getObjectByIndex(objectIndex);
- if (obj == nullptr || obj->_dataOffset == 0)
+ if (obj == nullptr || obj->_dataOffset == 0) {
continue;
- if ((int16)obj->_sceneIndex < 0 || obj->_sceneIndex != sceneIndex)
+ }
+ if ((int16)obj->_sceneIndex < 0 || obj->_sceneIndex != sceneIndex) {
continue;
+ }
const Common::Point pos = getSceneObjectHotspotPosition(view, obj);
if (snapshotIdx >= _hotspotSnapshot.sceneObjects.size()) {
@@ -2666,16 +2765,19 @@ bool Macs2Engine::hotspotDirty() const {
}
void Macs2Engine::getHotspotPositions(Common::Array<Graphics::HotspotInfo> &hotspots) {
- if (isMapModeActive())
+ if (isMapModeActive()) {
return;
+ }
for (const HotspotSnapshot::SceneHotspotEntry &entry : _hotspotSnapshot.sceneHotspots) {
- if (entry.index == 0)
+ if (entry.index == 0) {
continue;
+ }
const Common::Point ¢er = entry.center;
- if (center.x < 0 || center.x >= screenWidth() || center.y < 0 || center.y >= gameHeight())
+ if (center.x < 0 || center.x >= screenWidth() || center.y < 0 || center.y >= gameHeight()) {
continue;
+ }
const uint16 sceneIndex = (uint16)Scenes::instance()._currentSceneIndex;
const Common::String name = lookupSceneHotspotName(sceneIndex, entry.index);
@@ -2686,18 +2788,21 @@ void Macs2Engine::getHotspotPositions(Common::Array<Graphics::HotspotInfo> &hots
View1 *view = g_events ? (View1 *)g_events->findView("View1") : nullptr;
const uint16 currentActorIndex = (uint16)Scenes::instance()._currentActorIndex;
for (const HotspotSnapshot::SceneObjectEntry &entry : _hotspotSnapshot.sceneObjects) {
- if (entry.index == currentActorIndex)
+ if (entry.index == currentActorIndex) {
continue;
+ }
const Common::Point &screenPos = entry.position;
- if (screenPos.x < 0 || screenPos.x >= screenWidth() || screenPos.y < 0 || screenPos.y >= gameHeight())
+ if (screenPos.x < 0 || screenPos.x >= screenWidth() || screenPos.y < 0 || screenPos.y >= gameHeight()) {
continue;
+ }
Character *character = view ? view->getCharacterByIndex(entry.index) : nullptr;
const bool isCharacter = character != nullptr && !character->_markedForDeletion;
Graphics::HotspotType hotspotType = Graphics::kHotspotObject;
- if (isCharacter && GameObjects::isNpcIndex(entry.index))
+ if (isCharacter && GameObjects::isNpcIndex(entry.index)) {
hotspotType = Graphics::kHotspotNPC;
+ }
const Common::String &name = getObjectHotspotName(entry.index);
hotspots.emplace_back(Graphics::HotspotInfo(screenPos, hotspotLabelToU32(name), hotspotType));
@@ -2765,17 +2870,20 @@ void Macs2Engine::recordInputFrame(uint16 mouseX, uint16 mouseY, uint16 buttons)
}
bool Macs2Engine::readInputFrame(uint16 &mouseX, uint16 &mouseY, uint16 &buttons) {
- if (!_inputPlaybackStream || _inputPlaybackStream->eos())
+ if (!_inputPlaybackStream || _inputPlaybackStream->eos()) {
return false;
+ }
// Format: each record is [frameCounter(2), mouseX(2), mouseY(2), buttons(2)]
// Playback waits until current frame >= next record's frame counter
- if (_inputFrameCounter < _inputPlaybackEndFrame)
+ if (_inputFrameCounter < _inputPlaybackEndFrame) {
return false;
+ }
mouseX = _inputPlaybackStream->readUint16LE();
mouseY = _inputPlaybackStream->readUint16LE();
buttons = _inputPlaybackStream->readUint16LE();
- if (_inputPlaybackStream->eos())
+ if (_inputPlaybackStream->eos()) {
return false;
+ }
// Read next record's frame counter (or detect end)
_inputPlaybackEndFrame = _inputPlaybackStream->readUint16LE();
return !_inputPlaybackStream->eos();
@@ -2825,8 +2933,9 @@ int Macs2Engine::computeStringIndex(Common::MemoryReadStream *stream, int target
while (stream->pos() < targetOffset && !stream->eos()) {
// DOS: u16LE + XOR ciphertext. Amiga: u16BE + plaintext.
const uint16 len = isAmiga() ? stream->readUint16BE() : stream->readUint16LE();
- if (len == 0)
+ if (len == 0) {
break;
+ }
stream->skip(len);
index++;
}
@@ -2891,8 +3000,9 @@ void Macs2Engine::loadTranslation() {
for (uint16 j = 0; j < sceneIndex[i].numStrings; j++) {
uint16 len = f->readUint16LE();
Common::String s;
- for (uint16 k = 0; k < len; k++)
+ for (uint16 k = 0; k < len; k++) {
s += (char)f->readByte();
+ }
entry.strings.push_back(s);
}
stringDataEnd = MAX(stringDataEnd, (uint32)f->pos());
@@ -2906,8 +3016,9 @@ void Macs2Engine::loadTranslation() {
for (uint16 j = 0; j < objectIndex[i].numStrings; j++) {
uint16 len = f->readUint16LE();
Common::String s;
- for (uint16 k = 0; k < len; k++)
+ for (uint16 k = 0; k < len; k++) {
s += (char)f->readByte();
+ }
entry.strings.push_back(s);
}
stringDataEnd = MAX(stringDataEnd, (uint32)f->pos());
@@ -2918,21 +3029,25 @@ void Macs2Engine::loadTranslation() {
for (uint16 i = 0; i < count; i++) {
uint16 keyLen = f->readUint16LE();
Common::String key;
- for (uint16 k = 0; k < keyLen; k++)
+ for (uint16 k = 0; k < keyLen; k++) {
key += (char)f->readByte();
+ }
uint16 valLen = f->readUint16LE();
Common::String val;
- for (uint16 k = 0; k < valLen; k++)
+ for (uint16 k = 0; k < valLen; k++) {
val += (char)f->readByte();
- if (!key.empty() && !val.empty())
+ }
+ if (!key.empty() && !val.empty()) {
out[key] = val;
+ }
}
};
_hotspotLabelTranslations.clear();
_uiLabelTranslations.clear();
- if (numHotspotLabels > 0 || numUiLabels > 0)
+ if (numHotspotLabels > 0 || numUiLabels > 0) {
f->seek(stringDataEnd);
+ }
readLabelMap(numHotspotLabels, _hotspotLabelTranslations);
readLabelMap(numUiLabels, _uiLabelTranslations);
@@ -2942,20 +3057,24 @@ void Macs2Engine::loadTranslation() {
}
Common::String Macs2Engine::translateHotspotLabel(const Common::String &cp850Name) const {
- if (cp850Name.empty() || !(getFeatures() & GF_TRANSLATED))
+ if (cp850Name.empty() || !(getFeatures() & GF_TRANSLATED)) {
return cp850Name;
+ }
auto it = _hotspotLabelTranslations.find(cp850Name);
- if (it != _hotspotLabelTranslations.end())
+ if (it != _hotspotLabelTranslations.end()) {
return it->_value;
+ }
return cp850Name;
}
Common::String Macs2Engine::translateUiLabel(const Common::String &source) const {
- if (source.empty() || !(getFeatures() & GF_TRANSLATED))
+ if (source.empty() || !(getFeatures() & GF_TRANSLATED)) {
return source;
+ }
auto it = _uiLabelTranslations.find(source);
- if (it != _uiLabelTranslations.end())
+ if (it != _uiLabelTranslations.end()) {
return it->_value;
+ }
return source;
}
@@ -2968,8 +3087,9 @@ Common::StringArray Macs2Engine::decodeStrings(Common::MemoryReadStream *stream,
for (int i = 0; i < numStrings; i++) {
Common::String currentLine;
const uint16 length = stream->readUint16BE();
- for (uint16 index = 0; index < length; index++)
+ for (uint16 index = 0; index < length; index++) {
currentLine += (char)stream->readByte();
+ }
result[i] = currentLine;
}
} else {
@@ -3049,17 +3169,21 @@ bool Macs2Engine::loadAnimationFromSceneData(uint16 objectIndex, uint16 slotInde
const uint16 minSlots = maxAnimSlots();
const uint16 overloadSlot = overloadAnimSlot();
- while (go->_blobs.size() < minSlots)
+ while (go->_blobs.size() < minSlots) {
go->_blobs.push_back(Common::Array<uint8>());
- while (go->_blobSourceKeys.size() < minSlots)
+ }
+ while (go->_blobSourceKeys.size() < minSlots) {
go->_blobSourceKeys.push_back(0);
- while (go->_blobMirrorFlags.size() < minSlots)
+ }
+ while (go->_blobMirrorFlags.size() < minSlots) {
go->_blobMirrorFlags.push_back(false);
+ }
Common::Array<uint8> *targetBlob = nullptr;
if (slotIndex == overloadSlot) {
- while (go->_blobs.size() <= (uint)(overloadSlot - 1))
+ while (go->_blobs.size() <= (uint)(overloadSlot - 1)) {
go->_blobs.push_back(Common::Array<uint8>());
+ }
targetBlob = &go->_blobs[overloadSlot - 1];
go->_overloadAnimationSourceKey = static_cast<uint16>(address >> 16);
go->_overloadAnimationMirrored = shouldMirror;
@@ -3072,8 +3196,9 @@ bool Macs2Engine::loadAnimationFromSceneData(uint16 objectIndex, uint16 slotInde
// Binary: memFree old blob if bSlotLoaded, then alloc + read; sets slot+0x33 = 1.
*targetBlob = data;
- if (slotIndex == overloadSlot)
+ if (slotIndex == overloadSlot) {
go->_overloadAnimation = data;
+ }
if (shouldMirror) {
BackgroundAnimationBlob::mirrorAnimBlob(*targetBlob);
}
@@ -3081,12 +3206,14 @@ bool Macs2Engine::loadAnimationFromSceneData(uint16 objectIndex, uint16 slotInde
}
void Macs2Engine::sortObjectsByDepth(uint16 objectIndex) {
- if (objectIndex < 1 || objectIndex > 0x200)
+ if (objectIndex < 1 || objectIndex > 0x200) {
return;
+ }
GameObject *obj = GameObjects::getObjectByIndex(objectIndex);
- if (obj == nullptr || obj->_dataOffset == 0)
+ if (obj == nullptr || obj->_dataOffset == 0) {
return;
+ }
View1 *currentView = (View1 *)findView("View1");
if (currentView != nullptr && currentView->_activeInventoryItem != nullptr &&
@@ -3165,8 +3292,9 @@ bool Macs2Engine::loadObjectData(GameObject *obj) {
};
const uint16 animSlotCount = maxAnimSlots();
- if (isV2())
+ if (isV2()) {
_fileStream->readUint16LE(); // ReadyObject lead word before anim slots
+ }
for (int j = 0; j < (int)animSlotCount; j++) {
_fileStream->readUint16LE(); // animID (editor metadata, unused at runtime)
uint16 blobSourceKey = _fileStream->readUint16LE();
@@ -3229,10 +3357,11 @@ bool Macs2Engine::loadObjectData(GameObject *obj) {
_fileStream->readByte(); // runtime+0x184 hasInventoryIcon (derived from slot 0x13 in C++)
obj->_hasShading = _fileStream->readByte() != 0;
obj->_hasScaling = _fileStream->readByte() != 0;
- if (isV2())
+ if (isV2()) {
obj->_hasDoubleResAnim = _fileStream->readByte() != 0;
- else
+ } else {
obj->_hasDoubleResAnim = false;
+ }
if (obj->_blobs.size() > 0x11 && !obj->_blobs[0x11].empty()) {
const uint16 frameCount = BackgroundAnimationBlob::getAnimFrameCount(obj->_blobs[0x11]);
@@ -3244,8 +3373,9 @@ bool Macs2Engine::loadObjectData(GameObject *obj) {
}
obj->_overloadAnimTriggerDirection = 0x7FFF;
- for (uint i = 0; i < ARRAYSIZE(obj->_specialAnimTriggers); i++)
+ for (uint i = 0; i < ARRAYSIZE(obj->_specialAnimTriggers); i++) {
obj->_specialAnimTriggers[i] = 0x7FFF;
+ }
obj->_useOverloadAnimation = false;
obj->_overloadAnimation.clear();
obj->_snapToTarget = false;
@@ -3254,7 +3384,6 @@ bool Macs2Engine::loadObjectData(GameObject *obj) {
obj->_boundsAttachmentValue1 = 0;
obj->_boundsAttachmentValue2 = 0;
obj->_boundsAttachmentValue3 = 0;
- // Binary loadObjectData (1008:08ec): runtime+0x21D = object vertical offset.
obj->_storedWalkRuntime.motionTargetVerticalOffset = obj->_verticalOffsetScale;
const uint32 scriptTableOffset = getMcsDirectoryOffset() + kMcsV1ObjectScriptPtrRel + obj->_index * 0xC;
diff --git a/engines/macs2/macs2.h b/engines/macs2/macs2.h
index 56944b65885..4c523b18af0 100644
--- a/engines/macs2/macs2.h
+++ b/engines/macs2/macs2.h
@@ -96,8 +96,6 @@ public:
};
struct Macs2GameDescription;
-
-// enum class CursorMode { Talk = 0, Look = 1, Touch = 2, Walk = 3};
class Music;
struct Sprite {
@@ -210,21 +208,39 @@ struct AnimBlobView {
explicit AnimBlobView(const Common::Array<uint8> &blob) : _blob(blob) {}
- bool isValid() const { return _blob.size() >= 14; } // header(12) + at least 2 bytes frame count
+ bool isValid() const {
+ return _blob.size() >= 14;
+ }
+
+ uint16 sequencePosition() const {
+ return READ_LE_UINT16(&_blob[0x02]);
+ }
+
+ uint16 repeatCounter() const {
+ return READ_LE_UINT16(&_blob[0x04]);
+ }
+
+ uint16 loopStartPosition() const {
+ return READ_LE_UINT16(&_blob[0x06]);
+ }
+
+ uint16 delayCounter() const {
+ return READ_LE_UINT16(&_blob[0x08]);
+ }
- // Header fields
- uint16 sequencePosition() const { return READ_LE_UINT16(&_blob[0x02]); }
- uint16 repeatCounter() const { return READ_LE_UINT16(&_blob[0x04]); }
- uint16 loopStartPosition() const { return READ_LE_UINT16(&_blob[0x06]); }
- uint16 delayCounter() const { return READ_LE_UINT16(&_blob[0x08]); }
- uint16 sequenceLength() const { return READ_LE_UINT16(&_blob[0x0A]) + 1; }
+ uint16 sequenceLength() const {
+ return READ_LE_UINT16(&_blob[0x0A]) + 1;
+ }
+
+ uint32 frameDataOffset() const {
+ return 0x0B + sequenceLength();
+ }
- // Derived offsets
- uint32 frameDataOffset() const { return 0x0B + sequenceLength(); }
uint16 frameCount() const {
- uint32 off = frameDataOffset();
- if (off + 2 > _blob.size())
+ const uint32 off = frameDataOffset();
+ if (off + 2 > _blob.size()) {
return 0;
+ }
return READ_LE_UINT16(&_blob[off]);
}
@@ -241,16 +257,18 @@ struct AnimBlobView {
bool getFrameInfo(uint16 index, FrameInfo &out) const {
uint32 pos = frameDataOffset() + 2; // skip frame count word
for (uint16 i = 0; i <= index; i++) {
- if (pos + 10 > _blob.size())
+ if (pos + 10 > _blob.size()) {
return false;
- int16 ox = (int16)READ_LE_UINT16(&_blob[pos]);
- int16 oy = (int16)READ_LE_UINT16(&_blob[pos + 2]);
- uint16 unk = READ_LE_UINT16(&_blob[pos + 4]);
- uint16 w = READ_LE_UINT16(&_blob[pos + 6]);
- uint16 h = READ_LE_UINT16(&_blob[pos + 8]);
+ }
+ const int16 ox = (int16)READ_LE_UINT16(&_blob[pos]);
+ const int16 oy = (int16)READ_LE_UINT16(&_blob[pos + 2]);
+ const uint16 unk = READ_LE_UINT16(&_blob[pos + 4]);
+ const uint16 w = READ_LE_UINT16(&_blob[pos + 6]);
+ const uint16 h = READ_LE_UINT16(&_blob[pos + 8]);
pos += 10;
- if (w == 0 || h == 0 || pos + (uint32)w * h > _blob.size())
+ if (w == 0 || h == 0 || pos + (uint32)w * h > _blob.size()) {
return false;
+ }
if (i == index) {
out = {ox, oy, unk, w, h, &_blob[pos]};
return true;
@@ -308,7 +326,7 @@ public:
V2 // AHFFMACS0200
};
McsFileVersion detectMcsFileVersion(Common::SeekableReadStream &stream) const;
- /** Load AHFFMACS0100 layout (loadResourceFile @ 1008:2e8d). */
+ /** Load AHFFMACS0100 layout */
void loadResourceFileV1();
/** Load AHFFMACS0200 layout */
void loadResourceFileV2();
@@ -326,22 +344,14 @@ public:
* seed them from MXIN chrome (copper base16 layout).
*/
void installAmigaPortraitPalette(bool copyFromPlayfield);
- /**
- * Build _panelRemapTable from luminance buckets (Ghidra fill_ui_panel_darken_remap
- * @ 002221fe). Outputs into private UI bank 0xF0.. so playfield/intro colors
- * at MXIN darken indices are never overwritten.
- */
void buildAmigaPanelRemapTable();
bool loadAmigaCursorResource(uint16 resourceId, AnimFrame &out);
- /** Load FF_0000 MXFF into `_glyphs` (Ghidra drawText / g_pFont1Data). */
bool loadAmigaMxffFont();
- /** Opcode 0x38 overlay font: FF_* from DataA, else copy the main MXFF glyphs. */
bool loadAmigaOverlayFont(uint8 resourceIndex);
- /** Load one FF_* MXFF into `_overlayGlyphs`. Returns false if missing/undecodable. */
bool loadAmigaOverlayFontResource(uint16 ffId);
/**
* Amiga: load native MM_* MXMM package by resource id (not script scene id).
- * Script-visible scene ids are resourceId+1 (Ghidra FUN_002215fa / load_scene_mxmm).
+ * Script-visible scene ids are resourceId+1.
* Also extracts trailer script/strings into _amigaPendingScene* for changeScene.
* Palette indices 0..31 stay Amiga COLOR registers for OO sprite compatibility.
*/
diff --git a/engines/macs2/macs2_constants.h b/engines/macs2/macs2_constants.h
index bc6539ac1f0..57140a8c2c2 100644
--- a/engines/macs2/macs2_constants.h
+++ b/engines/macs2/macs2_constants.h
@@ -22,6 +22,8 @@
#ifndef MACS2_CONSTANTS_H
#define MACS2_CONSTANTS_H
+#include "common/scummsys.h"
+
namespace Macs2 {
// V1 (AHFFMACS0100) viewport - default engine dimensions.
diff --git a/engines/macs2/scriptexecutor.cpp b/engines/macs2/scriptexecutor.cpp
index 466b025c709..12c593196c5 100644
--- a/engines/macs2/scriptexecutor.cpp
+++ b/engines/macs2/scriptexecutor.cpp
@@ -491,8 +491,9 @@ void ScriptExecutor::clearScriptUiWaitState() {
}
void ScriptExecutor::recordScriptErrorPosition() {
- if (!hasScriptError() || !_stream)
+ if (!hasScriptError() || !_stream) {
return;
+ }
// save position and scene/object context on halt.
_errorScriptPosition = (uint32)_stream->pos();
if (_executingScriptObjectId == 0) {
@@ -518,8 +519,9 @@ void ScriptExecutor::runSceneScriptPass(bool initRun, bool repeatRun) {
const ExecutorState previousState = _state;
_state = ExecutorState::Executing;
step();
- if (_state != ExecutorState::WaitingForCallback)
+ if (_state != ExecutorState::WaitingForCallback) {
_state = previousState;
+ }
}
void ScriptExecutor::beginSceneEntryInitPass() {
@@ -535,13 +537,15 @@ void ScriptExecutor::beginSceneEntryInitPass() {
}
void ScriptExecutor::finishSceneEntryRepeatPass(bool terminateOuterScript) {
- if (!_initPassComplete || hasScriptError())
+ if (!_initPassComplete || hasScriptError()) {
return;
+ }
// Binary scriptChangeScene / loadResourceFile: set script position to end and
// executingObjectId=0x201 to stop outer object iteration, then repeat pass.
if (terminateOuterScript) {
- if (_stream)
+ if (_stream) {
_stream->seek(_stream->size(), SEEK_SET);
+ }
_executingScriptObjectId = 0x201;
_terminateOuterScriptBeforeRepeat = false;
}
@@ -1860,7 +1864,7 @@ Character *Script::ScriptExecutor::getOrCreateCharacter(uint16 objectID) {
return c;
}
-void Script::ScriptExecutor::saveWalkRuntime(const Character *c, GameObject *o) {
+void Script::ScriptExecutor::saveWalkRuntime(const Character *c, GameObject *o) const {
if (c == nullptr || o == nullptr)
return;
GameObject::StoredWalkRuntime &s = o->_storedWalkRuntime;
diff --git a/engines/macs2/scriptexecutor.h b/engines/macs2/scriptexecutor.h
index f1e76318248..dd42d067742 100644
--- a/engines/macs2/scriptexecutor.h
+++ b/engines/macs2/scriptexecutor.h
@@ -611,7 +611,7 @@ public:
// g_wScriptErrorCode (1020:0f86): non-zero halts opcode dispatch (1008:db56).
uint16 _scriptErrorCode = 0;
Character *getOrCreateCharacter(uint16 objectID);
- void saveWalkRuntime(const Character *c, GameObject *o);
+ void saveWalkRuntime(const Character *c, GameObject *o) const;
void restoreWalkRuntime(Character *c, const GameObject *o);
void clearStoredWalkRuntime(GameObject *o);
void seedMoveToPositionState(GameObject *object, Character *c, const Common::Point &target, uint16 targetVerticalOffset);
Commit: 9f955ecc232d91b2c1f2a35e109a8392bbf55fa5
https://github.com/scummvm/scummvm/commit/9f955ecc232d91b2c1f2a35e109a8392bbf55fa5
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: const + extract to local variable
Changed paths:
engines/macs2/view1.cpp
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 9a6d276484b..11a84db0596 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -20,6 +20,7 @@
*/
#include "macs2/view1.h"
+#include "common/ptr.h"
#include "common/util.h"
#include "common/config-manager.h"
#include "common/debug-channels.h"
@@ -231,10 +232,7 @@ View1::View1() : UIElement("View1") {
_bounds = Common::Rect(0, 0, sw, sh);
_innerBounds = _bounds;
- // TODO: Check if this works like this
Character *protagonist = new Character();
- // TODO: Need to properly handle the offset
- // TODO: Remember that the game starts enumerating objects at 1 and not at 0
protagonist->_gameObject = GameObjects::instance()._objects[0x0];
_characters.push_back(protagonist);
rebuildCharacterLookupTable();
@@ -248,12 +246,14 @@ View1::View1() : UIElement("View1") {
}
void View1::ensureActionBar() {
- if (!hasPersistentActionBar())
+ if (!hasPersistentActionBar()) {
return;
+ }
if (!_actionBar) {
_actionBar = new ActionBar(this);
- if (_inventorySource)
+ if (_inventorySource) {
setInventorySource(_inventorySource);
+ }
}
const int sw = g_engine->screenWidth();
const int sh = g_engine->screenHeight();
@@ -268,32 +268,40 @@ bool View1::hasPersistentActionBar() const {
}
int View1::actionBarTopY() const {
- if (_actionBar && shouldShowActionBar())
+ if (_actionBar && shouldShowActionBar()) {
return _actionBar->gameAreaBottomY();
- if (g_engine->hasNativeHudAssets() && g_engine->isBottomHudVisible() && g_engine->_menuMode != MenuMode::Hidden)
+ }
+ if (g_engine->hasNativeHudAssets() && g_engine->isBottomHudVisible() && g_engine->_menuMode != MenuMode::Hidden) {
return (int)g_engine->_panelTopY;
+ }
return g_engine->gameHeight();
}
bool View1::shouldShowActionBar() const {
- if (!hasPersistentActionBar())
+ if (!hasPersistentActionBar()) {
return false;
- if (!g_engine->isBottomHudVisible())
+ }
+ if (!g_engine->isBottomHudVisible()) {
return false;
- if (_currentMode == ViewMode::VM_HELP)
+ }
+ if (_currentMode == ViewMode::VM_HELP) {
return false;
- if (_uiPanelState == kUiPanelSaveLoad)
+ }
+ if (_uiPanelState == kUiPanelSaveLoad) {
return false;
+ }
// Scumm strip only: native HUD stays up during speech/choices (DisplayMenu
// is independent of AddText / TalkTo; mode 4 draws choices in the panel).
if (!g_engine->hasNativeHudAssets() &&
- (_isShowingDialoguePanel || _isDialogueChoiceInputActive || _isShowingTextBox))
+ (_isShowingDialoguePanel || _isDialogueChoiceInputActive || _isShowingTextBox)) {
return false;
+ }
// Use the actor object table directly; Character lookup can lag behind scene changes.
const GameObject *actor = GameObjects::getObjectByIndex(Scenes::instance()._currentActorIndex);
- if (!actor)
+ if (!actor) {
return false;
+ }
const uint16 scene = (uint16)Scenes::instance()._currentSceneIndex;
return actor->_sceneIndex == scene;
@@ -315,21 +323,22 @@ void View1::applyPaletteWithFade(const Graphics::Palette &sourcePalette, int fad
void View1::setViewPaletteSafely(const Graphics::Palette &colors) {
const bool shouldTouchCursor = _cursorSuppressedForFade;
const bool cursorWasVisible = shouldTouchCursor && CursorMan.isVisible();
- if (cursorWasVisible)
+ if (cursorWasVisible) {
CursorMan.showMouse(false);
+ }
- if (shouldTouchCursor)
+ if (shouldTouchCursor) {
updateCursor(&colors);
+ }
g_system->getPaletteManager()->setPalette(colors);
- if (cursorWasVisible)
+ if (cursorWasVisible) {
CursorMan.showMouse(true);
+ }
}
void View1::restoreUiPaletteEntries() {
- // Binary setPaletteRange(0xF0, 0x10, palette+0x30) after applyScenePaletteEffect:
- // push VGA indices 0xF0..0xFF from palette color slots 0x10..0x1F.
g_system->getPaletteManager()->setPalette(g_engine->_pal.data() + 16 * 3, 0xF0, 16);
}
@@ -344,8 +353,9 @@ void View1::openInventory(GameObject *newInventorySource) {
// SCUMM verb UI: protagonist inventory is always visible in the strip.
if (hasPersistentActionBar() && newInventorySource->_index == Scenes::instance()._currentActorIndex) {
- if (_actionBar)
+ if (_actionBar) {
_actionBar->syncInventory();
+ }
redraw();
return;
}
@@ -414,8 +424,9 @@ void View1::setInventorySource(GameObject *newInventorySource) {
_inventoryItems.push_back(currentObject);
}
}
- if (hasPersistentActionBar() && _actionBar)
+ if (hasPersistentActionBar() && _actionBar) {
_actionBar->syncInventory();
+ }
}
void View1::refreshProtagonistInventoryAfterLoad(uint16 actorIndex) {
@@ -424,13 +435,15 @@ void View1::refreshProtagonistInventoryAfterLoad(uint16 actorIndex) {
Common::Array<GameObject *> validated;
for (GameObject *obj : _inventoryItems) {
- if (obj && obj->_sceneIndex == invScene)
+ if (obj && obj->_sceneIndex == invScene) {
validated.push_back(obj);
+ }
}
for (GameObject *obj : GameObjects::instance()._objects) {
- if (!obj || obj->_sceneIndex != invScene)
+ if (!obj || obj->_sceneIndex != invScene) {
continue;
+ }
bool found = false;
for (GameObject *listed : validated) {
@@ -439,14 +452,16 @@ void View1::refreshProtagonistInventoryAfterLoad(uint16 actorIndex) {
break;
}
}
- if (!found)
+ if (!found) {
validated.push_back(obj);
+ }
}
_inventoryItems = validated;
- if (hasPersistentActionBar() && _actionBar)
+ if (hasPersistentActionBar() && _actionBar) {
_actionBar->resetInventoryAfterLoad();
+ }
}
bool View1::isInventorySourceProtagonist() const {
@@ -455,7 +470,7 @@ bool View1::isInventorySourceProtagonist() const {
}
void View1::transferInventoryItem(GameObject *item, GameObject *targetContainer) {
- int index = findInventoryItem(item);
+ const int index = findInventoryItem(item);
_inventoryItems.remove_at(index);
item->_sceneIndex = targetContainer->_index + 0x400;
if (hasPersistentActionBar() && _actionBar)
@@ -474,8 +489,9 @@ int View1::findInventoryItem(const GameObject *item) {
Character *View1::getCharacterByIndex(uint16 index) const {
if (index > 0 && index <= kMaxSceneObjects) {
Character *c = _characterByObjectIndex[index];
- if (c != nullptr && c->_gameObject != nullptr && c->_gameObject->_index == index)
+ if (c != nullptr && c->_gameObject != nullptr && c->_gameObject->_index == index) {
return c;
+ }
}
return nullptr;
}
@@ -490,28 +506,30 @@ void View1::rebuildCharacterLookupTable() const {
}
void View1::sortObjectListByY() const {
- // sortObjectListByY @ 1008:8cf2 - 1-based FAC table @ 0xFAC
_sortedObjectCount = 0;
const uint16 sceneIndex = (uint16)Scenes::instance()._currentSceneIndex;
for (uint16 objectIndex = 1; objectIndex <= kMaxSceneObjects; objectIndex++) {
- GameObject *obj = GameObjects::getObjectByIndex(objectIndex);
- if (obj == nullptr || obj->_dataOffset == 0)
+ const GameObject *obj = GameObjects::getObjectByIndex(objectIndex);
+ if (obj == nullptr || obj->_dataOffset == 0) {
continue;
- if ((int16)obj->_sceneIndex < 0 || obj->_sceneIndex != sceneIndex)
+ }
+ if ((int16)obj->_sceneIndex < 0 || obj->_sceneIndex != sceneIndex) {
continue;
+ }
_sortedObjectIndices[++_sortedObjectCount] = objectIndex;
}
- if (_sortedObjectCount > 1)
+ if (_sortedObjectCount > 1) {
buildSortedObjectList(1, (int)_sortedObjectCount);
+ }
}
void View1::buildSortedObjectList(int low, int high) const {
- // buildSortedObjectList @ 1008:8c5a - quicksort slots [low..high] by object Y (+0x02)
- if (low >= high)
+ if (low >= high) {
return;
+ }
auto objectY = [](uint16 objectIndex) -> int {
- GameObject *obj = GameObjects::getObjectByIndex(objectIndex);
+ const GameObject *obj = GameObjects::getObjectByIndex(objectIndex);
return obj ? obj->_position.y : 0;
};
@@ -519,20 +537,24 @@ void View1::buildSortedObjectList(int low, int high) const {
int i = low;
int j = high;
while (i <= j) {
- while (objectY(_sortedObjectIndices[i]) < pivotY)
+ while (objectY(_sortedObjectIndices[i]) < pivotY) {
i++;
- while (pivotY < objectY(_sortedObjectIndices[j]))
+ }
+ while (pivotY < objectY(_sortedObjectIndices[j])) {
j--;
+ }
if (i <= j) {
SWAP(_sortedObjectIndices[i], _sortedObjectIndices[j]);
i++;
j--;
}
}
- if (low < j)
+ if (low < j) {
buildSortedObjectList(low, j);
- if (i < high)
+ }
+ if (i < high) {
buildSortedObjectList(i, high);
+ }
}
void View1::updateCursor(const Graphics::Palette *palette) {
@@ -584,10 +606,11 @@ void View1::updateCursor(const Graphics::Palette *palette) {
}
byte r, g, b;
- if (colorIndex < activePalette.size())
+ if (colorIndex < activePalette.size()) {
activePalette.get(colorIndex, r, g, b);
- else
+ } else {
r = g = b = 0;
+ }
rgbaCursor[i] = rgbaCursorFormat.RGBToColor(r, g, b);
}
@@ -650,11 +673,9 @@ void View1::drawDarkRectangle(uint16 x, uint16 y, uint16 width, uint16 height) {
void View1::drawBackgroundAnimations(Graphics::ManagedSurface &s) {
for (int i = 0; i < (int)g_engine->_backgroundAnimations.size(); i++) {
- BackgroundAnimation ¤t = g_engine->_backgroundAnimations[i];
+ const BackgroundAnimation ¤t = g_engine->_backgroundAnimations[i];
BackgroundAnimationBlob ¤tBlob = g_engine->_backgroundAnimationsBlobs[i];
Common::Array<uint8> &blob = currentBlob.activeBlob();
- // Binary drawAllCharacters (1008:90a2): null bg-anim blob -> error 0x08;
- // zero frame count -> error 0x0B; aborts entire draw pass.
if (blob.empty()) {
g_engine->_scriptExecutor->setScriptError(8);
return;
@@ -664,11 +685,10 @@ void View1::drawBackgroundAnimations(Graphics::ManagedSurface &s) {
g_engine->_scriptExecutor->setScriptError(view.frameCount() == 0 ? 0x0B : 8);
return;
}
- // Binary drawAllCharacters (1008:929c): drawAnimFrame(2, y, x+1, blob) - one
- // advanceAnimFrame(save=1, mode=2) per frame, not a separate tick advance.
const uint32 frameStart = BackgroundAnimationBlob::advanceAnimFrame(blob, true, 2);
- if (frameStart == 0 || frameStart + 10 > blob.size())
+ if (frameStart == 0 || frameStart + 10 > blob.size()) {
continue;
+ }
const int16 frameOffsetX = (int16)READ_LE_UINT16(&blob[frameStart]);
const int16 frameOffsetY = (int16)READ_LE_UINT16(&blob[frameStart + 2]);
AnimFrame currentFrame;
@@ -708,12 +728,12 @@ void View1::drawCurrentSpeaker(Graphics::ManagedSurface &s) {
// Select portrait blob: primary (Blobs[17]) during countdown, alternate (Blobs[18]) after
// Mode 0: render current frame without advancing (advance happens in tick())
- AnimFrame *frame = currentSpeechActData.speaker->getCurrentPortrait(useAlternateBlob, 0);
- if (frame == nullptr) {
+ Common::ScopedPtr<AnimFrame> frame(currentSpeechActData.speaker->getCurrentPortrait(useAlternateBlob, 0));
+ if (!frame) {
return;
}
- AnimFrame *leftPortrait = currentSpeechActData.speaker->getCurrentPortrait(false, 0);
- AnimFrame *rightPortrait = currentSpeechActData.speaker->getCurrentPortrait(true, 0);
+ Common::ScopedPtr<AnimFrame> leftPortrait(currentSpeechActData.speaker->getCurrentPortrait(false, 0));
+ Common::ScopedPtr<AnimFrame> rightPortrait(currentSpeechActData.speaker->getCurrentPortrait(true, 0));
Common::Point pos = currentSpeechActData.position;
if (!g_engine->isAmiga()) {
@@ -726,9 +746,6 @@ void View1::drawCurrentSpeaker(Graphics::ManagedSurface &s) {
pos += Common::Point(contentInset, contentInset);
}
drawSprite(pos, frame->_width, frame->_height, frame->_data.data(), s, false);
- delete frame;
- delete leftPortrait;
- delete rightPortrait;
}
void View1::renderString(uint16 x, uint16 y, const Common::String &s) {
@@ -748,7 +765,7 @@ void View1::renderString(uint16 x, uint16 y, const Common::String &s) {
// Second pass: render with correct spacing
for (auto iter = s.begin(); iter != s.end(); iter++) {
GlyphData data;
- bool found = g_engine->findGlyph(*iter, data);
+ const bool found = g_engine->findGlyph(*iter, data);
if (found) {
drawSprite(currentX, currentY, data, surf, false);
currentX += data._width + 1;
@@ -804,8 +821,9 @@ int View1::measureStringWithFont(const Common::String &s, const GlyphData *glyph
break;
}
}
- if (!found)
+ if (!found) {
width += widestGlyph;
+ }
}
return width;
}
@@ -832,8 +850,9 @@ void View1::renderStringWithFontTo(uint16 x, uint16 y, const Common::String &s,
break;
}
}
- if (!found)
+ if (!found) {
currentX += widestGlyph;
+ }
}
}
@@ -853,10 +872,10 @@ void View1::clearOverlayTextEntries() {
void View1::drawOverlayTextEntries() {
for (const OverlayTextEntry &entry : _overlayTextEntries) {
int x = entry.position.x;
- Common::String text = entry.text;
+ const Common::String &text = entry.text;
// Use overlay font if loaded, otherwise fall back to main font
const GlyphData *font = g_engine->numOverlayGlyphs > 0 ? g_engine->_overlayGlyphs : g_engine->_glyphs;
- uint16 fontCount = g_engine->numOverlayGlyphs > 0 ? g_engine->numOverlayGlyphs : g_engine->_numGlyphs;
+ const uint16 fontCount = g_engine->numOverlayGlyphs > 0 ? g_engine->numOverlayGlyphs : g_engine->_numGlyphs;
if (entry.alignment == 1) {
x -= measureStringWithFont(text, font, fontCount);
@@ -864,8 +883,9 @@ void View1::drawOverlayTextEntries() {
x -= measureStringWithFont(text, font, fontCount) / 2;
}
- if (x < 0)
+ if (x < 0) {
x = 0;
+ }
logRenderedText("Overlay", x, entry.position.y, text);
renderStringWithFont(x, entry.position.y, text, font, fontCount);
@@ -877,8 +897,8 @@ void View1::showStringBox(const Common::StringArray &sa) {
const int padH = g_engine->dialogPadH();
const int textInset = g_engine->dialogTextInset();
const int lineHeight = g_engine->dialogLineHeight();
- int totalWidth = g_engine->measureStrings(sa) + padW;
- int totalHeight = g_engine->measureStringsVertically(sa) + padH;
+ const int totalWidth = g_engine->measureStrings(sa) + padW;
+ const int totalHeight = g_engine->measureStringsVertically(sa) + padH;
g_engine->_textLog.push_back(Common::String::format(
"Render text box: lines=%u pos=(%d,%d) size=(%d,%d) text=\"", sa.size(),
_stringBoxPosition.x, _stringBoxPosition.y, totalWidth, totalHeight) +
@@ -903,10 +923,10 @@ void View1::drawPathfindingPoints(Graphics::ManagedSurface &s) {
yOffset = xData._height / 2;
}
for (int i = 0; i < 16; i++) {
- PathfindingPoint ¤t = g_engine->_pathfindingPoints[i];
+ const PathfindingPoint ¤t = g_engine->_pathfindingPoints[i];
renderString(current._position.x - xOffset, current._position.y - yOffset, "x");
- Common::String number = Common::String::format("%u", i);
+ const Common::String &number = Common::String::format("%u", i);
renderString(current._position.x - xOffset + 10, current._position.y - yOffset + 10, number.c_str());
for (uint8 adjacentIndex : current._adjacentPoints) {
@@ -919,7 +939,7 @@ void View1::drawPathfindingPoints(Graphics::ManagedSurface &s) {
}
// Draw the test results
- Macs2::Character *c = getCharacterByIndex(Scenes::instance()._currentActorIndex);
+ const Macs2::Character *c = getCharacterByIndex(Scenes::instance()._currentActorIndex);
// Handle the active actor not being in the scene
if (c == nullptr) {
return;
@@ -976,8 +996,9 @@ void View1::layoutActionBarButtons() {
}
void View1::openMainMenu(Common::Point clickedPosition) {
- if (hasPersistentActionBar())
+ if (hasPersistentActionBar()) {
return;
+ }
// Binary handleInput: save cursor and set to PanelCursor (0x19)
_savedCursorMode = g_engine->_scriptExecutor->_cursorMode;
@@ -1017,16 +1038,18 @@ void View1::openMainMenu(Common::Point clickedPosition) {
}
void View1::openScriptActionBar(const Common::Point &position, Script::MouseMode restoreCursorMode) {
- if (_uiPanelState != kUiPanelNone || hasPersistentActionBar())
+ if (_uiPanelState != kUiPanelNone || hasPersistentActionBar()) {
return;
+ }
openMainMenu(position);
g_engine->setCursorMode(restoreCursorMode);
updateCursor();
}
void View1::closeScriptActionBar(Script::MouseMode &outSavedCursorMode) {
- if (_uiPanelState != kUiPanelActionBar)
+ if (_uiPanelState != kUiPanelActionBar) {
return;
+ }
outSavedCursorMode = g_engine->_scriptExecutor->_cursorMode;
_uiPanelState = kUiPanelNone;
_clickedButtonIndex = 0;
@@ -1038,7 +1061,7 @@ void View1::enterMapMode() {
// Binary handleInput end-block when scene+0x61db != 0 (1008:e8bf): fade, load map
// from scene+0x5DDB (_mapSceneOffsets[0]), set cursor 0x18 (PanelUse).
// this path is the DOS help-map overlay
- uint32 helpOffset = g_engine->_mapSceneOffsets[0];
+ const uint32 helpOffset = g_engine->_mapSceneOffsets[0];
if (helpOffset == 0 || helpOffset >= (uint32)g_engine->_fileStream->size()) {
return;
}
@@ -1071,7 +1094,7 @@ void View1::drawMainMenu(Graphics::ManagedSurface &s) {
const BorderStyle &border = pressed ? kBorderPressed : kBorderRaised;
drawNinePatchBorder(Common::Point(cell.left, cell.top), Common::Point(cell.width(), cell.height()), border, false, false, s);
- AnimFrame &frame = g_engine->_imageResources[i];
+ const AnimFrame &frame = g_engine->_imageResources[i];
const int pressOffset = pressed ? 1 : 0;
const uint16 iconX = cell.left + (cell.width() - frame._width) / 2 + pressOffset;
const uint16 iconY = cell.top + (cell.height() - frame._height) / 2 + pressOffset;
@@ -1121,13 +1144,13 @@ bool View1::handleDialogueChoiceClick(int clickY, int clickX) {
return false;
}
- int lineHeight = g_engine->dialogLineHeight();
- int firstLineY = _stringBoxPosition.y + textInset;
- int relY = clickY - firstLineY;
+ const int lineHeight = g_engine->dialogLineHeight();
+ const int firstLineY = _stringBoxPosition.y + textInset;
+ const int relY = clickY - firstLineY;
debug("handleDialogueChoiceClick: clickY=%d firstLineY=%d relY=%d lineHeight=%d clickedLine=%d",
clickY, firstLineY, relY, lineHeight, relY >= 0 ? relY / lineHeight : -1);
if (relY >= 0) {
- int clickedLine = relY / lineHeight;
+ const int clickedLine = relY / lineHeight;
int cumulativeLines = 0;
for (uint i = 0; i < _dialogueChoiceLineCounts.size(); i++) {
cumulativeLines += _dialogueChoiceLineCounts[i];
@@ -1248,8 +1271,9 @@ void View1::startFading(uint16 speed) {
void View1::fadePaletteToBlack(uint16 speed, const Graphics::Palette &sourcePalette) {
// Blocking fade to black matching DOS fadePaletteToBlack (1010:00ba).
- if (speed == 0)
+ if (speed == 0) {
speed = 4;
+ }
beginFadeCursorSuppression();
// Ensure current frame is on screen before fading
@@ -1259,7 +1283,7 @@ void View1::fadePaletteToBlack(uint16 speed, const Graphics::Palette &sourcePale
uint fadeValue = 0;
while (fadeValue <= 0x40 && !g_system->getEventManager()->shouldQuit()) {
- uint32 frameStart = g_system->getMillis();
+ const uint32 frameStart = g_system->getMillis();
Graphics::Palette colors(Graphics::PALETTE_COUNT);
buildFadedPalette(colors, sourcePalette, fadeValue);
@@ -1270,15 +1294,17 @@ void View1::fadePaletteToBlack(uint16 speed, const Graphics::Palette &sourcePale
Common::Event evt;
while (g_system->getEventManager()->pollEvent(evt)) {
- if (evt.type == Common::EVENT_QUIT)
+ if (evt.type == Common::EVENT_QUIT) {
break;
+ }
}
// Original syncs to VGA vsync during palette writes. On real hardware
// writing 768 bytes to the DAC takes most of one frame period.
- uint32 elapsed = g_system->getMillis() - frameStart;
- if (elapsed < 16)
+ const uint32 elapsed = g_system->getMillis() - frameStart;
+ if (elapsed < 16) {
g_system->delayMillis(16 - elapsed);
+ }
fadeValue += speed;
}
@@ -1321,8 +1347,9 @@ void View1::startFadingWithSpeed(uint16 speed) {
// Original starts at fadeValue = fadeSpeed + 0x40, subtracts fadeSpeed each
// iteration until underflow or zero, then writes the full target palette.
// Each iteration waits for VGA vsync (~14ms at 70Hz).
- if (speed == 0)
+ if (speed == 0) {
speed = 4;
+ }
beginFadeCursorSuppression();
// Set palette to black before blitting new scene pixels
@@ -1345,7 +1372,7 @@ void View1::startFadingWithSpeed(uint16 speed) {
// is fully black (max 6-bit value is 0x3F, so subtracting 0x44 always clamps to 0)
int fadeValue = speed + 0x40;
while (!g_system->getEventManager()->shouldQuit()) {
- uint32 frameStart = g_system->getMillis();
+ const uint32 frameStart = g_system->getMillis();
applyPaletteWithFade(g_engine->_palVanilla, fadeValue);
// Re-copy pixels so the backend redraws with the new palette
@@ -1355,13 +1382,15 @@ void View1::startFadingWithSpeed(uint16 speed) {
Common::Event evt;
while (g_system->getEventManager()->pollEvent(evt)) {
- if (evt.type == Common::EVENT_QUIT)
+ if (evt.type == Common::EVENT_QUIT) {
break;
+ }
}
uint32 elapsed = g_system->getMillis() - frameStart;
- if (elapsed < 16)
+ if (elapsed < 16) {
g_system->delayMillis(16 - elapsed);
+ }
// Check exit: original exits when subtraction underflows or reaches 0
if (fadeValue < (int)speed) {
@@ -1441,7 +1470,7 @@ bool View1::handleInventoryClick(const MouseDownMessage &msg) {
}
_clickedButtonIndex = (uint16)(i + 1);
- InventoryButtonIndex buttonIndex = (InventoryButtonIndex)i;
+ const InventoryButtonIndex buttonIndex = (InventoryButtonIndex)i;
switch (buttonIndex) {
case InventoryButtonIndex::Look: {
g_engine->setCursorMode(Script::MouseMode::Look);
@@ -1557,10 +1586,6 @@ bool View1::handleInventoryClick(const MouseDownMessage &msg) {
return true;
}
if (_activeInventoryItem != nullptr && clickedObject != nullptr) {
- // Use item on item (combine): from handleInventoryClick grid hit-test, mode 0x17.
- // Binary sets interactedObjectId (source) + interactedInventoryItemId (target),
- // g_wPendingPanelRequest=1, then epilogue runScriptExecutor (clears pending after return).
- // Does NOT set g_wInventoryCombineFlag here (that's only in the Drop button path).
g_engine->_scriptExecutor->_interactedObjectID = 0x400 + _activeInventoryItem->_index;
g_engine->_scriptExecutor->_interactedInventoryItemId = 0x400 + clickedObject->_index;
_clickedButtonIndex = 5;
@@ -1589,7 +1614,7 @@ bool View1::handleContainerInventoryClick(const MouseDownMessage &msg) {
}
_clickedButtonIndex = (uint16)(i + 1);
- InventoryButtonIndex buttonIndex = (InventoryButtonIndex)i;
+ const InventoryButtonIndex buttonIndex = (InventoryButtonIndex)i;
switch (buttonIndex) {
case InventoryButtonIndex::Look: {
g_engine->setCursorMode(Script::MouseMode::Look);
@@ -1623,8 +1648,9 @@ bool View1::handleContainerInventoryClick(const MouseDownMessage &msg) {
updateCursor();
g_engine->_scriptExecutor->_inventoryActionFlag = true;
setInventorySource(_inventorySource);
- if (hasPersistentActionBar() && _actionBar)
+ if (hasPersistentActionBar() && _actionBar) {
_actionBar->syncInventory();
+ }
}
break;
}
@@ -1658,14 +1684,15 @@ bool View1::handleContainerInventoryClick(const MouseDownMessage &msg) {
g_engine->_scriptExecutor->_interactedObjectID = 0x400 + clickedObject->_index;
AnimFrame *icon = getInventoryIcon(_activeInventoryItem);
if (icon != nullptr) {
- int cursorSlot = (int)Script::MouseMode::UseInventory - 1;
+ const int cursorSlot = (int)Script::MouseMode::UseInventory - 1;
g_engine->_imageResources[cursorSlot] = *icon;
delete icon;
}
g_engine->setCursorMode(Script::MouseMode::UseInventory);
updateCursor();
- if (hasPersistentActionBar() && _actionBar)
+ if (hasPersistentActionBar() && _actionBar) {
_actionBar->syncInventory();
+ }
return true;
}
@@ -1684,7 +1711,7 @@ bool View1::handleActionBarClick(const MouseDownMessage &msg) {
}
_clickedButtonIndex = (uint16)(i + 1);
- MainMenuButtonIndex buttonIndex = (MainMenuButtonIndex)i;
+ const MainMenuButtonIndex buttonIndex = (MainMenuButtonIndex)i;
switch (buttonIndex) {
case MainMenuButtonIndex::Talk: {
_savedCursorMode = Script::MouseMode::Talk;
@@ -1707,8 +1734,6 @@ bool View1::handleActionBarClick(const MouseDownMessage &msg) {
break;
}
case MainMenuButtonIndex::Inventory: {
- // Binary: handleActionBarClick button 5 sets g_wPendingPanelRequest = 1.
- // Panel closes on release; gameTick opens inventory when state returns to 0.
_pendingPanelRequest = kPanelRequestInventory;
break;
}
@@ -1721,8 +1746,6 @@ bool View1::handleActionBarClick(const MouseDownMessage &msg) {
break;
}
case MainMenuButtonIndex::Map: {
- // Binary handleActionBarClick (1008:42dc) button 7: sets scene+0x61db=1
- // and saved cursor Walk; map load happens after action bar closes on release.
if (!_helpButtonDisabled) {
_pendingMapOpen = true;
_savedCursorMode = Script::MouseMode::Walk;
@@ -1750,7 +1773,7 @@ bool View1::handleActionBarClick(const MouseDownMessage &msg) {
bool View1::handleHelpClick(const MouseDownMessage &msg) {
Common::Rect screenRect(g_engine->screenWidth(), g_engine->gameHeight());
if (screenRect.contains(msg._pos)) {
- uint8 depth = g_engine->_depthMap.getPixel(msg._pos.x, msg._pos.y);
+ const uint8 depth = g_engine->_depthMap.getPixel(msg._pos.x, msg._pos.y);
if (depth > 0 && depth < 0xFA) {
// Binary: fileSeek(scene + 0x5DD7 + depth*4) = _mapSceneOffsets[depth-1]
uint32 subSceneOffset = g_engine->_mapSceneOffsets[depth - 1];
@@ -1809,8 +1832,9 @@ void View1::walkToScreenPosition(const Common::Point &pos) {
protagonist->_targetPosition = target;
} else {
const bool found = protagonist->calculatePath(target);
- if (!found)
+ if (!found) {
protagonist->_targetPosition = target;
+ }
}
protagonist->_stepDeltaX = abs(protagonist->_targetPosition.x - charPos.x);
protagonist->_stepDeltaY = abs(protagonist->_targetPosition.y - charPos.y);
@@ -1820,6 +1844,7 @@ void View1::walkToScreenPosition(const Common::Point &pos) {
}
bool View1::handleInput(const MouseDownMessage &msg) {
+ Script::ScriptExecutor *script = g_engine->_scriptExecutor;
if (msg._button == MouseMessage::MB_LEFT) {
// Help mode (depth-based scene preview) from handleInput (1008:e8bf).
// When currentMode == VM_HELP, clicking on the depth map previews scenes.
@@ -1828,8 +1853,8 @@ bool View1::handleInput(const MouseDownMessage &msg) {
}
if (shouldShowActionBar() && _actionBar && _actionBar->isPointInUI(msg._pos)) {
- if (g_engine->_scriptExecutor->_cursorMode != Script::MouseMode::Disabled) {
- _actionBar->handleClick(msg._pos, g_engine->_scriptExecutor->isExecuting());
+ if (script->_cursorMode != Script::MouseMode::Disabled) {
+ _actionBar->handleClick(msg._pos, script->isExecuting());
presentFrame();
}
return true;
@@ -1845,11 +1870,11 @@ bool View1::handleInput(const MouseDownMessage &msg) {
// text-box-dismiss gate before the interaction check. The text box (if any)
// is cleared as a side-effect of the script rerunning. Clear it here so the
// UI updates immediately, but do NOT consume the click.
- if (_isShowingTextBox && !g_engine->_scriptExecutor->isExecuting()) {
+ if (_isShowingTextBox && !script->isExecuting()) {
handleTextBoxInput();
}
- if (_uiPanelState == kUiPanelInventory && !g_engine->_scriptExecutor->isExecuting()) {
+ if (_uiPanelState == kUiPanelInventory && !script->isExecuting()) {
return handleInventoryClick(msg);
}
@@ -1857,7 +1882,7 @@ bool View1::handleInput(const MouseDownMessage &msg) {
return handleContainerInventoryClick(msg);
}
- if (_uiPanelState == kUiPanelActionBar && !g_engine->_scriptExecutor->isExecuting()) {
+ if (_uiPanelState == kUiPanelActionBar && !script->isExecuting()) {
return handleActionBarClick(msg);
}
@@ -1865,8 +1890,7 @@ bool View1::handleInput(const MouseDownMessage &msg) {
// From handleInput (1008:f1d4): clicks during script execution are ONLY processed
// if cursor is not Disabled (0x1A). When cursor is Disabled (walk/wait in progress),
// clicks are completely ignored.
- if (g_engine->_scriptExecutor->isScriptMidExecution() &&
- g_engine->_scriptExecutor->_cursorMode != Script::MouseMode::Disabled) {
+ if (script->isScriptMidExecution() && script->_cursorMode != Script::MouseMode::Disabled) {
// Binary handleInput (1008:f1d4-f225): exact sequence of unconditional checks
// 1. if g_wIsShowingTextBox != 0: handleTextBoxInput()
// 2. if g_wIsShowingDialoguePanel != 0: dismissDialoguePanel()
@@ -1893,26 +1917,23 @@ bool View1::handleInput(const MouseDownMessage &msg) {
}
}
if (!_isDialogueChoiceInputActive) {
- g_engine->_scriptExecutor->_scriptClickFlag = 0;
- g_engine->_scriptExecutor->_scriptClickX = (uint16)msg._pos.x;
- g_engine->_scriptExecutor->_scriptClickY = (uint16)msg._pos.y;
- g_engine->_scriptExecutor->_scriptClickResult = 1;
+ script->_scriptClickFlag = 0;
+ script->_scriptClickX = (uint16)msg._pos.x;
+ script->_scriptClickY = (uint16)msg._pos.y;
+ script->_scriptClickResult = 1;
g_engine->runScriptExecutor();
}
return true;
}
- // Binary handleInput (1008:e8bf): when g_wScriptIsExecuting != 0 and cursor
- // is Disabled (0x1A), ALL input is ignored. Only the section above (for
- // text box/dialogue clicks with non-disabled cursor) processes clicks.
- if (g_engine->_scriptExecutor->isExecuting()) {
+ if (script->isExecuting()) {
return true;
}
if (shouldShowActionBar() && msg._pos.y >= actionBarTopY())
return true;
- const Script::MouseMode mode = g_engine->_scriptExecutor->_cursorMode;
+ const Script::MouseMode mode = script->_cursorMode;
// Walk never hit-tests; other verbs interact when a target is under the cursor.
// Empty-ground clicks walk so the persistent verb bar does not trap the player
@@ -1926,7 +1947,7 @@ bool View1::handleInput(const MouseDownMessage &msg) {
Character *protagonist = getCharacterByIndex(Scenes::instance()._currentActorIndex);
if (protagonist != nullptr) {
- Common::Point pos = protagonist->getPosition();
+ const Common::Point pos = protagonist->getPosition();
protagonist->_targetPosition = pos;
protagonist->_pathFinalDestination = pos;
protagonist->_path.clear();
@@ -1934,13 +1955,13 @@ bool View1::handleInput(const MouseDownMessage &msg) {
}
if (mode != Script::MouseMode::UseInventory) {
- g_engine->_scriptExecutor->_interactedInventoryItemId = 0;
+ script->_interactedInventoryItemId = 0;
_activeInventoryItem = nullptr;
}
- g_engine->_scriptExecutor->_interactedObjectID = index;
+ script->_interactedObjectID = index;
g_engine->runScriptExecutor(false);
- g_engine->_scriptExecutor->_interactedObjectID = 0;
+ script->_interactedObjectID = 0;
return true;
}
}
@@ -1952,34 +1973,27 @@ bool View1::handleInput(const MouseDownMessage &msg) {
}
return true;
} else if (msg._button == MouseMessage::MB_RIGHT) {
- // Map mode: right-click does nothing (binary: only left-click processed in map mode)
if (_currentMode == ViewMode::VM_HELP) {
return true;
}
// Handle no other interactions during a script
- if (g_engine->_scriptExecutor->isExecuting()) {
- // From handleInput: right-click during script execution opens the
- // map/save panel ONLY if none of these are active:
- // Binary: g_wIsShowingDialoguePanel, g_wIsSceneInitRun, scene+0x53B9,
- // g_wIsShowingTextBox, overlay, sound, music, adlib
+ if (script->isExecuting()) {
if (!_isShowingDialoguePanel && !_isDialogueChoiceInputActive &&
!_isShowingTextBox &&
- !g_engine->_scriptExecutor->_overlayTextStageActive &&
- !g_engine->_scriptExecutor->_waitForPcmSound &&
- !g_engine->_scriptExecutor->_waitForMusicControl &&
- !g_engine->_scriptExecutor->_waitForAdlibReady &&
- !g_engine->_scriptExecutor->_waitForObjectAnimStep &&
- !g_engine->_scriptExecutor->_waitForSpecialAnimStep &&
- !g_engine->_scriptExecutor->_waitForDeltaAnim &&
- !g_engine->_scriptExecutor->_waitForDeltaSpeed &&
- g_engine->_scriptExecutor->canOpenSaveMenu()) {
+ !script->_overlayTextStageActive &&
+ !script->_waitForPcmSound &&
+ !script->_waitForMusicControl &&
+ !script->_waitForAdlibReady &&
+ !script->_waitForObjectAnimStep &&
+ !script->_waitForSpecialAnimStep &&
+ !script->_waitForDeltaAnim &&
+ !script->_waitForDeltaSpeed &&
+ script->canOpenSaveMenu()) {
if (ConfMan.getBool("original_menus")) {
- // Binary handleInput (1008:f2af): saves cursor mode before opening panel
- _savedCursorMode = g_engine->_scriptExecutor->_cursorMode;
+ _savedCursorMode = script->_cursorMode;
openOriginalSaveLoadPanel();
} else {
- // Binary save/load path saves cursor then sets PanelCursor (0x19).
- _savedCursorMode = g_engine->_scriptExecutor->_cursorMode;
+ _savedCursorMode = script->_cursorMode;
g_engine->setCursorMode(Script::MouseMode::PanelCursor);
g_engine->openMainMenuDialog();
updateCursor();
@@ -1988,9 +2002,7 @@ bool View1::handleInput(const MouseDownMessage &msg) {
return true;
}
- // From handleInput (1008:e8bf): right-click when not executing and cursor != Disabled
- // opens the action bar at the mouse position (or cycles verbs with SCUMM UI).
- if (g_engine->_scriptExecutor->_cursorMode == Script::MouseMode::Disabled) {
+ if (script->_cursorMode == Script::MouseMode::Disabled) {
return true;
}
if (hasPersistentActionBar()) {
@@ -1998,7 +2010,7 @@ bool View1::handleInput(const MouseDownMessage &msg) {
if (canCycleVerbs) {
g_engine->nextCursorMode();
_activeInventoryItem = nullptr;
- g_engine->_scriptExecutor->_interactedInventoryItemId = 0;
+ script->_interactedInventoryItemId = 0;
if (_actionBar && shouldShowActionBar())
_actionBar->syncActiveVerbFromCursorMode();
updateCursor();
@@ -2020,6 +2032,7 @@ bool View1::handleInput(const MouseDownMessage &msg) {
}
return false;
}
+
bool View1::msgMouseDown(const MouseDownMessage &msg) {
return handleInput(msg);
}
@@ -2032,7 +2045,6 @@ void View1::finishPanelCloseAfterRelease(UiPanelState closedFromState) {
_uiBackgroundRestorePending = false;
redraw();
- // Binary handleInput (1008:e8bf): runScriptExecutor after close unless state was 1 or 4.
if (closedFromState != kUiPanelActionBar && closedFromState != kUiPanelSaveLoad) {
g_engine->runScriptExecutor();
}
@@ -2047,11 +2059,7 @@ bool View1::handlePanelRelease(const MouseUpMessage &msg) {
return false;
}
- // Binary handleInput (1008:e8bf): action bar/inventory panel release is only handled
- // when g_wScriptIsExecuting==0 and g_wCursorMode!=0x1A. Save/load (state 4) still
- // closes during script execution.
- if (g_engine->_scriptExecutor->isExecuting() &&
- _uiPanelState != kUiPanelSaveLoad) {
+ if (g_engine->_scriptExecutor->isExecuting() && _uiPanelState != kUiPanelSaveLoad) {
return true;
}
@@ -2074,7 +2082,6 @@ bool View1::handlePanelRelease(const MouseUpMessage &msg) {
}
if (!shouldClose) {
- // Binary handleInput (1008:e8bf): always clears g_wClickedButtonIndex on release.
_clickedButtonIndex = 0;
redraw();
return true;
@@ -2150,7 +2157,7 @@ bool View1::msgMouseMove(const MouseMoveMessage &msg) {
_actionBar->clearSentenceObject();
GameObject *hovered = getClickedInventoryItem(msg._pos);
if (hovered != nullptr) {
- const Common::String name = getObjectHotspotName(hovered->_index);
+ const Common::String &name = getObjectHotspotName(hovered->_index);
if (!name.empty())
_actionBar->updateSentenceLine(name);
}
@@ -2159,7 +2166,7 @@ bool View1::msgMouseMove(const MouseMoveMessage &msg) {
uint16 index = getHitObjectID(msg._pos);
if (index == 0)
index = g_engine->getHotspotAtPoint(msg._pos);
- const Common::String name = lookupInteractionDisplayName(index);
+ const Common::String &name = lookupInteractionDisplayName(index);
if (!name.empty())
_actionBar->updateSentenceLine(name);
}
@@ -2238,8 +2245,9 @@ bool View1::msgKeypress(const KeypressMessage &msg) {
if (!g_engine->_scriptExecutor->isExecuting() && g_engine->_scriptExecutor->_cursorMode != Script::MouseMode::Disabled) {
if (msg.ascii == (uint16)'i') {
if (hasPersistentActionBar()) {
- if (_uiPanelState == kUiPanelContainerInventory)
+ if (_uiPanelState == kUiPanelContainerInventory) {
closeInventory();
+ }
} else if (_uiPanelState != kUiPanelInventory) {
openInventory(GameObjects::instance().getProtagonistObject());
} else {
@@ -2251,8 +2259,9 @@ bool View1::msgKeypress(const KeypressMessage &msg) {
g_engine->nextCursorMode();
_activeInventoryItem = nullptr;
g_engine->_scriptExecutor->_interactedInventoryItemId = 0;
- if (_actionBar)
+ if (_actionBar) {
_actionBar->syncActiveVerbFromCursorMode();
+ }
updateCursor();
presentFrame();
}
@@ -2266,7 +2275,7 @@ bool View1::msgKeypress(const KeypressMessage &msg) {
if (msg.ascii >= '1' && msg.ascii <= '9') {
// Select a visible dialogue option by number key.
// Register a dialogue choice and act upon it
- uint8 numberPressed = msg.ascii - '1' + 1;
+ const uint8 numberPressed = msg.ascii - '1' + 1;
if (numberPressed <= _dialogueChoiceCount && _isDialogueChoiceInputActive) {
handleTextBoxInput();
dismissDialoguePanel();
@@ -2316,11 +2325,11 @@ void View1::draw() {
if (_isShowingTextBox || _isShowingDialoguePanel) {
showStringBox(_drawnStringBox);
if (_isDialogueChoiceInputActive && g_engine->enhancementEnabled(kEnhUIUX)) {
- int lineHeight = g_engine->dialogLineHeight();
- int firstLineY = _stringBoxPosition.y + g_engine->dialogTextInset();
- int relY = mousePos.y - firstLineY;
+ const int lineHeight = g_engine->dialogLineHeight();
+ const int firstLineY = _stringBoxPosition.y + g_engine->dialogTextInset();
+ const int relY = mousePos.y - firstLineY;
if (relY >= 0) {
- int hoveredLine = relY / lineHeight;
+ const int hoveredLine = relY / lineHeight;
int cumulativeLines = 0;
for (uint i = 0; i < _dialogueChoiceLineCounts.size(); i++) {
if (hoveredLine < cumulativeLines + _dialogueChoiceLineCounts[i]) {
Commit: 183e229f712aabd4932fe7007b3e850accdbf59d
https://github.com/scummvm/scummvm/commit/183e229f712aabd4932fe7007b3e850accdbf59d
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: const + formatting
Changed paths:
engines/macs2/gameobjects.cpp
engines/macs2/macs2.cpp
engines/macs2/metaengine.cpp
engines/macs2/music.cpp
diff --git a/engines/macs2/gameobjects.cpp b/engines/macs2/gameobjects.cpp
index 107c009f7b1..4556d6e0160 100644
--- a/engines/macs2/gameobjects.cpp
+++ b/engines/macs2/gameobjects.cpp
@@ -458,12 +458,13 @@ bool Macs2::GameObject::isAnimSlotLoaded(uint16 orient) const {
return blob != nullptr && !blob->empty();
}
const uint16 maxOrient = g_engine->maxOrientations();
- if (orient < 1 || orient > maxOrient)
+ if (orient < 1 || orient > maxOrient) {
return false;
+ }
const uint slot = orient - 1;
- if (slot < _blobs.size() && !_blobs[slot].empty())
+ if (slot < _blobs.size() && !_blobs[slot].empty()) {
return true;
- // Binary drawAllCharacters (1008:90a2): bSlotLoaded at slot+0x33; file speeds often 0x010x.
+ }
if (slot < _blobWalkSpeeds.size() && (_blobWalkSpeeds[slot] & 0xFF00) != 0)
return true;
return false;
@@ -482,37 +483,28 @@ Macs2::AnimationReader::~AnimationReader() {
}
uint16 Macs2::AnimationReader::readNumAnimations() {
- // Read the header
-
_readStream->seek(0, SEEK_SET);
- // bp-22h
+ // Read the header
_readStream->readUint16();
- // bp-6h
_readStream->readUint16();
- // bp-8h
_readStream->readUint16();
- // bp-0Ah
_readStream->readUint16();
- // bp-10h
_readStream->readUint16();
- // Offset 0xA: number of command bytes in the control section (bp-0Eh in advanceAnimFrame)
- uint16 commandSectionLength = _readStream->readUint16() + 1;
+ // Offset 0xA: number of command bytes in the control section
+ const uint16 commandSectionLength = _readStream->readUint16() + 1;
- // Frame count (bp-24h) is stored right after the header + command section
+ // Frame count is stored right after the header + command section
_readStream->seek(0x0B + commandSectionLength);
// bp-24h
- uint16 result = _readStream->readUint16();
+ const uint16 result = _readStream->readUint16();
return result;
}
void Macs2::AnimationReader::seekToAnimation(uint16 index) {
- // Read bp-0Eh directly
_readStream->seek(0xA, SEEK_SET);
- // Offset 0xA: command section length (bp-0Eh in advanceAnimFrame)
- uint16 commandSectionLength = _readStream->readUint16() + 1;
- // Skip reading bp-24h
+ const uint16 commandSectionLength = _readStream->readUint16() + 1;
_readStream->seek(0x0B + commandSectionLength + 0x2, SEEK_SET);
for (int i = 0; i < index; i++) {
skipCurrentAnimationFrame();
@@ -520,10 +512,10 @@ void Macs2::AnimationReader::seekToAnimation(uint16 index) {
}
void Macs2::AnimationReader::skipCurrentAnimationFrame() {
- _readStream->readUint16(); // value1
- _readStream->readUint16(); // value2
+ _readStream->readUint16();
+ _readStream->readUint16();
_readStream->seek(2, SEEK_CUR);
- uint16 width = _readStream->readUint16();
- uint16 height = _readStream->readUint16();
+ const uint16 width = _readStream->readUint16();
+ const uint16 height = _readStream->readUint16();
_readStream->seek(width * height, SEEK_CUR);
}
diff --git a/engines/macs2/macs2.cpp b/engines/macs2/macs2.cpp
index 6c0b25ab8a9..aec7da085fa 100644
--- a/engines/macs2/macs2.cpp
+++ b/engines/macs2/macs2.cpp
@@ -67,13 +67,13 @@ Common::U32String hotspotLabelToU32(const Common::String &name) {
bool isMapModeActive() {
if (g_events == nullptr)
return false;
- View1 *view = (View1 *)g_events->findView("View1");
+ const View1 *view = (View1 *)g_events->findView("View1");
return view != nullptr && view->_currentMode == ViewMode::VM_HELP;
}
Common::Point getSceneObjectHotspotPosition(View1 *view, GameObject *obj) {
if (view != nullptr) {
- Character *character = view->getCharacterByIndex(obj->_index);
+ const Character *character = view->getCharacterByIndex(obj->_index);
if (character != nullptr && !character->_markedForDeletion)
return character->getPosition();
}
@@ -83,9 +83,10 @@ Common::Point getSceneObjectHotspotPosition(View1 *view, GameObject *obj) {
} // namespace
void resetCharacterWalkPath(Character *character) {
- if (character == nullptr || character->_gameObject == nullptr)
+ if (character == nullptr || character->_gameObject == nullptr) {
return;
- const Common::Point pos = character->_gameObject->_position;
+ }
+ const Common::Point &pos = character->_gameObject->_position;
character->_path.clear();
character->_currentPathIndex = 0;
character->_targetPosition = pos;
@@ -144,8 +145,9 @@ Graphics::ManagedSurface Macs2Engine::readRLEImage(int64 offs, Common::SeekableR
}
Macs2Engine::McsFileVersion Macs2Engine::detectMcsFileVersion(Common::SeekableReadStream &stream) const {
- if (stream.size() < (int64)kMcsMagicSize)
+ if (stream.size() < (int64)kMcsMagicSize) {
return McsFileVersion::Unknown;
+ }
const int64 pos = stream.pos();
byte magic[kMcsMagicSize];
@@ -156,10 +158,12 @@ Macs2Engine::McsFileVersion Macs2Engine::detectMcsFileVersion(Common::SeekableRe
}
stream.seek(pos, SEEK_SET);
- if (memcmp(magic, kMcsMagicV1, kMcsMagicSize) == 0)
+ if (memcmp(magic, kMcsMagicV1, kMcsMagicSize) == 0) {
return McsFileVersion::V1;
- if (memcmp(magic, kMcsMagicV2, kMcsMagicSize) == 0)
+ }
+ if (memcmp(magic, kMcsMagicV2, kMcsMagicSize) == 0) {
return McsFileVersion::V2;
+ }
return McsFileVersion::Unknown;
}
diff --git a/engines/macs2/metaengine.cpp b/engines/macs2/metaengine.cpp
index b0655bcd3aa..3e848399e14 100644
--- a/engines/macs2/metaengine.cpp
+++ b/engines/macs2/metaengine.cpp
@@ -136,27 +136,28 @@ SaveStateList Macs2MetaEngine::listSaves(const char *target) const {
if (f) {
// Validate magic
char magic[12];
- f->read(magic, 12);
- if (memcmp(magic, "AHFFMSGM0100", 12) == 0) {
+ f->read(magic, sizeof(magic));
+ if (memcmp(magic, "AHFFMSGM0100", sizeof(magic)) == 0) {
// Read slot name (Pascal string: 1 byte length + up to 20 chars)
byte nameLen = f->readByte();
- if (nameLen > 20)
+ if (nameLen > 20) {
nameLen = 20;
+ }
char name[21];
f->read(name, nameLen);
name[nameLen] = '\0';
// Use slots 100+ for original saves to avoid conflicts
- int scummSlot = 100 + slot;
+ const int scummSlot = 100 + slot;
// Check if this slot is already in the list
bool found = false;
- for (const auto &s : saves) {
+ for (const SaveStateDescriptor &s : saves) {
if (s.getSaveSlot() == scummSlot) {
found = true;
break;
}
}
if (!found) {
- Common::String desc = Common::String::format("[DOS] %s", name);
+ const Common::String &desc = Common::String::format("[DOS] %s", name);
saves.push_back(SaveStateDescriptor(this, scummSlot, desc));
}
}
diff --git a/engines/macs2/music.cpp b/engines/macs2/music.cpp
index f92ec2a8875..3d9a54b224f 100644
--- a/engines/macs2/music.cpp
+++ b/engines/macs2/music.cpp
@@ -70,9 +70,6 @@ void Music::deinit() {
void Music::onTimer() {
if (_parser) {
- // Binary adlibISRHandler (1000:1a9f): g_bAdlibPlaybackReady is set when the
- // song stream loops back to the start (0xF0/0x2F meta or timer expiry), not on
- // the first timer tick after playMusicSlot clears the flag.
const uint32 tickBefore = _parser->getTick();
_parser->onTimer();
if (_playing && !_adlibPlaybackReady && _parser->getTick() < tickBefore)
@@ -232,10 +229,10 @@ void Music::setVolume(uint16 volume) {
// --- MidiDriver_BASE interface ---
void Music::send(uint32 b) {
- byte cmd = b & 0xF0;
- byte channel = b & 0x0F;
- byte param1 = (b >> 8) & 0xFF;
- byte param2 = (b >> 16) & 0xFF;
+ const byte cmd = b & 0xF0;
+ const byte channel = b & 0x0F;
+ const byte param1 = (b >> 8) & 0xFF;
+ const byte param2 = (b >> 16) & 0xFF;
switch (cmd) {
case 0x90:
@@ -267,8 +264,6 @@ void Music::metaEvent(byte type, const byte *data, uint16 length) {
}
}
-// --- Music playback logic (matching original macs2 behavior) ---
-
void Music::noteOn(byte channel, byte note, byte velocity) {
if (_numOplChannels == 9 || channel < 0x0B) {
// Melodic note-on
@@ -310,8 +305,8 @@ void Music::noteOn(byte channel, byte note, byte velocity) {
_voiceNote[voice] = note;
// Volume calculation matching original
- uint8 velAtten = (uint8)((0x3F - ((velocity & 0x7F) >> 1)) >> 1) >> 1;
- uint16 instBase = (uint16)_channelPrograms[channel] << 4;
+ const uint8 velAtten = (uint8)((0x3F - ((velocity & 0x7F) >> 1)) >> 1) >> 1;
+ const uint16 instBase = (uint16)_channelPrograms[channel] << 4;
uint8 op2Base = 0;
uint8 op1Base = 0;
@@ -330,22 +325,22 @@ void Music::noteOn(byte channel, byte note, byte velocity) {
// Key off, set volumes, then key on
writeReg(voice + 0xB0, 0);
- byte reg2 = readReg(_opMap2[voice] + 0x40);
+ const byte reg2 = readReg(_opMap2[voice] + 0x40);
writeReg(_opMap2[voice] + 0x40, (reg2 & 0xC0) + vol1);
- byte reg1 = readReg(_opMap1[voice] + 0x40);
+ const byte reg1 = readReg(_opMap1[voice] + 0x40);
writeReg(_opMap1[voice] + 0x40, (reg1 & 0xC0) + vol2);
_channelPitchBend[channel] = 0;
setFrequency(voice, note, 0);
} else {
// Percussion note-on
- uint16 instBase = (uint16)_channelPrograms[channel] << 4;
- uint8 percIdx = channel - 0x0B;
+ const uint16 instBase = (uint16)_channelPrograms[channel] << 4;
+ const uint8 percIdx = channel - 0x0B;
if (percIdx >= _percOpMap.size())
return;
- uint8 opIdx = _percOpMap[percIdx];
+ const uint8 opIdx = _percOpMap[percIdx];
if (channel == 0x0B) {
// Bass drum: load full instrument
@@ -362,21 +357,21 @@ void Music::noteOn(byte channel, byte note, byte velocity) {
// Percussion volume
uint8 vol = _masterVolume;
if ((uint32)(_instrumentDataOffset + instBase + 3) < _songData.size()) {
- byte volByte = _songData[_instrumentDataOffset + instBase + 3];
- uint8 volIdx = ((volByte & 0x3F) >> 4) * 8 + (velocity >> 4);
+ const byte volByte = _songData[_instrumentDataOffset + instBase + 3];
+ const uint8 volIdx = ((volByte & 0x3F) >> 4) * 8 + (velocity >> 4);
if (volIdx < _percVolTable.size())
vol = _percVolTable[volIdx] + _masterVolume;
}
if (vol > 0x3F)
vol = 0x3F;
- uint8 freqChan = _percFreqChannel[percIdx];
+ const uint8 freqChan = _percFreqChannel[percIdx];
writeReg(freqChan + 0xB0, 0);
- byte regVal = readReg(opIdx + 0x40);
+ const byte regVal = readReg(opIdx + 0x40);
writeReg(opIdx + 0x40, vol + (regVal & 0xC0));
setFrequency(freqChan, note, 0);
- byte bdVal = readReg(0xBD);
+ const byte bdVal = readReg(0xBD);
writeReg(0xBD, bdVal | (1 << (0xF - channel)));
}
}
@@ -392,7 +387,7 @@ void Music::noteOff(byte channel, byte note) {
for (uint8 v = 0; v < _numOplChannels; v++) {
if (_voiceAge[v] == 0 && _voiceMidiChannel[v] == channel && _voiceNote[v] == note) {
// Write frequency without key-on
- uint16 freq = ((uint16)_freqTableHi[note] << 8) | _freqTableLo[note];
+ const uint16 freq = ((uint16)_freqTableHi[note] << 8) | _freqTableLo[note];
writeReg(v + 0xA0, freq & 0xFF);
writeReg(v + 0xB0, (freq >> 8) & 0xDF); // clear key-on bit
_voiceAge[v] = 1;
@@ -401,7 +396,7 @@ void Music::noteOff(byte channel, byte note) {
}
} else {
// Percussion note-off
- byte bdVal = readReg(0xBD);
+ const byte bdVal = readReg(0xBD);
writeReg(0xBD, bdVal & ~(1 << (0xF - channel)));
}
}
@@ -444,13 +439,13 @@ void Music::controlChange(byte channel, byte control, byte value) {
}
void Music::loadInstrument(uint8 voice, uint8 program) {
- uint16 instBase = (uint16)program << 4;
+ const uint16 instBase = (uint16)program << 4;
if ((uint32)_instrumentDataOffset + instBase + 11 > _songData.size())
return;
const byte *inst = _songData.data() + _instrumentDataOffset + instBase;
- uint8 op1 = _opMap1[voice];
- uint8 op2 = _opMap2[voice];
+ const uint8 op1 = _opMap1[voice];
+ const uint8 op2 = _opMap2[voice];
writeReg(op1 + 0x20, inst[0]);
writeReg(op2 + 0x20, inst[1]);
@@ -473,12 +468,12 @@ void Music::setFrequency(uint8 voice, uint8 note, uint8 pitchBend) {
if (pitchBend != 0) {
if (pitchBend < 0x80) {
- uint8 nextNote = (note < 0x7F) ? note + 1 : 0x7F;
- uint16 nextFreq = ((uint16)_freqTableHi[nextNote] << 8) | _freqTableLo[nextNote];
+ const uint8 nextNote = (note < 0x7F) ? note + 1 : 0x7F;
+ const uint16 nextFreq = ((uint16)_freqTableHi[nextNote] << 8) | _freqTableLo[nextNote];
freq += (uint16)((uint64)pitchBend * (nextFreq - freq) >> 7);
} else {
- uint8 prevNote = (note > 0) ? note - 1 : 0;
- uint16 prevFreq = ((uint16)_freqTableHi[prevNote] << 8) | _freqTableLo[prevNote];
+ const uint8 prevNote = (note > 0) ? note - 1 : 0;
+ const uint16 prevFreq = ((uint16)_freqTableHi[prevNote] << 8) | _freqTableLo[prevNote];
freq -= (uint16)((uint64)pitchBend * (freq - prevFreq) >> 7);
}
}
Commit: d5ba0756b45cdfc079041f84069f54666607a258
https://github.com/scummvm/scummvm/commit/d5ba0756b45cdfc079041f84069f54666607a258
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: extract to local var
Changed paths:
engines/macs2/macs2.cpp
engines/macs2/view1.cpp
diff --git a/engines/macs2/macs2.cpp b/engines/macs2/macs2.cpp
index aec7da085fa..10330d49401 100644
--- a/engines/macs2/macs2.cpp
+++ b/engines/macs2/macs2.cpp
@@ -2599,9 +2599,8 @@ void Macs2Engine::setCursorMode(Script::MouseMode newMode) {
}
uint16 Macs2Engine::getHotspotAtPoint(const Common::Point &p) const {
- uint16 result = 0;
if (p.x < 0 || p.x >= screenWidth() || p.y < 0 || p.y >= gameHeight() || _hotspotMap.w == 0) {
- return result;
+ return 0;
}
uint8 firstLookup = _hotspotMap.getPixel(p.x, p.y);
@@ -2609,7 +2608,7 @@ uint16 Macs2Engine::getHotspotAtPoint(const Common::Point &p) const {
uint8 i = 1;
if (i > numHotspots) {
- return result;
+ return 0;
}
Common::Array<uint16> a = _hotspotColorTable;
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 11a84db0596..fcbcc373833 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -590,9 +590,10 @@ void View1::updateCursor(const Graphics::Palette *palette) {
return;
}
- const uint16 width = g_engine->_imageResources[mode]._width;
- const uint16 height = g_engine->_imageResources[mode]._height;
- const byte *cursorData = g_engine->_imageResources[mode]._data.data();
+ const AnimFrame &cursorSprite = g_engine->_imageResources[mode];
+ const uint16 width = cursorSprite._width;
+ const uint16 height = cursorSprite._height;
+ const byte *cursorData = cursorSprite._data.data();
const Graphics::PixelFormat rgbaCursorFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
Common::Array<uint32> rgbaCursor;
rgbaCursor.resize(width * height);
Commit: 794eb6fd91d25538821eed37a588b58752d382b4
https://github.com/scummvm/scummvm/commit/794eb6fd91d25538821eed37a588b58752d382b4
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: renamed method and order members to reduce size
Changed paths:
engines/macs2/view1.cpp
engines/macs2/view1.h
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index fcbcc373833..867a2631ac3 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -1815,14 +1815,10 @@ void View1::walkToScreenPosition(const Common::Point &pos) {
return;
}
- Common::Point target = pos;
- Common::Point charPos = protagonist->getPosition();
+ const Common::Point &charPos = protagonist->getPosition();
- int16 targetY = target.y;
- int16 targetX = target.x;
- g_engine->snapToWalkablePosition(&targetY, &targetX, charPos.y, charPos.x);
- target.x = targetX;
- target.y = targetY;
+ Common::Point target = pos;
+ g_engine->snapToWalkablePosition(&target.y, &target.x, charPos.y, charPos.x);
protagonist->_pathFinalDestination = target;
protagonist->_currentPathIndex = 0;
@@ -3182,7 +3178,7 @@ void View1::drawSprite(int16 x, int16 y, const Sprite &sprite, Graphics::Managed
drawSprite(x, y, sprite._width, sprite._height, const_cast<byte *>(sprite._data.data()), s, mirrored, useDepth, depth, clipToGameArea);
}
-void View1::drawSpriteClipped(uint16 x, uint16 y, Common::Rect &clippingRect, uint16 width, uint16 height, const byte *const data, Graphics::ManagedSurface &s) {
+void View1::drawSpriteClipped(uint16 x, uint16 y, const Common::Rect &clippingRect, uint16 width, uint16 height, const byte *const data, Graphics::ManagedSurface &s) {
for (int currentX = 0; currentX < width; currentX++) {
for (int currentY = 0; currentY < height; currentY++) {
uint8 val = data[currentY * width + currentX];
@@ -3196,7 +3192,7 @@ void View1::drawSpriteClipped(uint16 x, uint16 y, Common::Rect &clippingRect, ui
}
}
-void View1::drawSpriteClipped(uint16 x, uint16 y, Common::Rect &clippingRect, const Sprite &sprite, Graphics::ManagedSurface &s) {
+void View1::drawSpriteClipped(uint16 x, uint16 y, const Common::Rect &clippingRect, const Sprite &sprite, Graphics::ManagedSurface &s) {
drawSpriteClipped(x, y, clippingRect, sprite._width, sprite._height, sprite._data.data(), s);
}
@@ -3485,17 +3481,15 @@ void View1::drawBorder(const Common::Point &pos, const Common::Point &size, Grap
drawVerticalBorderHighlight(pos + Common::Point(size.x - border, border), size.y - 0xB, 0x1012, s);
}
-// drawBorderSide (1008:39b5)
void View1::drawBorderSide(const Common::Point &pos, const Common::Point &size, Graphics::ManagedSurface &s) {
- // Clipping region: (x+1, y+1) to (x+width, y+height) per disassembly
- Common::Rect clippingRect(pos + Common::Point(1, 1), pos + size);
- // Texture: border sprite from cursor image array at offset 0x1f0 (mode 1)
- uint16 currentX = clippingRect.left;
- uint16 currentY = clippingRect.top;
const AnimFrame &sprite = g_engine->_imageResources[31];
- if (sprite._width == 0 || sprite._height == 0 || sprite._data.empty())
+ if (sprite._width == 0 || sprite._height == 0 || sprite._data.empty()) {
return;
+ }
+ const Common::Rect clippingRect(pos + Common::Point(1, 1), pos + size);
+ uint16 currentX = clippingRect.left;
+ uint16 currentY = clippingRect.top;
while (currentY < clippingRect.bottom) {
while (currentX < clippingRect.right) {
drawSpriteClipped(currentX, currentY, clippingRect, sprite._width, sprite._height, sprite._data.data(), s);
@@ -3520,16 +3514,14 @@ Macs2::AnimFrame *View1::getUISprite(uint32 offset) {
}
void View1::drawHorizontalBorderHighlight(const Common::Point &pos, int16 width, uint32 spriteAddress, Graphics::ManagedSurface &s) {
- // drawHorizontalBorderHighlight (1008:3737)
- // Sets clipping region to 1px tall horizontal strip, tiles the highlight/shadow sprite.
- Common::Rect clippingRect(pos, pos + Common::Point(width, 1));
- uint16 currentX = clippingRect.left;
- uint16 currentY = clippingRect.top;
-
const AnimFrame *sprite = getUISprite(spriteAddress);
if (sprite == nullptr) {
return;
}
+ const Common::Rect clippingRect(pos, pos + Common::Point(width, 1));
+ const uint16 currentY = clippingRect.top;
+
+ uint16 currentX = clippingRect.left;
while (currentX < clippingRect.right) {
drawSpriteClipped(currentX, currentY, clippingRect, sprite->_width, sprite->_height, sprite->_data.data(), s);
currentX += sprite->_width;
@@ -3537,17 +3529,14 @@ void View1::drawHorizontalBorderHighlight(const Common::Point &pos, int16 width,
}
void View1::drawVerticalBorderHighlight(const Common::Point &pos, int16 height, uint32 spriteAddress, Graphics::ManagedSurface &s) {
- // drawVerticalBorderHighlight (1008:3876)
- // Sets clipping region to 1px wide vertical strip, tiles the highlight/shadow sprite.
- Common::Rect clippingRect(pos, pos + Common::Point(1, height));
- uint16 currentX = clippingRect.left;
- uint16 currentY = clippingRect.top;
-
const AnimFrame *sprite = getUISprite(spriteAddress);
if (sprite == nullptr) {
return;
}
+ const Common::Rect clippingRect(pos, pos + Common::Point(1, height));
+ const uint16 currentX = clippingRect.left;
+ uint16 currentY = clippingRect.top;
while (currentY < clippingRect.bottom) {
drawSpriteClipped(currentX, currentY, clippingRect, sprite->_width, sprite->_height, sprite->_data.data(), s);
currentY += sprite->_height;
@@ -3572,7 +3561,7 @@ void View1::drawImageResources(Graphics::ManagedSurface &s) {
void View1::showDialogueChoice(uint16 speakerObjectID, const Common::Array<Common::StringArray> &choices, const Common::Point &position, bool onRightSide) {
Common::StringArray joinedLines;
- for (auto ¤tLines : choices) {
+ for (const Common::Array<Common::String> ¤tLines : choices) {
for (auto ¤tLine : currentLines) {
joinedLines.push_back(currentLine);
}
@@ -3581,8 +3570,9 @@ void View1::showDialogueChoice(uint16 speakerObjectID, const Common::Array<Commo
// TTS: speak the dialogue choices
Common::String ttsText;
for (uint i = 0; i < choices.size(); i++) {
- if (!ttsText.empty())
+ if (!ttsText.empty()) {
ttsText += ". ";
+ }
ttsText += Common::String::format("%u: ", i + 1);
for (const Common::String &line : choices[i]) {
ttsText += line + " ";
@@ -3594,7 +3584,7 @@ void View1::showDialogueChoice(uint16 speakerObjectID, const Common::Array<Commo
_isDialogueChoiceInputActive = true;
_dialogueChoiceCount = choices.size();
_dialogueChoiceLineCounts.clear();
- for (const auto &c : choices) {
+ for (const Common::Array<Common::String> &c : choices) {
_dialogueChoiceLineCounts.push_back(c.size());
}
}
@@ -3605,9 +3595,6 @@ void View1::triggerDialogueChoice(uint8 index) {
return;
}
- // Binary handleTimerClick (1008:d53b): stores the script-provided index value
- // from the choice entry (scene+0x5351+choice*6), NOT the 1-based array position.
- // It does NOT resume the script - that happens in handleInput after setting click state.
uint16 scriptIndex = index;
if ((uint)(index - 1) < g_engine->_scriptExecutor->_dialogueChoiceScriptIndices.size()) {
scriptIndex = g_engine->_scriptExecutor->_dialogueChoiceScriptIndices[index - 1];
@@ -3650,7 +3637,7 @@ uint16 View1::getHitObjectID(const Common::Point &pos) const {
return 0;
}
-bool Character::HandleWalkability(Character *c) {
+bool Character::handleWalkability(Character *c) {
// Wall-sliding obstacle avoidance from walkAlongPath (1008:1b8f).
// When the character steps into a non-walkable pixel (walkability >= 200),
// the original code samples walkability at +/-1 and +/-2 pixels in each
@@ -3877,7 +3864,7 @@ void Character::floodFillConnectedNodes(int nodeIndex, bool *visited, int nodeCo
}
}
-Common::Point Character::getPosition() const {
+const Common::Point &Character::getPosition() const {
return _gameObject->_position;
}
@@ -3960,8 +3947,9 @@ bool Character::fillCurrentAnimationFrame(uint16 advanceMode, Macs2::AnimFrame &
_shouldMirrorCurrentAnimation = false;
Common::Array<uint8> *blobPtr = _gameObject->getAnimSlotBlob(animSlot);
- if (blobPtr == nullptr || blobPtr->empty())
+ if (blobPtr == nullptr || blobPtr->empty()) {
return false;
+ }
Common::Array<uint8> &blob = *blobPtr;
const uint16 frameStart = BackgroundAnimationBlob::advanceAnimFrame(blob, true, advanceMode);
@@ -4075,10 +4063,6 @@ bool Character::shouldStepVerticalMotion() const {
}
void Character::update() {
- // Binary drawAllCharacters (1008:90a2): calls walkAlongPath for every character
- // every frame, gated ONLY by: frozen flag and orientation != 0x11.
-
- // Binary: pickup animation handled separately (orientation == 0x11)
if (_gameObject->_orientation == 0x11) {
if (_pickedUpObject != nullptr) {
View1 *currentView = (View1 *)g_engine->findView("View1");
diff --git a/engines/macs2/view1.h b/engines/macs2/view1.h
index 953fd0ffb48..dfa10df1a5f 100644
--- a/engines/macs2/view1.h
+++ b/engines/macs2/view1.h
@@ -78,7 +78,7 @@ public:
private:
// Handle when the character has moved into a non-walkable area, push them out if
// they did and return true, return false otherwise
- bool HandleWalkability(Character *c);
+ bool handleWalkability(Character *c);
// fn0037_0E8C proc
uint16 lookupWalkability(const Common::Point &p) const;
@@ -112,7 +112,7 @@ public:
void startLerpTo(const Common::Point &target, uint32 duration, bool ignoreObstacles = false);
void startPickup(Macs2::GameObject *object);
- Common::Point getPosition() const;
+ const Common::Point &getPosition() const;
void setPosition(const Common::Point &newPosition);
Macs2::GameObject *_gameObject = nullptr;
@@ -327,8 +327,8 @@ private:
void drawSprite(int16 x, int16 y, const Sprite &sprite, Graphics::ManagedSurface &s, bool mirrored, bool useDepth = false, uint8 depth = 0, bool clipToGameArea = false);
void drawSprite(const Common::Point &pos, uint16 width, uint16 height, byte *data, Graphics::ManagedSurface &s, bool mirrored, bool useDepth = false, uint8 depth = 0, bool clipToGameArea = false);
- void drawSpriteClipped(uint16 x, uint16 y, Common::Rect &clippingRect, uint16 width, uint16 height, const byte *const data, Graphics::ManagedSurface &s);
- void drawSpriteClipped(uint16 x, uint16 y, Common::Rect &clippingRect, const Sprite &sprite, Graphics::ManagedSurface &s);
+ void drawSpriteClipped(uint16 x, uint16 y, const Common::Rect &clippingRect, uint16 width, uint16 height, const byte *const data, Graphics::ManagedSurface &s);
+ void drawSpriteClipped(uint16 x, uint16 y, const Common::Rect &clippingRect, const Sprite &sprite, Graphics::ManagedSurface &s);
void drawSpriteFitted(const Common::Rect &bounds, const Sprite &sprite, Graphics::ManagedSurface &s, uint16 inset = 6);
// Binary sortObjectListByY (1008:8cf2) + buildSortedObjectList (1008:8c5a):
@@ -374,21 +374,10 @@ public:
AnimFrame *getInventoryIcon(GameObject *gameObject);
bool _paletteDirty = true;
-
- // Background animation timing from gameTick (1008:e556).
- // The original game increments a tick counter each frame (~70Hz DOS timer)
- // and advances background animations when the counter exceeds a threshold:
- // Background animation timing from gameTick (1008:e556).
- // g_wBgAnimTickCounter is incremented once per game frame (~20fps).
- // Background animation tick counter (mode 2: threshold 0x27, mode 3: threshold 1)
- static constexpr uint32 kGameFrameRate = 20;
-
- // Binary g_wIsShowingTextBox (1020:0ff6): set by scriptPrintString, cleared by handleTextBoxInput
bool _isShowingTextBox = false;
- // Binary g_wIsShowingDialoguePanel (1020:1008): set by scriptShowDialogue, cleared by dismissDialoguePanel
bool _isShowingDialoguePanel = false;
- Common::StringArray _drawnStringBox;
bool _continueScriptAfterUI = false;
+ Common::StringArray _drawnStringBox;
uint16 _dialogueChoiceCount = 0;
Common::Array<uint16> _dialogueChoiceLineCounts;
SpeechActData currentSpeechActData;
@@ -428,9 +417,6 @@ public:
void finishPanelCloseAfterRelease(UiPanelState closedFromState);
- // Binary scene+0x53B9: dialogue choice input mode active (waiting for player to pick an answer)
- bool _isDialogueChoiceInputActive = false;
-
// Binary g_wPendingPanelRequest (1020:1034): deferred panel open request.
// Set while action bar is active; processed by gameTick when _uiPanelState returns to kUiPanelNone.
// Values: 0=none, 1=protagonist inventory, 2=container inventory, 3=save/load
@@ -443,10 +429,8 @@ public:
};
PendingPanelRequest _pendingPanelRequest = kPanelRequestNone;
- // Binary g_wUiBackgroundRestorePending: set when panel was open and background needs redraw
bool _uiBackgroundRestorePending = false;
-
- // Binary g_wSavedCursorMode [scene+0xFEA]: saved before opening action bar panel
+ bool _isDialogueChoiceInputActive = false;
Script::MouseMode _savedCursorMode = Script::MouseMode::Walk;
enum class InventoryButtonIndex {
@@ -523,7 +507,6 @@ public:
void closeScriptActionBar(Script::MouseMode &outSavedCursorMode);
void enterMapMode();
- // Binary openActionBarAtPosition
void layoutActionBarButtons();
void drawMainMenu(Graphics::ManagedSurface &s);
void drawSceneUpdate();
Commit: bdca62eb7c5f5df3758007067a25a99ea5c90290
https://github.com/scummvm/scummvm/commit/bdca62eb7c5f5df3758007067a25a99ea5c90290
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: convert object orientation into an enum
Changed paths:
engines/macs2/amiga_resources.cpp
engines/macs2/debugtools.cpp
engines/macs2/detection.cpp
engines/macs2/detection.h
engines/macs2/gameobjects.cpp
engines/macs2/gameobjects.h
engines/macs2/macs2.cpp
engines/macs2/macs2.h
engines/macs2/saveload.cpp
engines/macs2/scriptexecutor.cpp
engines/macs2/view1.cpp
engines/macs2/view1.h
diff --git a/engines/macs2/amiga_resources.cpp b/engines/macs2/amiga_resources.cpp
index 6521eb8da1e..a566d8a4860 100644
--- a/engines/macs2/amiga_resources.cpp
+++ b/engines/macs2/amiga_resources.cpp
@@ -548,7 +548,7 @@ void Macs2Engine::readAmigaResources() {
gameObject->_dataOffset = 1;
gameObject->_position = Common::Point(0, 0);
gameObject->_sceneIndex = 0;
- gameObject->_orientation = 11;
+ gameObject->_orientation = OrientationStandingEast;
gameObject->_verticalOffsetScale = 0;
while (gameObject->_blobs.size() < 0x15)
@@ -653,7 +653,7 @@ void Macs2Engine::readAmigaResources() {
}
protagonist->_sceneIndex = 0;
protagonist->_position = Common::Point(0, 0);
- protagonist->_orientation = 11;
+ protagonist->_orientation = OrientationStandingEast;
Scenes::instance()._currentActorIndex = 1;
diff --git a/engines/macs2/debugtools.cpp b/engines/macs2/debugtools.cpp
index 6a3335373a6..50bd900e62c 100644
--- a/engines/macs2/debugtools.cpp
+++ b/engines/macs2/debugtools.cpp
@@ -987,7 +987,8 @@ static void showCharactersWindow() {
// --- Editable GameObject fields ---
int orient = (int)c->_gameObject->_orientation;
if (ImGui::InputInt("Orientation", &orient)) {
- c->_gameObject->_orientation = (uint8)CLIP(orient, 0, 255);
+ // TODO: add a combo box for orientation instead of raw int input including speaking names
+ c->_gameObject->_orientation = (ObjectOrientation)CLIP((uint16)orient, (uint16)OrientationNone, (uint16)OrientationPickup);
}
int animIdx = (int)c->_animationIndex;
@@ -1898,7 +1899,6 @@ static void showDebugToolbarWindow() {
} channels[] = {
{kDebugGraphics, "Graphics"},
{kDebugPath, "Path"},
- {kDebugScan, "Scan"},
{kDebugFilePath, "FilePath"},
{kDebugInput, "Input"},
{kDebugImGui, "ImGui"},
diff --git a/engines/macs2/detection.cpp b/engines/macs2/detection.cpp
index f306d4e0974..485290cf027 100644
--- a/engines/macs2/detection.cpp
+++ b/engines/macs2/detection.cpp
@@ -28,7 +28,6 @@ const DebugChannelDef Macs2MetaEngineDetection::debugFlagList[] = {
{Macs2::kDebugPath, "Path", "Pathfinding debug level"},
{Macs2::kDebugFilePath, "FilePath", "File path debug level"},
{Macs2::kDebugInput, "Input", "Input debug level"},
- {Macs2::kDebugScan, "Scan", "Scan for unrecognised games"},
{Macs2::kDebugScript, "Script", "Enable debug script dump"},
DEBUG_CHANNEL_END};
diff --git a/engines/macs2/detection.h b/engines/macs2/detection.h
index 52f60774382..f2605fa2ebe 100644
--- a/engines/macs2/detection.h
+++ b/engines/macs2/detection.h
@@ -29,7 +29,6 @@ namespace Macs2 {
enum Macs2DebugChannels {
kDebugGraphics = 1 << 0,
kDebugPath = 1 << 1,
- kDebugScan = 1 << 2,
kDebugFilePath = 1 << 3,
kDebugInput = 1 << 4,
kDebugScript = 1 << 5,
diff --git a/engines/macs2/gameobjects.cpp b/engines/macs2/gameobjects.cpp
index 4556d6e0160..61e9e05d554 100644
--- a/engines/macs2/gameobjects.cpp
+++ b/engines/macs2/gameobjects.cpp
@@ -31,11 +31,9 @@ DECLARE_SINGLETON(Macs2::Scenes);
} // namespace Common
Common::MemoryReadStream *Macs2::Scenes::readSceneScript(uint16 sceneIndex, Common::SeekableReadStream *fileStream) {
- // Directory entry for sceneIndex: absolute seek uses
- // directoryOffset + sceneIndex * 0xC - 8 (second dword of entry sceneIndex-1).
const uint32 directoryOffset = g_engine->getMcsDirectoryOffset();
fileStream->seek(directoryOffset + sceneIndex * 0xC - 0x8);
- uint32 sceneDataOffset2 = fileStream->readUint32LE();
+ const uint32 sceneDataOffset2 = fileStream->readUint32LE();
fileStream->seek(sceneDataOffset2, SEEK_SET);
if (g_engine->isV2()) {
@@ -46,7 +44,7 @@ Common::MemoryReadStream *Macs2::Scenes::readSceneScript(uint16 sceneIndex, Comm
// V1: skip 0x80 resource offsets, then script size + bytecode.
fileStream->seek(0x80, SEEK_CUR);
}
- uint16 scriptSize = fileStream->readUint16LE();
+ const uint16 scriptSize = fileStream->readUint16LE();
if (scriptSize == 0) {
warning("Macs2::Scenes::ReadSceneScript: scene %u has empty script", sceneIndex);
return new Common::MemoryReadStream(nullptr, 0);
@@ -62,9 +60,8 @@ Common::Array<uint32> Macs2::Scenes::readSpecialAnimsOffsets(uint16 sceneIndex,
const uint32 directoryOffset = g_engine->getMcsDirectoryOffset();
fileStream->seek(directoryOffset + sceneIndex * 0xC - 0x8);
- uint32 sceneDataOffset2 = fileStream->readUint32LE();
+ const uint32 sceneDataOffset2 = fileStream->readUint32LE();
fileStream->seek(sceneDataOffset2, SEEK_SET);
-
fileStream->read(result.data(), 0x80);
return result;
@@ -72,13 +69,10 @@ Common::Array<uint32> Macs2::Scenes::readSpecialAnimsOffsets(uint16 sceneIndex,
Common::MemoryReadStream *Macs2::Scenes::readSceneStrings(uint16 sceneIndex, Common::SeekableReadStream *fileStream) {
const uint32 directoryOffset = g_engine->getMcsDirectoryOffset();
- // Third dword of entry (sceneIndex-1) / strings blob - DOS formula directory+scene*0xC-4.
fileStream->seek(directoryOffset + sceneIndex * 0xC - 0x4);
- uint32 sceneDataOffset2 = fileStream->readUint32LE();
+ const uint32 sceneDataOffset2 = fileStream->readUint32LE();
fileStream->seek(sceneDataOffset2, SEEK_SET);
-
- uint16 size = fileStream->readUint16LE();
-
+ const uint16 size = fileStream->readUint16LE();
byte *stringData = (byte *)malloc(size);
fileStream->read(stringData, size);
return new Common::MemoryReadStream(stringData, size, DisposeAfterUse::YES);
@@ -90,13 +84,13 @@ Common::Array<uint8> Macs2::Scenes::readSpecialAnimBlob(uint16 index, Common::Se
index, _currentSceneSpecialAnimOffsets.size());
return Common::Array<uint8>();
}
- uint32 offset = _currentSceneSpecialAnimOffsets[index - 1];
+ const uint32 offset = _currentSceneSpecialAnimOffsets[index - 1];
if (offset == 0 || fileStream == nullptr) {
warning("readSpecialAnimBlob: null offset for index %u", index);
return Common::Array<uint8>();
}
fileStream->seek(offset, SEEK_SET);
- uint32 length = fileStream->readUint32LE();
+ const uint32 length = fileStream->readUint32LE();
// Skip a string - note the original code adds 0x4 for the previously read size since
// it does not use the stream position
fileStream->seek(0xC, SEEK_CUR);
@@ -107,6 +101,9 @@ Common::Array<uint8> Macs2::Scenes::readSpecialAnimBlob(uint16 index, Common::Se
void Macs2::GameObjects::init() {
_objectNames.resize(0xFF);
+ if (!g_engine->isV1()) {
+ return;
+ }
// Object names from game string dumps. Index matches the object ID used in scripts.
if (g_engine->isDemo()) {
_objectNames[0x02] = "Laib Brot"; // sliced
@@ -353,8 +350,13 @@ void Macs2::GameObjects::init() {
}
bool Macs2::GameObjects::isNpcIndex(uint16 objectIndex) {
- if (objectIndex == 0)
+ if (objectIndex == 0) {
return false;
+ }
+
+ if (!g_engine->isV1()) {
+ return false;
+ }
if (g_engine->isDemo()) {
static const uint16 kDemoNpcIndices[] = {
@@ -394,22 +396,23 @@ Common::MemoryReadStream *Macs2::GameObjects::readGameObjectStrings(uint16 index
// Amiga: strings live on the GameObject itself (plaintext, u16BE lengths).
if (g_engine->isAmiga()) {
GameObject *obj = getObjectByIndex(index);
- if (obj == nullptr)
+ if (obj == nullptr) {
return new Common::MemoryReadStream(nullptr, 0);
+ }
byte *copy = (byte *)malloc(obj->_stringData.size());
- if (!obj->_stringData.empty())
+ if (!obj->_stringData.empty()) {
memcpy(copy, obj->_stringData.data(), obj->_stringData.size());
+ }
return new Common::MemoryReadStream(copy, obj->_stringData.size(), DisposeAfterUse::YES);
}
const uint32 directoryOffset = g_engine->getMcsDirectoryOffset();
// Object string table pointer at directory + index*0xC + 0x17FC.
fileStream->seek(directoryOffset + index * 0xC + 0x17FC);
- uint32 sceneDataOffset2 = fileStream->readUint32LE();
+ const uint32 sceneDataOffset2 = fileStream->readUint32LE();
fileStream->seek(sceneDataOffset2, SEEK_SET);
- uint16 size = fileStream->readUint16LE();
-
+ const uint16 size = fileStream->readUint16LE();
byte *stringData = (byte *)malloc(size);
fileStream->read(stringData, size);
return new Common::MemoryReadStream(stringData, size, DisposeAfterUse::YES);
@@ -418,17 +421,20 @@ Common::MemoryReadStream *Macs2::GameObjects::readGameObjectStrings(uint16 index
Common::Array<uint8> *Macs2::GameObject::getAnimSlotBlob(uint16 slot) {
const uint16 maxSlots = g_engine->maxAnimSlots();
const uint16 overloadSlot = g_engine->overloadAnimSlot();
- if (slot < 1 || slot > maxSlots)
+ if (slot < 1 || slot > maxSlots) {
return nullptr;
+ }
if (slot == overloadSlot) {
const uint overloadIndex = overloadSlot - 1;
- if (_blobs.size() > overloadIndex && !_blobs[overloadIndex].empty())
+ if (_blobs.size() > overloadIndex && !_blobs[overloadIndex].empty()) {
return &_blobs[overloadIndex];
+ }
return &_overloadAnimation;
}
const uint index = slot - 1;
- if (index >= _blobs.size())
+ if (index >= _blobs.size()) {
return nullptr;
+ }
return &_blobs[index];
}
@@ -465,8 +471,9 @@ bool Macs2::GameObject::isAnimSlotLoaded(uint16 orient) const {
if (slot < _blobs.size() && !_blobs[slot].empty()) {
return true;
}
- if (slot < _blobWalkSpeeds.size() && (_blobWalkSpeeds[slot] & 0xFF00) != 0)
+ if (slot < _blobWalkSpeeds.size() && (_blobWalkSpeeds[slot] & 0xFF00) != 0) {
return true;
+ }
return false;
}
@@ -497,9 +504,7 @@ uint16 Macs2::AnimationReader::readNumAnimations() {
// Frame count is stored right after the header + command section
_readStream->seek(0x0B + commandSectionLength);
- // bp-24h
- const uint16 result = _readStream->readUint16();
- return result;
+ return _readStream->readUint16();
}
void Macs2::AnimationReader::seekToAnimation(uint16 index) {
diff --git a/engines/macs2/gameobjects.h b/engines/macs2/gameobjects.h
index 0a6f9ac3666..927c59716aa 100644
--- a/engines/macs2/gameobjects.h
+++ b/engines/macs2/gameobjects.h
@@ -71,7 +71,6 @@ class AnimationReader {
public:
Common::MemoryReadStreamEndian *_readStream;
- // TODO: Can the init list also go into the cpp file?
AnimationReader(const Common::Array<uint8> &blob);
~AnimationReader();
@@ -84,6 +83,27 @@ public:
void skipCurrentAnimationFrame();
};
+enum ObjectOrientation : uint16 {
+ OrientationNone = 0,
+ OrientationNorth = 1,
+ OrientationNorthEast = 2,
+ OrientationEast = 3,
+ OrientationSouthEast = 4,
+ OrientationSouth = 5,
+ OrientationSouthWest = 6,
+ OrientationWest = 7,
+ OrientationNorthWest = 8,
+ OrientationStandingNorth = 9,
+ OrientationStandingNorthEast = 10,
+ OrientationStandingEast = 11,
+ OrientationStandingSouthEast = 12,
+ OrientationStandingSouth = 13,
+ OrientationStandingSouthWest = 14,
+ OrientationStandingWest = 15,
+ OrientationStandingNorthWest = 16,
+ OrientationPickup = 17
+};
+
class GameObject {
public:
// Index of the object, starting at 1
@@ -105,22 +125,10 @@ public:
// These are the values read by the code around l0037_082D:
Common::Point _position;
uint16 _sceneIndex = 0;
- // 8-directional movement system from walkAlongPath (1008:1b8f).
- // Direction codes 1-8 are walking directions, 9-16 are standing (idle) variants.
// The direction is chosen based on the angle between current and target position:
- // 1 = North (up) - deltaY dominates, target above
- // 2 = NorthEast - diagonal (deltaX/4 < deltaY < deltaX*2)
- // 3 = East (right) - deltaX dominates, target to the right
- // 4 = SouthEast - diagonal
- // 5 = South (down) - deltaY dominates, target below
- // 6 = SouthWest - diagonal
- // 7 = West (left) - deltaX dominates, target to the left
- // 8 = NorthWest - diagonal
- // 9-16 = Standing idle variants (walking direction + 8)
- // 17 (0x11) = Pickup animation
// Each direction has a validity flag at runtime offset +0x43 + (dir-1)*0x20
// that indicates whether the object has animation data for that direction.
- uint16 _orientation = 0;
+ ObjectOrientation _orientation = OrientationNone;
// Per-object percentage multiplier for ground-elevation vertical offset.
// Walkability map values < 0xC8 represent ground height at each pixel;
// this factor scales how much that height displaces the object upward
@@ -197,12 +205,12 @@ public:
// survives scene change / off-scene script opcodes). Restored on Character create.
struct StoredWalkRuntime {
bool valid = false;
+ bool stepDirectionSet = false;
Common::Point targetPosition;
Common::Point pathFinalDestination;
int16 stepDeltaX = 0;
int16 stepDeltaY = 0;
int16 stepError = 0;
- bool stepDirectionSet = false;
int16 currentPathIndex = 0;
Common::Array<uint16> path;
uint16 motionTargetVerticalOffset = 0;
@@ -226,7 +234,6 @@ public:
class GameObjects : public Common::Singleton<GameObjects> {
public:
Common::Array<GameObject *> _objects;
-
Common::Array<Common::String> _objectNames;
void init();
diff --git a/engines/macs2/macs2.cpp b/engines/macs2/macs2.cpp
index 10330d49401..2ef1d5e5f7e 100644
--- a/engines/macs2/macs2.cpp
+++ b/engines/macs2/macs2.cpp
@@ -515,7 +515,7 @@ void Macs2Engine::loadResourceFileV2() {
void Macs2Engine::bootstrapMcsActorsObjectsAndScene() {
Scenes &scenes = Scenes::instance();
scenes._currentActorIndex = _fileStream->readUint16LE();
- uint16 firstSceneIndex = _fileStream->readUint16LE();
+ const uint16 firstSceneIndex = _fileStream->readUint16LE();
scenes._currentSceneIndex = firstSceneIndex;
scenes._currentSceneScript = scenes.readSceneScript(firstSceneIndex, _fileStream);
scenes._currentSceneStrings = scenes.readSceneStrings(firstSceneIndex, _fileStream);
@@ -527,7 +527,6 @@ void Macs2Engine::bootstrapMcsActorsObjectsAndScene() {
const uint32 dir = getMcsDirectoryOffset();
GameObjects::instance()._objects.resize(0x200, nullptr);
for (int i = 1; i <= 0x200; i++) {
- // Directory object DATA dword: file+kMcsV1DirectoryOffset+kMcsV1ObjectDataPtrRel+i*12
const uint32 addressOffset = dir + kMcsV1ObjectDataPtrRel + (uint32)i * 0xC;
_fileStream->seek(addressOffset, SEEK_SET);
uint32 objectOffset = _fileStream->readUint32LE();
@@ -549,7 +548,8 @@ void Macs2Engine::bootstrapMcsActorsObjectsAndScene() {
}
gameObject->_position = Common::Point(x, y);
gameObject->_sceneIndex = _fileStream->readUint16LE();
- gameObject->_orientation = _fileStream->readUint16LE();
+ const uint16 orientation = _fileStream->readUint16LE();
+ gameObject->_orientation = (ObjectOrientation)orientation;
gameObject->_verticalOffsetScale = _fileStream->readUint16LE();
const uint16 animSlotCount = maxAnimSlots();
@@ -559,9 +559,10 @@ void Macs2Engine::bootstrapMcsActorsObjectsAndScene() {
for (int j = 0; j < (int)animSlotCount; j++) {
_fileStream->readUint16LE(); // animID
_fileStream->readUint16LE(); // sourceKey
- uint32 dataSize = _fileStream->readUint32LE();
- if (dataSize > 0)
+ const uint32 dataSize = _fileStream->readUint32LE();
+ if (dataSize > 0) {
_fileStream->skip(dataSize);
+ }
_fileStream->readUint16LE(); // speed
_fileStream->readByte(); // mirror
_fileStream->readByte(); // pad
@@ -577,20 +578,21 @@ void Macs2Engine::bootstrapMcsActorsObjectsAndScene() {
} else {
for (int j = 1; j <= (int)animSlotCount; j++) {
_fileStream->readUint16LE(); // animID
- uint16 blobSourceKey = _fileStream->readUint16LE();
- uint32 dataSize = _fileStream->readUint32LE();
+ const uint16 blobSourceKey = _fileStream->readUint16LE();
+ const uint32 dataSize = _fileStream->readUint32LE();
uint8 *data = new uint8[dataSize];
_fileStream->read(data, dataSize);
gameObject->_blobs.push_back(Common::Array<uint8>(data, dataSize));
delete[] data;
gameObject->_blobSourceKeys.push_back(blobSourceKey);
- uint16 blobSpeed = _fileStream->readUint16LE();
+ const uint16 blobSpeed = _fileStream->readUint16LE();
gameObject->_blobWalkSpeeds.push_back(blobSpeed);
- uint16 blobMirrorFlag = _fileStream->readByte();
+ const uint16 blobMirrorFlag = _fileStream->readByte();
_fileStream->readByte();
gameObject->_blobMirrorFlags.push_back(blobMirrorFlag != 0);
- if (blobMirrorFlag != 0 && dataSize > 0)
+ if (blobMirrorFlag != 0 && dataSize > 0) {
BackgroundAnimationBlob::mirrorAnimBlob(gameObject->_blobs.back());
+ }
}
_fileStream->readByte();
gameObject->_hasShading = _fileStream->readByte() != 0;
@@ -601,14 +603,6 @@ void Macs2Engine::bootstrapMcsActorsObjectsAndScene() {
_fileStream->seek(scriptPtrOffset, SEEK_SET);
objectOffset = _fileStream->readUint32LE();
- // Binary loadResourceFile prunes an object slot ONLY when its DATA offset
- // (scene table +0x17F4) is zero (handled by the `continue` above). A zero
- // SCRIPT offset (+0x17F8) does NOT remove the object - it simply has no
- // script/resource table. The original keeps the slot non-null so that the
- // object set (used implicitly by save/load record ordering) stays correct.
- // Previously this did `break`, which leaked this object, left it null, and
- // aborted loading every higher-index object - corrupting the object set
- // and shifting the save-file object section.
if (objectOffset == 0) {
GameObjects::instance()._objects[i - 1] = gameObject;
continue;
diff --git a/engines/macs2/macs2.h b/engines/macs2/macs2.h
index 4c523b18af0..f53713fe1d9 100644
--- a/engines/macs2/macs2.h
+++ b/engines/macs2/macs2.h
@@ -777,7 +777,7 @@ public:
bool isDemo() const { return getFeatures() & ADGF_DEMO; }
- /** AHFFMACS0200 dialect (directory at 0x212) vs AHFFMACS0100 (0x10). */
+ bool isV1() const { return _mcsFileVersion == McsFileVersion::V1; }
bool isV2() const { return _mcsFileVersion == McsFileVersion::V2; }
/** MCS directory base. */
@@ -825,15 +825,15 @@ public:
uint16 ticksPerGameFrame() const { return isV2() ? 1 : 2; }
/** ReadyObject anim slots (1-based inclusive max). */
- uint16 maxAnimSlots() const { return isV2() ? 0x26 : 0x15; }
+ uint16 maxAnimSlots() const { return isV2() ? 38 : 21; }
/** Orientations that map to anim slots 1..N (inclusive). */
- uint16 maxOrientations() const { return isV2() ? 0x25 : 0x14; }
+ uint16 maxOrientations() const { return maxAnimSlots() - 1; }
/** Overload / special-anim slot index. */
uint16 overloadAnimSlot() const { return maxAnimSlots(); }
static uint16 specialAnimSlotToAnimSlot(uint16 specialSlot);
/** Scene hotspot override table entries (1-based inclusive max). */
/** Hotspot remap table indices (1-based). DOS scene+0x5BD1: 16; V2 ActModule+0x6161: 32. */
- uint16 maxHotspots() const { return isV2() ? 0x20 : 0x10; }
+ uint16 maxHotspots() const { return isV2() ? 32 : 16; }
/** Per-object resource offset table entries. */
uint maxObjectResources() const { return 32; }
/** Anim slot used for the current orientation (overload-direction rule). */
diff --git a/engines/macs2/saveload.cpp b/engines/macs2/saveload.cpp
index 971f872f864..1a5532df71f 100644
--- a/engines/macs2/saveload.cpp
+++ b/engines/macs2/saveload.cpp
@@ -567,10 +567,10 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
chr->_pickupFrameCounter = pickupFrameCounter;
s.syncAsUint16LE(obj->_pickupFrameStart);
s.syncAsUint16LE(obj->_pickupFrameEnd);
- uint16 prevOrientation = chr ? chr->_previousOrientation : 0;
+ uint16 prevOrientation = chr ? chr->_previousOrientation : OrientationNone;
s.syncAsUint16LE(prevOrientation);
if (s.isLoading())
- chr->_previousOrientation = (uint8)prevOrientation;
+ chr->_previousOrientation = (ObjectOrientation)prevOrientation;
s.syncAsUint16LE(obj->_overloadAnimTriggerDirection);
diff --git a/engines/macs2/scriptexecutor.cpp b/engines/macs2/scriptexecutor.cpp
index 12c593196c5..7758d7331be 100644
--- a/engines/macs2/scriptexecutor.cpp
+++ b/engines/macs2/scriptexecutor.cpp
@@ -2061,12 +2061,12 @@ OpcodeResult Script::ScriptExecutor::scriptSetOrientation() {
setScriptError(0x19);
return OpcodeResult::Continue;
}
- if (animIndex < 9 || animIndex > 0x10) {
+ if (animIndex < OrientationStandingNorth || animIndex > OrientationStandingNorthWest) {
setScriptError(0x14);
return OpcodeResult::Continue;
}
- object->_orientation = animIndex;
+ object->_orientation = (ObjectOrientation)animIndex;
return OpcodeResult::Continue;
}
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 867a2631ac3..38df8433eb1 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -2502,12 +2502,12 @@ bool View1::tick() {
_bgAnimTickCounter = 0;
g_engine->updateBackgroundAnimationPalette();
}
- if (_bgAnimTickCounter > 0x27 && g_engine->_scenePaletteMode == 2) {
+ if (_bgAnimTickCounter > 39 && g_engine->_scenePaletteMode == 2) {
_bgAnimTickCounter = 0;
g_engine->updateBackgroundAnimationPalette();
}
- // Advance portrait animation once per tick (matching handleDialogueInput 1008:b4bd)
+ // Advance portrait animation once per tick
if (_isShowingDialoguePanel && currentSpeechActData.speaker != nullptr && currentSpeechActData.mouthAnimActive) {
Character *speaker = currentSpeechActData.speaker;
if (currentSpeechActData.mouthAnimCounter < 1) {
@@ -2531,7 +2531,7 @@ bool View1::tick() {
}
}
- // Binary gameTick (1008:e556): process pending panel requests when state is idle.
+ // process pending panel requests when state is idle
if (_uiPanelState == kUiPanelNone && _pendingPanelRequest != kPanelRequestNone) {
switch (_pendingPanelRequest) {
case kPanelRequestInventory:
@@ -2615,11 +2615,11 @@ bool View1::tick() {
executor->debugLogActorWalkState("waitForWalk complete");
executor->_walkTargetObjectIndex = 0;
g_engine->runScriptExecutor();
- } else if (c != nullptr && c->_gameObject->_orientation != 0x11) {
+ } else if (c != nullptr && c->_gameObject->_orientation != OrientationPickup) {
// Binary: pickup in progress, trigger pickup animation.
// Save current orientation so it can be restored after pickup.
c->_previousOrientation = c->_gameObject->_orientation;
- c->_gameObject->_orientation = 0x11;
+ c->_gameObject->_orientation = OrientationPickup;
}
}
}
@@ -2649,13 +2649,14 @@ bool View1::tick() {
} else if (executor->_waitForObjectAnimStep) {
drawSceneUpdate();
bool animStepReached = false;
- GameObject *waitObject = GameObjects::getObjectByIndex(executor->_waitObjectAnimObjectId);
+ const GameObject *waitObject = GameObjects::getObjectByIndex(executor->_waitObjectAnimObjectId);
if (waitObject != nullptr && waitObject->_dataOffset != 0) {
const Common::Array<uint8> *blob = waitObject->getAnimSlotBlob(executor->_waitObjectAnimSlot);
if (blob != nullptr && !blob->empty()) {
AnimBlobView view(*blob);
- if (view.isValid())
+ if (view.isValid()) {
animStepReached = view.sequencePosition() >= executor->_waitObjectAnimTargetStep;
+ }
}
}
if (animStepReached) {
@@ -2716,8 +2717,6 @@ bool View1::tick() {
g_engine->runScriptExecutor();
}
}
-
- // Binary gameTick (1008:e556): drawScene(1) when not executing is handled by redraw().
}
redraw();
@@ -2740,7 +2739,6 @@ void View1::drawAllCharacters(Graphics::ManagedSurface *surface, bool fullUpdate
const uint16 sortedCount = _sortedObjectCount;
Script::ScriptExecutor *executor = g_engine->_scriptExecutor;
- // --- Pass 1 (1008:90a2): erase previous sprite rects, walkAlongPath, pickup ---
if (fullUpdate && sortedCount > 0) {
for (uint16 local_c = 1; local_c <= sortedCount; local_c++) {
const uint16 objectIndex = _sortedObjectIndices[local_c];
@@ -2748,7 +2746,6 @@ void View1::drawAllCharacters(Graphics::ManagedSurface *surface, bool fullUpdate
if (obj == nullptr || obj->_index != objectIndex)
continue;
- // Binary pass 1: runtime+0x20D..+0x213 from object runtime+0x225..+0x22B.
const int32 eraseLeft = obj->_lastDrawX;
const int32 eraseTop = obj->_lastDrawY;
const int32 eraseRight = eraseLeft + (int32)obj->_lastDrawWidth + 1;
@@ -2777,37 +2774,36 @@ void View1::drawAllCharacters(Graphics::ManagedSurface *surface, bool fullUpdate
(current->_markedForDeletion || current->_gameObject != obj))
current = nullptr;
- // walkAlongPath(objectIndex) when orientation != 0x11; pickup at 0x11.
if (current != nullptr) {
- if (obj->_orientation != 0x11)
- current->update();
- else if (executor->_pickupInProgress)
+ if (obj->_orientation != OrientationPickup || executor->_pickupInProgress)
current->update();
}
}
flushPendingCharacterDeletes();
}
- // --- Background animations (1008:929c, before LAB_1008_92d4) ---
- if (surface != nullptr && _currentMode != ViewMode::VM_HELP)
+ if (surface != nullptr && _currentMode != ViewMode::VM_HELP) {
drawBackgroundAnimations(*surface);
+ }
- // --- Pass 2 (LAB_1008_92d4): draw sorted scene objects back -> front ---
+ // draw sorted scene objects back -> front
if (surface != nullptr && !executor->hasScriptError() && sortedCount > 0) {
const uint16 animAdvanceMode = (fullUpdate && _uiPanelState == kUiPanelNone) ? 2 : 0;
for (uint16 local_c = 1; local_c <= sortedCount; local_c++) {
const uint16 objectIndex = _sortedObjectIndices[local_c];
GameObject *obj = GameObjects::getObjectByIndex(objectIndex);
- if (obj == nullptr || obj->_index != objectIndex)
+ if (obj == nullptr || obj->_index != objectIndex) {
continue;
+ }
Character *current = _characterByObjectIndex[objectIndex];
if (current != nullptr &&
- (current->_markedForDeletion || current->_gameObject != obj))
+ (current->_markedForDeletion || current->_gameObject != obj)) {
current = nullptr;
+ }
if (obj->_hasBoundsAttachment) {
- GameObject *parent = GameObjects::getObjectByIndex(obj->_boundsAttachmentObjectID);
+ const GameObject *parent = GameObjects::getObjectByIndex(obj->_boundsAttachmentObjectID);
if (parent != nullptr) {
obj->_position.x = parent->_position.x + (int16)obj->_boundsAttachmentValue1;
obj->_position.y = parent->_position.y + (int16)obj->_boundsAttachmentValue2;
@@ -2822,7 +2818,6 @@ void View1::drawAllCharacters(Graphics::ManagedSurface *surface, bool fullUpdate
}
const uint16 animSlot = g_engine->resolveAnimSlotIndex(obj);
-
if (!obj->isAnimSlotLoaded(animSlot)) {
executor->setScriptError(10);
return;
@@ -2847,7 +2842,7 @@ void View1::drawAllCharacters(Graphics::ManagedSurface *surface, bool fullUpdate
return;
}
} else {
- uint16 frameStart = BackgroundAnimationBlob::advanceAnimFrame(*blob, true, animAdvanceMode);
+ const uint16 frameStart = BackgroundAnimationBlob::advanceAnimFrame(*blob, true, animAdvanceMode);
frame._offsetX = (int16)READ_LE_UINT16(&(*blob)[frameStart]);
frame._offsetY = (int16)READ_LE_UINT16(&(*blob)[frameStart + 2]);
const uint16 offset = frameStart + 6;
@@ -2861,7 +2856,7 @@ void View1::drawAllCharacters(Graphics::ManagedSurface *surface, bool fullUpdate
const int16 charY = obj->_position.y;
// drawAllCharacters @ 1008:93f8-9440 (inlined; not a separate EXE function)
- int32 depthOffset = ((int32)charY - (int32)g_engine->_walkDepthThresholdY) *
+ const int32 depthOffset = ((int32)charY - (int32)g_engine->_walkDepthThresholdY) *
(int32)g_engine->_walkDepthScaleFactor / 100;
uint16 scalingFactor = (uint16)((int32)g_engine->_walkBaseSpeedPct + depthOffset);
if (obj->_hasDoubleResAnim)
@@ -2934,17 +2929,15 @@ void View1::drawAllCharacters(Graphics::ManagedSurface *surface, bool fullUpdate
const_cast<byte *>(pixelData), *surface, false, false, 0, clipGameArea);
}
- // drawAllCharacters @ 1008:9759: wLastDrawX/Y exclude per-frame offsetX/offsetY
- // (offsets applied inside drawAnimFrameDepth @ 1010:1753-1759 only)
obj->_lastDrawX = charX - (frameWidth >> 1);
obj->_lastDrawY = (charY - frameHeight) - walkabilityOffset;
obj->_lastDrawWidth = frameWidth;
obj->_lastDrawHeight = frameHeight;
- int16 newLeft = obj->_lastDrawX - 1;
- int16 newTop = obj->_lastDrawY - 1;
- int16 newRight = obj->_lastDrawX + 2 * (frameWidth >> 1) + 1;
- int16 newBottom = obj->_lastDrawY + frameHeight + 1;
+ const int16 newLeft = obj->_lastDrawX - 1;
+ const int16 newTop = obj->_lastDrawY - 1;
+ const int16 newRight = obj->_lastDrawX + 2 * (frameWidth >> 1) + 1;
+ const int16 newBottom = obj->_lastDrawY + frameHeight + 1;
if (newLeft < obj->_dirtyLeft)
obj->_dirtyLeft = newLeft;
@@ -2956,16 +2949,17 @@ void View1::drawAllCharacters(Graphics::ManagedSurface *surface, bool fullUpdate
obj->_dirtyBottom = newBottom;
if (obj->_dirtyTop < 0)
- obj->_dirtyLeft = 0;
+ obj->_dirtyLeft = 0; // TODO: check this is in disassembly
if (obj->_dirtyBottom < 0)
obj->_dirtyBottom = 0;
if (current != nullptr && DebugMan.isDebugChannelEnabled(kDebugGraphics)) {
- Common::String number = Common::String::format("%u", obj->_orientation);
+ const Common::String &number = Common::String::format("%u", obj->_orientation);
renderString(current->getPosition(), number.c_str());
- Common::Rect screenRect(0, 0, g_engine->screenWidth(), g_engine->gameHeight());
- if (screenRect.contains(current->getPosition()))
+ const Common::Rect screenRect(0, 0, g_engine->screenWidth(), g_engine->gameHeight());
+ if (screenRect.contains(current->getPosition())) {
surface->setPixel(current->getPosition().x, current->getPosition().y, 0xFF);
+ }
}
}
}
@@ -4107,15 +4101,17 @@ void Character::update() {
// pwVar7[orientation * 8 + 0x18] = word at runtime + orientation*16 + 0x30
// = AnimSlot.wAnimSpeed (slot+0x0C). Stored in _blobWalkSpeeds.
uint16 animSpeed = 2; // default fallback
- uint8 orient = _gameObject->_orientation;
- if (orient >= 1 && orient <= g_engine->maxAnimSlots() && (uint)(orient - 1) < _gameObject->_blobWalkSpeeds.size()) {
+ ObjectOrientation orient = _gameObject->_orientation;
+ if (orient >= OrientationNorth && orient <= g_engine->maxAnimSlots() && (uint)(orient - 1) < _gameObject->_blobWalkSpeeds.size()) {
animSpeed = _gameObject->_blobWalkSpeeds[orient - 1];
- if (animSpeed == 0)
+ if (animSpeed == 0) {
animSpeed = 2;
+ }
}
int walkSpeed = ((int)animSpeed * ((int)g_engine->_walkBaseSpeedPct + (int)depthOffset)) / 100;
- if (walkSpeed < 1)
+ if (walkSpeed < 1) {
walkSpeed = 1;
+ }
// Proximity arrival check from walkAlongPath (1008:1b8f):
// Binary checks if character is within walkSpeed pixels of target in both axes.
@@ -4127,7 +4123,7 @@ void Character::update() {
}
if (arrived) {
// Binary (22cd): check if target == finalDest (at final destination)
- bool atFinalDest = (_targetPosition.x == _pathFinalDestination.x &&
+ const bool atFinalDest = (_targetPosition.x == _pathFinalDestination.x &&
_targetPosition.y == _pathFinalDestination.y);
if (!atFinalDest && !_path.empty()) {
@@ -4156,22 +4152,11 @@ void Character::update() {
}
// Walk arrival: orientation changes to standing (walking dir + 8).
// Script resumption is handled by position polling in View1::tick().
- bool wasWalking = (_gameObject->_orientation < 9);
+ const bool wasWalking = (_gameObject->_orientation < OrientationStandingNorth);
if (wasWalking) {
- _gameObject->_orientation += 8;
- // Binary walkAlongPath (1008:1b8f): sets g_bMovementFinishedFlag=1
- // when orientation < 9 at final arrival. This triggers the scene script
- // to check getAreaAtPoint (case 0x27) for scene transitions.
+ _gameObject->_orientation = (ObjectOrientation)(_gameObject->_orientation + OrientationNorthWest);
g_engine->_movementFinishedFlag = true;
}
- if (_pickedUpObject != nullptr) {
- // Binary: walk completion does NOT set orientation to 0x11 here.
- // gameTick checks position==finalDest each frame, and when matched
- // (with verticalOk), THEN it sets orientation to 0x11.
- // The _pickupFrameCounter and _previousOrientation are already set
- // in startPickup(). View1::tick() handles the orientation trigger.
- return;
- }
return;
}
@@ -4187,38 +4172,38 @@ void Character::update() {
// Binary returns after setting direction (1-frame turn delay).
uint16 absDx = abs(pos.x - _targetPosition.x);
uint16 absDy = abs(pos.y - _targetPosition.y);
- uint8 dir = _gameObject->_orientation;
- if (dir > 8 && dir < 17)
- dir -= 8;
- if (dir > 16)
- dir = 1;
+ ObjectOrientation dir = _gameObject->_orientation;
+ if (dir >= OrientationStandingNorth && dir <= OrientationStandingNorthWest)
+ dir = (ObjectOrientation)(dir - OrientationNorthWest);
+ if (dir > OrientationStandingNorthWest)
+ dir = OrientationNorth;
// Cardinal directions (only if animation available for that direction)
if (_targetPosition.y < pos.y && absDx <= absDy &&
_gameObject->_blobs.size() > 0 && !_gameObject->_blobs[0].empty())
- dir = 1; // North
+ dir = OrientationNorth;
if (pos.x < _targetPosition.x && absDy <= absDx &&
_gameObject->_blobs.size() > 2 && !_gameObject->_blobs[2].empty())
- dir = 3; // East
+ dir = OrientationEast;
if (pos.y < _targetPosition.y && absDx <= absDy &&
_gameObject->_blobs.size() > 4 && !_gameObject->_blobs[4].empty())
- dir = 5; // South
+ dir = OrientationSouth;
if (_targetPosition.x < pos.x && absDy <= absDx &&
_gameObject->_blobs.size() > 6 && !_gameObject->_blobs[6].empty())
- dir = 7; // West
+ dir = OrientationWest;
// Diagonals: absDx/4 < absDy AND absDy/2 < absDx
if ((absDx >> 2) < absDy && (absDy >> 1) < absDx) {
if (_targetPosition.y < pos.y && pos.x < _targetPosition.x &&
_gameObject->_blobs.size() > 1 && !_gameObject->_blobs[1].empty())
- dir = 2; // NE
+ dir = OrientationNorthEast;
if (pos.x < _targetPosition.x && pos.y < _targetPosition.y &&
_gameObject->_blobs.size() > 3 && !_gameObject->_blobs[3].empty())
- dir = 4; // SE
+ dir = OrientationSouthEast;
if (pos.y < _targetPosition.y && _targetPosition.x < pos.x &&
_gameObject->_blobs.size() > 5 && !_gameObject->_blobs[5].empty())
- dir = 6; // SW
+ dir = OrientationSouthWest;
if (_targetPosition.x < pos.x && _targetPosition.y < pos.y &&
_gameObject->_blobs.size() > 7 && !_gameObject->_blobs[7].empty())
- dir = 8; // NW
+ dir = OrientationNorthWest;
}
_gameObject->_orientation = dir;
_stepDeltaX = absDx;
@@ -4363,10 +4348,6 @@ void View1::openOriginalSaveLoadPanel() {
g_engine->setCursorMode(Script::MouseMode::PanelCursor);
- // g_wActionBarButtonWidth = 0; g_wActionBarButtonHeight = 0
- uint16 maxW = 0;
- uint16 maxH = 0;
-
// g_wSaveConfirmArmed = 0; g_wLoadConfirmArmed = 0
_saveConfirmArmed = false;
_loadConfirmArmed = false;
@@ -4377,9 +4358,13 @@ void View1::openOriginalSaveLoadPanel() {
g_engine->getMusic()->stopMusic();
}
+ // g_wActionBarButtonWidth = 0; g_wActionBarButtonHeight = 0
+ uint16 maxW = 0;
+ uint16 maxH = 0;
+
// First loop: calculate max icon width/height from the 7 button images
- for (int i = 1; i <= 7; i++) {
- int imgIdx = kLookupTable[i] - 1; // convert to 0-based
+ for (int i = 1; i < ARRAYSIZE(kLookupTable); i++) {
+ const int imgIdx = kLookupTable[i] - 1; // convert to 0-based
if (imgIdx >= (int)g_engine->_imageResources.size())
continue;
AnimFrame &frame = g_engine->_imageResources[imgIdx];
@@ -4400,11 +4385,11 @@ void View1::openOriginalSaveLoadPanel() {
if (panelWidth < 0xD4)
panelWidth = 0xD4;
// g_wUiPanelHeight = g_wActionBarButtonHeight + 0x8A
- uint16 panelHeight = maxH + 0x8A;
+ const uint16 panelHeight = maxH + 0x8A;
// g_wUiPanelX = (g_wScreenWidth >> 1) - (g_wUiPanelWidth >> 1)
- int panelX = 160 - (panelWidth >> 1);
+ const int panelX = 160 - (panelWidth >> 1);
// g_wUiPanelY = (g_wScreenHeight >> 1) - (g_wUiPanelHeight >> 1)
- int panelY = 100 - (panelHeight >> 1);
+ const int panelY = 100 - (panelHeight >> 1);
// g_wActionBarButtonWidth = g_wActionBarButtonWidth + 6
_saveLoadButtonWidth = maxW + 6;
@@ -4416,7 +4401,7 @@ void View1::openOriginalSaveLoadPanel() {
// local_6 = ((g_wScreenWidth >> 1) - (g_wActionBarButtonWidth + 4) * 7 / 2) + 2
int buttonRowX = (160 - (int)((_saveLoadButtonWidth + 4) * 7) / 2) + 2;
// local_8 = (g_wUiPanelY + g_wUiPanelHeight - 4) - g_wActionBarButtonHeight
- int buttonRowY = (panelY + panelHeight - 4) - _saveLoadButtonHeight;
+ const int buttonRowY = (panelY + panelHeight - 4) - _saveLoadButtonHeight;
// Second loop: store button positions and draw them
for (int i = 1; i <= 7; i++) {
@@ -4429,12 +4414,12 @@ void View1::openOriginalSaveLoadPanel() {
// Load save slot names (ScummVM equivalent of binary's file reading loop)
// Convert UTF-8 descriptions to DOS CP850 since the glyph table uses DOS encoding
- for (int idx = 0; idx < 30; idx++) {
+ for (int idx = 0; idx < ARRAYSIZE(_saveSlotNames); idx++) {
SaveStateDescriptor desc = g_engine->getMetaEngine()->querySaveMetaInfos(
g_engine->getGameId().c_str(), idx);
if (desc.getSaveSlot() != -1) {
- Common::String utf8Name = desc.getDescription();
- Common::U32String u32Name = utf8Name.decode(Common::kUtf8);
+ const Common::String &utf8Name = desc.getDescription();
+ const Common::U32String &u32Name = utf8Name.decode(Common::kUtf8);
_saveSlotNames[idx] = Common::String(u32Name, Common::kDos850);
} else {
_saveSlotNames[idx] = "";
diff --git a/engines/macs2/view1.h b/engines/macs2/view1.h
index dfa10df1a5f..27f79a133ab 100644
--- a/engines/macs2/view1.h
+++ b/engines/macs2/view1.h
@@ -23,6 +23,7 @@
#define MACS2_VIEW1_H
#include "macs2/events.h"
+#include "macs2/gameobjects.h"
#include "macs2/macs2.h"
namespace Macs2 {
@@ -73,7 +74,7 @@ public:
bool _pickupItemTransferred = false;
bool _markedForDeletion = false;
- uint8 _previousOrientation = 0;
+ ObjectOrientation _previousOrientation = OrientationNone;
private:
// Handle when the character has moved into a non-walkable area, push them out if
Commit: 3f2d5d909df6ac4b490d52562441ad9cb7dc8dcb
https://github.com/scummvm/scummvm/commit/3f2d5d909df6ac4b490d52562441ad9cb7dc8dcb
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: cleanup + const
Changed paths:
engines/macs2/view1.cpp
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 38df8433eb1..7bcb3ff9c87 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -195,7 +195,7 @@ void buildFadedPalette(Graphics::Palette &colors, const Graphics::Palette &sourc
uint16 darkenPercent = (g_engine->_scenePaletteMode == 1) ? 0 : g_engine->_paletteDarkenPercent;
if (darkenPercent > 100)
darkenPercent = 100;
- uint16 brightnessFactor = 100 - darkenPercent;
+ const uint16 brightnessFactor = 100 - darkenPercent;
for (uint i = 0; i < Graphics::PALETTE_COUNT; ++i) {
byte r, g, b;
sourcePalette.get(i, r, g, b);
@@ -446,7 +446,7 @@ void View1::refreshProtagonistInventoryAfterLoad(uint16 actorIndex) {
}
bool found = false;
- for (GameObject *listed : validated) {
+ for (const GameObject *listed : validated) {
if (listed == obj) {
found = true;
break;
@@ -647,13 +647,12 @@ AnimFrame *View1::getInventoryIcon(GameObject *gameObject) {
Common::Array<uint8> &blob = gameObject->_blobs[index];
// Original calls getAnimFrameWidth(1, ...) with mode=1 to reset to frame 1
- uint16 offset = Macs2::BackgroundAnimationBlob::advanceAnimFrame(blob, true, 1);
+ const uint16 offset = Macs2::BackgroundAnimationBlob::advanceAnimFrame(blob, true, 1);
// offset points to per-frame: offsetX(2), offsetY(2), unknown(2), width(2), height(2), pixels
- offset += 6;
- result->_width = READ_LE_UINT16(&blob[offset]);
- result->_height = READ_LE_UINT16(&blob[offset + 2]);
+ result->_width = READ_LE_UINT16(&blob[offset + 6]);
+ result->_height = READ_LE_UINT16(&blob[offset + 8]);
result->_data.resize(result->_width * result->_height);
- memcpy(result->_data.data(), &blob[offset + 4], result->_width * result->_height);
+ memcpy(result->_data.data(), &blob[offset + 10], result->_width * result->_height);
// TODO: Think about proper memory management
return result;
}
@@ -4367,7 +4366,7 @@ void View1::openOriginalSaveLoadPanel() {
const int imgIdx = kLookupTable[i] - 1; // convert to 0-based
if (imgIdx >= (int)g_engine->_imageResources.size())
continue;
- AnimFrame &frame = g_engine->_imageResources[imgIdx];
+ const AnimFrame &frame = g_engine->_imageResources[imgIdx];
if (frame._data.empty() && frame._width == 0) {
// Binary: if no data, sets width/height fields to 0
continue;
@@ -4382,10 +4381,10 @@ void View1::openOriginalSaveLoadPanel() {
// g_wUiPanelWidth = (g_wActionBarButtonWidth + 10) * 7 + 4
uint16 panelWidth = (maxW + 10) * 7 + 4;
// if (g_wUiPanelWidth < 0xD4) g_wUiPanelWidth = 0xD4
- if (panelWidth < 0xD4)
- panelWidth = 0xD4;
+ if (panelWidth < 212)
+ panelWidth = 212;
// g_wUiPanelHeight = g_wActionBarButtonHeight + 0x8A
- const uint16 panelHeight = maxH + 0x8A;
+ const uint16 panelHeight = maxH + 138;
// g_wUiPanelX = (g_wScreenWidth >> 1) - (g_wUiPanelWidth >> 1)
const int panelX = 160 - (panelWidth >> 1);
// g_wUiPanelY = (g_wScreenHeight >> 1) - (g_wUiPanelHeight >> 1)
@@ -4404,7 +4403,7 @@ void View1::openOriginalSaveLoadPanel() {
const int buttonRowY = (panelY + panelHeight - 4) - _saveLoadButtonHeight;
// Second loop: store button positions and draw them
- for (int i = 1; i <= 7; i++) {
+ for (int i = 1; i <= ARRAYSIZE(_saveLoadButtonRects); i++) {
// Store position into button rect (binary stores into cursor array entry x/y fields)
_saveLoadButtonRects[i - 1] = Common::Rect(
buttonRowX, buttonRowY,
@@ -4415,7 +4414,7 @@ void View1::openOriginalSaveLoadPanel() {
// Load save slot names (ScummVM equivalent of binary's file reading loop)
// Convert UTF-8 descriptions to DOS CP850 since the glyph table uses DOS encoding
for (int idx = 0; idx < ARRAYSIZE(_saveSlotNames); idx++) {
- SaveStateDescriptor desc = g_engine->getMetaEngine()->querySaveMetaInfos(
+ const SaveStateDescriptor &desc = g_engine->getMetaEngine()->querySaveMetaInfos(
g_engine->getGameId().c_str(), idx);
if (desc.getSaveSlot() != -1) {
const Common::String &utf8Name = desc.getDescription();
@@ -4460,7 +4459,7 @@ void View1::drawOriginalSaveLoadPanel(Graphics::ManagedSurface &s) {
uint16 subMode = (uint16)_saveLoadSubMode;
- for (int i = 1; i <= 7; i++) {
+ for (int i = 1; i <= ARRAYSIZE(_saveLoadButtonRects); i++) {
int imgIdx = kLookupTable[i] - 1; // 0-based
Common::Point btnPos(_saveLoadButtonRects[i - 1].left, _saveLoadButtonRects[i - 1].top);
@@ -4514,24 +4513,24 @@ void View1::drawOriginalSaveLoadPanel(Graphics::ManagedSurface &s) {
// Slot loop: local_4 = 0..9
for (int slot = 0; slot <= 9; slot++) {
// drawPanelSlot(0xc, g_wUiPanelWidth - 8, g_wUiPanelY + 4 + slot * 0xc, g_wUiPanelX + 4)
- int slotX = panelX + 4;
- int slotY = panelY + 4 + slot * 0xc;
- int slotW = panelW - 8;
- int slotH = 0xc;
+ const int slotX = panelX + 4;
+ const int slotY = panelY + 4 + slot * 12;
+ const int slotW = panelW - 8;
+ const int slotH = 12;
drawNinePatchBorder(Common::Point(slotX, slotY), Common::Point(slotW, slotH), kBorderPressed, false, false, s);
// drawText at (g_wUiPanelX + 6, g_wUiPanelY + 6 + slot * 0xc)
- int idx = _saveLoadPageIndex * 10 + slot;
+ const int idx = _saveLoadPageIndex * 10 + slot;
Common::String label;
- if (idx < 30 && !_saveSlotNames[idx].empty()) {
+ if (idx < ARRAYSIZE(_saveSlotNames) && !_saveSlotNames[idx].empty()) {
label = _saveSlotNames[idx];
+ label.toUppercase();
} else {
label = "NONE";
}
const GlyphData *font = g_engine->numPanelGlyphs > 0 ? g_engine->_panelGlyphs : g_engine->_glyphs;
- uint16 fontCount = g_engine->numPanelGlyphs > 0 ? g_engine->numPanelGlyphs : g_engine->_numGlyphs;
- label.toUppercase();
- renderStringWithFont(panelX + 6, panelY + 6 + slot * 0xc, label, font, fontCount);
+ const uint16 fontCount = g_engine->numPanelGlyphs > 0 ? g_engine->numPanelGlyphs : g_engine->_numGlyphs;
+ renderStringWithFont(panelX + 6, panelY + 6 + slot * 12, label, font, fontCount);
}
}
@@ -4567,12 +4566,12 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
// Slot hit test for sub-mode 2 (save): editSaveSlotName
if (_saveLoadSubMode == SaveLoadSubMode::Save &&
(int)(panelX + 6) <= clickX &&
- clickX <= (int)(panelX + panelW - 0xc) &&
- (int)(panelY + 6 + slot * 0xc) <= clickY &&
- clickY <= (int)(panelY + slot * 0xc + 0x10)) {
+ clickX <= (int)(panelX + panelW - 12) &&
+ (int)(panelY + 6 + slot * 12) <= clickY &&
+ clickY <= (int)(panelY + slot * 12 + 16)) {
// editSaveSlotName(slot) - ScummVM: save to slot
- int idx = _saveLoadPageIndex * 10 + slot;
- Common::String name = Common::String::format("Save %d", idx + 1);
+ const int idx = _saveLoadPageIndex * 10 + slot;
+ const Common::String &name = Common::String::format("Save %d", idx + 1);
g_engine->saveGameState(idx, name);
_saveSlotNames[idx] = name;
redraw();
@@ -4582,11 +4581,11 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
// Slot hit test for sub-mode 1 (load): loadGameFromFile
if (_saveLoadSubMode == SaveLoadSubMode::Load &&
(int)(panelX + 6) <= clickX &&
- clickX <= (int)(panelX + panelW - 0xc) &&
- (int)(panelY + 6 + slot * 0xc) <= clickY &&
- clickY <= (int)(panelY + slot * 0xc + 0x10)) {
+ clickX <= (int)(panelX + panelW - 12) &&
+ (int)(panelY + 6 + slot * 12) <= clickY &&
+ clickY <= (int)(panelY + slot * 12 + 16)) {
int idx = _saveLoadPageIndex * 10 + slot;
- if (idx < 30 && !_saveSlotNames[idx].empty()) {
+ if (idx < ARRAYSIZE(_saveSlotNames) && !_saveSlotNames[idx].empty()) {
// Binary: loadGameFromFile then:
// g_wUiPanelState = 4; g_wClickedButtonIndex = 0;
// g_wPendingPanelRequest = 4; g_wSaveLoadSubMode = 0
@@ -4602,8 +4601,8 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
}
for (int i = 1; i < ARRAYSIZE(kLookupTable); i++) {
- int imgIdx = kLookupTable[i] - 1; // 0-based
- Common::Point btnPos(_saveLoadButtonRects[i - 1].left, _saveLoadButtonRects[i - 1].top);
+ const int imgIdx = kLookupTable[i] - 1; // 0-based
+ const Common::Point btnPos(_saveLoadButtonRects[i - 1].left, _saveLoadButtonRects[i - 1].top);
// Hit test: clickX > btnPos.x && clickY > btnPos.y &&
// clickX < btnPos.x + btnW && clickY < btnPos.y + btnH
@@ -4616,7 +4615,7 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
}
Script::ScriptExecutor *scriptExecutor = g_engine->_scriptExecutor;
- bool isHit = (btnPos.x < clickX && btnPos.y < clickY &&
+ const bool isHit = (btnPos.x < clickX && btnPos.y < clickY &&
clickX < btnPos.x + btnW && clickY < btnPos.y + btnH &&
hasData &&
(!_helpButtonDisabled || i > 2));
@@ -4657,7 +4656,7 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
// Binary: if music enabled AND sound active, play active music
if (scriptExecutor->_musicEnabled &&
scriptExecutor->_soundSystemActive) {
- uint16 slot = scriptExecutor->_activeMusicSlot;
+ const uint16 slot = scriptExecutor->_activeMusicSlot;
if (slot != 0 && !scriptExecutor->_musicSlots[slot - 1].empty() &&
g_engine->getMusic()->playSongData(scriptExecutor->_musicSlots[slot - 1])) {
// Original's adlibTickHandler resets g_bAdlibMasterVolume=0 (full volume).
@@ -4698,8 +4697,9 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
// Binary: if (bPageScroll && ++g_wMapPanelPageIndex == 3) g_wMapPanelPageIndex = 0
if (bPageScroll) {
_saveLoadPageIndex++;
- if (_saveLoadPageIndex == 3)
+ if (_saveLoadPageIndex == 3) {
_saveLoadPageIndex = 0;
+ }
}
// Reset for next click
Commit: 654a6a8e711eb59f6cc2366efb3f70192e64f989
https://github.com/scummvm/scummvm/commit/654a6a8e711eb59f6cc2366efb3f70192e64f989
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: cleanup + const
Changed paths:
engines/macs2/actionbar.cpp
engines/macs2/debugtools.cpp
engines/macs2/macs2.cpp
engines/macs2/macs2.h
engines/macs2/saveload.cpp
engines/macs2/scriptexecutor.cpp
engines/macs2/scriptexecutor.h
engines/macs2/view1.cpp
engines/macs2/view1.h
diff --git a/engines/macs2/actionbar.cpp b/engines/macs2/actionbar.cpp
index 311eff50830..f5975cfcc01 100644
--- a/engines/macs2/actionbar.cpp
+++ b/engines/macs2/actionbar.cpp
@@ -640,8 +640,8 @@ void ActionBar::drawNative(Graphics::ManagedSurface &s) {
(btn.buttonId == 4 && (mode == Script::MouseMode::Use ||
mode == Script::MouseMode::UseInventory)))) ||
(menuMode == MenuMode::Options &&
- ((btn.buttonId == 0x1e && g_engine->_optionsSubMode == OptionsSubMode::Save) ||
- (btn.buttonId == 0x1f && g_engine->_optionsSubMode == OptionsSubMode::Load)));
+ ((btn.buttonId == 30 && g_engine->_optionsSubMode == OptionsSubMode::Save) ||
+ (btn.buttonId == 31 && g_engine->_optionsSubMode == OptionsSubMode::Load)));
const bool pressed = (_pressedButtonId != 0 && btn.buttonId == _pressedButtonId);
const bool hovered = (_hoveredButtonId != 0 && btn.buttonId == _hoveredButtonId);
@@ -832,8 +832,9 @@ bool ActionBar::handleClickNative(const Common::Point &pos) {
const uint16 dlgY = g_engine->_hudTextLayout[6];
const uint16 pitch = g_engine->_hudTextLayout[4] ? g_engine->_hudTextLayout[4] : 10;
uint totalLines = 0;
- for (uint n : _view->_dialogueChoiceLineCounts)
+ for (uint n : _view->_dialogueChoiceLineCounts) {
totalLines += n;
+ }
if (totalLines > 0 && pos.x >= (int)dlgX &&
localY >= (int)dlgY && localY < (int)(dlgY + totalLines * pitch)) {
const int clickedLine = (localY - (int)dlgY) / (int)pitch;
@@ -851,8 +852,9 @@ bool ActionBar::handleClickNative(const Common::Point &pos) {
}
const HudButton *btn = findHudButtonAt(pos);
- if (btn == nullptr)
+ if (btn == nullptr) {
return true;
+ }
_pressedButtonId = btn->buttonId;
const uint16 id = btn->buttonId;
@@ -866,38 +868,38 @@ bool ActionBar::handleClickNative(const Common::Point &pos) {
g_engine->setCursorMode(Script::MouseMode::Talk);
} else if (id == 4) {
g_engine->setCursorMode(Script::MouseMode::Use);
- } else if (id == 0x33) {
+ } else if (id == 51) {
g_engine->_savedMenuCursorMode = g_engine->_scriptExecutor->_cursorMode;
g_engine->_menuMode = MenuMode::Options;
g_engine->_optionsSubMode = OptionsSubMode::None;
g_engine->_saveListScroll = 1;
refreshSaveSlotNames();
g_engine->setCursorMode(Script::MouseMode::PanelCursor);
- } else if (id == 0x32) {
+ } else if (id == 50) {
g_engine->_menuMode = MenuMode::Main;
g_engine->_optionsSubMode = OptionsSubMode::None;
g_engine->setCursorMode(g_engine->_savedMenuCursorMode);
- } else if (id == 0x1e) {
+ } else if (id == 30) {
g_engine->_optionsSubMode = OptionsSubMode::Save;
refreshSaveSlotNames();
- } else if (id == 0x1f) {
+ } else if (id == 31) {
g_engine->_optionsSubMode = OptionsSubMode::Load;
refreshSaveSlotNames();
- } else if (id == 0x20) {
+ } else if (id == 32) {
g_engine->softRestart();
return true;
- } else if (id == 0x21) {
+ } else if (id == 33) {
::GUI::MessageDialog quitDialog(_("Quit the game?"), _("Quit"), _("Cancel"));
if (quitDialog.runModal() == ::GUI::kMessageOK)
Engine::quitGame();
- } else if (id == 0x14 || id == 0x16) {
- const uint16 page = (id == 0x14) ? 1 : (g_engine->_inventCols * g_engine->_inventRows);
+ } else if (id == 20 || id == 22) {
+ const uint16 page = (id == 20) ? 1 : (g_engine->_inventCols * g_engine->_inventRows);
if (g_engine->_inventScroll > page)
g_engine->_inventScroll = (uint16)(g_engine->_inventScroll - page);
else
g_engine->_inventScroll = 1;
- } else if (id == 0x15 || id == 0x17) {
- const uint16 page = (id == 0x15) ? 1 : (g_engine->_inventCols * g_engine->_inventRows);
+ } else if (id == 21 || id == 23) {
+ const uint16 page = (id == 21) ? 1 : (g_engine->_inventCols * g_engine->_inventRows);
const uint16 maxStart = _view->_inventoryItems.empty() ? 1
: (uint16)((_view->_inventoryItems.size() > page) ? (_view->_inventoryItems.size() - page + 1) : 1);
uint16 next = (uint16)(g_engine->_inventScroll + page);
@@ -906,40 +908,40 @@ bool ActionBar::handleClickNative(const Common::Point &pos) {
if (next < 1)
next = 1;
g_engine->_inventScroll = next;
- } else if (id == 0x2a) {
+ } else if (id == 42) {
const uint16 page = g_engine->_hudTextLayout[3] ? g_engine->_hudTextLayout[3] : 9;
if (g_engine->_saveListScroll > page)
g_engine->_saveListScroll = (uint16)(g_engine->_saveListScroll - page);
else
g_engine->_saveListScroll = 1;
refreshSaveSlotNames();
- } else if (id == 0x2b) {
+ } else if (id == 43) {
const uint16 page = g_engine->_hudTextLayout[3] ? g_engine->_hudTextLayout[3] : 9;
g_engine->_saveListScroll = (uint16)(g_engine->_saveListScroll + page);
if (g_engine->_saveListScroll > 100)
g_engine->_saveListScroll = 100;
refreshSaveSlotNames();
- } else if (id == 0x42) {
+ } else if (id == 66) {
g_engine->_skipSpeed = 1;
- } else if (id == 0x43) {
+ } else if (id == 67) {
g_engine->_skipSpeed = 2;
- } else if (id == 0x44) {
+ } else if (id == 68) {
g_engine->_skipSpeed = 3;
- } else if (id == 0x45) {
+ } else if (id == 69) {
g_engine->_skipSpeed = 4;
- } else if (id == 0x3c) {
+ } else if (id == 60) {
g_engine->_scriptExecutor->_musicEnabled = true;
- } else if (id == 0x3d) {
+ } else if (id == 61) {
g_engine->_scriptExecutor->_musicEnabled = false;
g_engine->getMusic()->stopMusic();
- } else if (id == 0x3e) {
+ } else if (id == 62) {
g_engine->_scriptExecutor->_soundEnabled = true;
- } else if (id == 0x3f) {
+ } else if (id == 63) {
g_engine->_scriptExecutor->_soundEnabled = false;
g_engine->stopSample();
- } else if (id == 0x40) {
+ } else if (id == 64) {
g_engine->_scriptExecutor->_textEnabled = true;
- } else if (id == 0x41) {
+ } else if (id == 65) {
g_engine->_scriptExecutor->_textEnabled = false;
} else {
debugC(1, kDebugScript, "ActionBar: unhandled button id=0x%x menu=%u", id, (uint)menuMode);
diff --git a/engines/macs2/debugtools.cpp b/engines/macs2/debugtools.cpp
index 50bd900e62c..7180a4432f5 100644
--- a/engines/macs2/debugtools.cpp
+++ b/engines/macs2/debugtools.cpp
@@ -991,11 +991,6 @@ static void showCharactersWindow() {
c->_gameObject->_orientation = (ObjectOrientation)CLIP((uint16)orient, (uint16)OrientationNone, (uint16)OrientationPickup);
}
- int animIdx = (int)c->_animationIndex;
- if (ImGui::InputInt("Animation Index", &animIdx)) {
- c->_animationIndex = (uint8)CLIP(animIdx, 0, 255);
- }
-
ImGui::Text("Vertical Offset: %u", c->getVerticalOffset());
bool hasShading = c->_gameObject->_hasShading;
@@ -1025,9 +1020,6 @@ static void showCharactersWindow() {
if (ImGui::InputInt("Progress", &motionProg))
c->_motionProgress = (uint16)CLIP(motionProg, 0, 65535);
ImGui::Text("Pending VOffset Motion: %s", c->hasPendingVerticalMotion() ? "Y" : "N");
- bool shouldMirror = c->_shouldMirrorCurrentAnimation;
- if (ImGui::Checkbox("Mirror Animation", &shouldMirror))
- c->_shouldMirrorCurrentAnimation = shouldMirror;
ImGui::TreePop();
}
@@ -1141,7 +1133,6 @@ static void showCharactersWindow() {
df.writeString(Common::String::format(" \"character\": {\n"));
df.writeString(Common::String::format(" \"positionX\": %d,\n", c->getPosition().x));
df.writeString(Common::String::format(" \"positionY\": %d,\n", c->getPosition().y));
- df.writeString(Common::String::format(" \"shouldMirror\": %s,\n", c->_shouldMirrorCurrentAnimation ? "true" : "false"));
df.writeString(Common::String::format(" \"verticalOffset\": %u\n", c->getVerticalOffset()));
df.writeString(" }\n");
df.writeString("}\n");
diff --git a/engines/macs2/macs2.cpp b/engines/macs2/macs2.cpp
index 2ef1d5e5f7e..3f3bd88a5f4 100644
--- a/engines/macs2/macs2.cpp
+++ b/engines/macs2/macs2.cpp
@@ -86,7 +86,7 @@ void resetCharacterWalkPath(Character *character) {
if (character == nullptr || character->_gameObject == nullptr) {
return;
}
- const Common::Point &pos = character->_gameObject->_position;
+ const Common::Point &pos = character->getPosition();
character->_path.clear();
character->_currentPathIndex = 0;
character->_targetPosition = pos;
@@ -2320,8 +2320,8 @@ bool Macs2Engine::isPathWalkable(int16 y1, int16 x1, int16 y2, int16 x2) {
uint16 error = 0;
int16 curX = x2;
int16 curY = y2;
- uint16 absDx = (uint16)abs((int)(x2 - x1));
- uint16 absDy = (uint16)abs((int)(y2 - y1));
+ uint16 absDx = (uint16)ABS((int)(x2 - x1));
+ uint16 absDy = (uint16)ABS((int)(y2 - y1));
bool result = true;
do {
@@ -2364,8 +2364,8 @@ bool Macs2Engine::isPathWalkable(int16 y1, int16 x1, int16 y2, int16 x2) {
// integer Euclidean distance approximation.
// Iterates i from 0 until i^2 >= dx^2 + dy^2. Capped at 0x500.
int Macs2Engine::euclideanDistance(const Common::Point &a, const Common::Point &b) {
- int32 dx = abs((int)(b.x - a.x));
- int32 dy = abs((int)(b.y - a.y));
+ int32 dx = ABS((int)(b.x - a.x));
+ int32 dy = ABS((int)(b.y - a.y));
int32 distSq = dx * dx + dy * dy;
int i = 0;
while (i < 0x500 && (int32)i * i < distSq) {
@@ -2383,8 +2383,8 @@ int Macs2Engine::walkableDistance(int nodeA, int nodeB) {
return 0x500;
}
// Binary search for integer sqrt(dx^2 + dy^2), matching binary at 1008:1293
- int32 dx = abs((int)(b.x - a.x));
- int32 dy = abs((int)(b.y - a.y));
+ int32 dx = ABS((int)(b.x - a.x));
+ int32 dy = ABS((int)(b.y - a.y));
int32 distSq = dx * dx + dy * dy;
int result = 0x280;
int step = 0x280;
@@ -2417,11 +2417,11 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
if (!isPathWalkable(nodePos.y, nodePos.x, finalDest.y, finalDest.x)) {
result = 0x500;
} else {
- int32 dx = abs((int)(finalDest.x - nodePos.x));
- int32 dy = abs((int)(finalDest.y - nodePos.y));
+ int32 dx = ABS((int)(finalDest.x - nodePos.x));
+ int32 dy = ABS((int)(finalDest.y - nodePos.y));
int32 distSq = dx * dx + dy * dy;
- int dist = 0x280;
- int step = 0x280;
+ int dist = 640;
+ int step = 320;
do {
step = step >> 1;
if ((int32)dist * dist >= distSq) {
@@ -2443,7 +2443,7 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
if (adjCount > 0) {
for (int i = 0; i < adjCount; i++) {
- int adj = pt._adjacentPoints[i];
+ const int adj = pt._adjacentPoints[i];
if (adj == prevNode) {
continue;
}
@@ -2461,7 +2461,7 @@ int Macs2Engine::computeMinCostToReachable(int nodeIndex, int prevNode, uint16 a
}
// Recursive call
- int cost = computeMinCostToReachable(adj, nodeIndex, actorIndex, reachable, nodeCount, finalDest);
+ const int cost = computeMinCostToReachable(adj, nodeIndex, actorIndex, reachable, nodeCount, finalDest);
if (cost < bestCost) {
bestAdj = adj;
bestCost = cost;
diff --git a/engines/macs2/macs2.h b/engines/macs2/macs2.h
index f53713fe1d9..4ab35a80719 100644
--- a/engines/macs2/macs2.h
+++ b/engines/macs2/macs2.h
@@ -962,7 +962,6 @@ public:
};
extern Macs2Engine *g_engine;
-#define SHOULD_QUIT ::Macs2::g_engine->shouldQuit()
Common::String getObjectHotspotName(uint16 objectIndex);
/** Display name for a hit id: 0x400+object or 0x800+scene hotspot. */
Common::String lookupInteractionDisplayName(uint16 interactionId);
diff --git a/engines/macs2/saveload.cpp b/engines/macs2/saveload.cpp
index 1a5532df71f..cc065549df5 100644
--- a/engines/macs2/saveload.cpp
+++ b/engines/macs2/saveload.cpp
@@ -152,7 +152,7 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
s.syncAsUint16LE(activeInventoryItemId);
if (s.isLoading()) {
if (activeInventoryItemId >= 0x401 && activeInventoryItemId <= 0x600) {
- uint16 idx = activeInventoryItemId - 0x400;
+ const uint16 idx = activeInventoryItemId - 0x400;
if (idx <= GameObjects::instance()._objects.size()) {
GameObject *obj = GameObjects::instance()._objects[idx - 1];
view1->_activeInventoryItem = obj;
@@ -259,9 +259,7 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
}
}
- // --- Scene data: pathfinding overrides [+0x528D]: 200 bytes ---
- // 40 entries x 5 bytes each (1 byte active + 2 bytes value + 2 bytes remap)
- // indexed by pathfinding value 0xC8..0xEF
+ // Scene data: pathfinding overrides [+0x528D]: 200 bytes ---
if (s.isLoading())
_pathfindingOverrides.clear();
for (int i = 0; i < ARRAYSIZE(_areaOverrides); i++) {
@@ -294,7 +292,7 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
}
}
- // --- Scene data: hotspot overrides
+ // Scene data: hotspot overrides
if (s.isLoading()) {
_hotspotOverrides.clear();
_hotspotOverrides.resize(17, 0xFFFF);
@@ -316,20 +314,7 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
s.syncAsUint32LE(_sceneTimerParams[i]);
}
- // --- Animation blob sequence positions (one uint16 per background anim) ---
- //
- // Binary save (1008:6859): for each bg anim (1..count) writes
- // getAnimBlobSequencePos(blob) = blob[+2] = the blob header's current sequence
- // position word.
- // Binary load (1008:747e): reads the value V, then calls
- // advanceAnimFrame(save=1, mode=V+100, blob), i.e. jumps the blob to
- // sequence position V (mode 100+N). This both restores the saved position
- // AND re-parses the sequence so the blob header is fully consistent -
- // exactly what scriptChangeAnimation does.
- //
- // The count is iStack_199 = sceneData+0x50F5, which equals
- // _backgroundAnimationsBlobs.size() after changeScene() above.
- uint16 numSpecialAnims = (uint16)_backgroundAnimationsBlobs.size();
+ const uint16 numSpecialAnims = (uint16)_backgroundAnimationsBlobs.size();
for (uint16 i = 0; i < numSpecialAnims; i++) {
BackgroundAnimationBlob &blob = _backgroundAnimationsBlobs[i];
uint16 seqPos = 0;
@@ -347,8 +332,9 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
// command byte). Force it back to exactly V so the field round-trips
// losslessly and byte-matches what the original wrote (the original
// stores its live running position, not a re-derived one).
- if (blob._blob.size() >= 4)
+ if (blob._blob.size() >= 4) {
WRITE_LE_UINT16(&blob._blob[2], seqPos);
+ }
}
}
}
@@ -369,7 +355,7 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
s.syncAsUint16LE(_scriptExecutor->_activeMusicSlot);
// --- Music slot buffers (slots 1-2): size (2 bytes) + data each ---
- for (int slot = 0; slot < 2; slot++) {
+ for (int slot = 0; slot < ARRAYSIZE(_scriptExecutor->_musicSlots); slot++) {
uint16 musicSize = 0;
if (s.isSaving())
musicSize = (uint16)_scriptExecutor->_musicSlots[slot].size();
@@ -447,8 +433,9 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
// Find the Character for this object (exists after changeScene on load too)
Character *chr = nullptr;
for (uint ci = 0; ci < view1->_characters.size(); ci++) {
- if (view1->_characters[ci] && view1->_characters[ci]->_gameObject == obj) {
- chr = view1->_characters[ci];
+ Character *c = view1->_characters[ci];
+ if (c && c->_gameObject == obj) {
+ chr = c;
break;
}
}
diff --git a/engines/macs2/scriptexecutor.cpp b/engines/macs2/scriptexecutor.cpp
index 7758d7331be..3f77b002e71 100644
--- a/engines/macs2/scriptexecutor.cpp
+++ b/engines/macs2/scriptexecutor.cpp
@@ -101,7 +101,6 @@ Common::String ScriptExecutor::identifyHelperOpcode(uint8 opcode, uint16 value)
inline void ScriptExecutor::scriptSkipBlock() {
_lastOpcodeTriggeredSkip = true;
- _isSkipping = true;
if (_expectedEndLocation != _stream->pos()) {
warning("Macs2::ScriptExecutor::scriptSkipBlock resyncing stream from %u to %u",
(uint32)_expectedEndLocation, (uint32)_stream->pos());
@@ -137,11 +136,9 @@ inline void ScriptExecutor::scriptSkipBlock() {
// Fix up the expected location after skipping
_expectedEndLocation = _stream->pos();
- _isSkipping = false;
}
void ScriptExecutor::scriptSkipAlternate() {
- _isSkipping = true;
if (_expectedEndLocation != _stream->pos()) {
warning("Macs2::ScriptExecutor::scriptSkipAlternate resyncing stream from %u to %u",
(uint32)_expectedEndLocation, (uint32)_stream->pos());
@@ -174,7 +171,6 @@ void ScriptExecutor::scriptSkipAlternate() {
// Fix up the expected location after skipping
_expectedEndLocation = _stream->pos();
- _isSkipping = false;
}
bool ScriptExecutor::skipToEndOfSkippableSection() {
@@ -1980,7 +1976,6 @@ void Script::ScriptExecutor::restoreOpenInventoryScriptContext() {
_scriptClickY = _savedScriptClickY;
_scriptClickResult = _savedScriptClickResult;
_state = ExecutorState::Executing;
- _isRunningScript = true;
}
OpcodeResult Script::ScriptExecutor::scriptSetYOffset() {
@@ -4196,7 +4191,6 @@ const uint ScriptExecutor::kV2OpcodeTableSize = ARRAYSIZE(ScriptExecutor::kV2Opc
OpcodeResult Script::ScriptExecutor::executeOpcodes() {
debugC(kDebugScript, "----- Scripting function entered - scene: %.2x 1014: %.2x 1012: %.2x", Scenes::instance()._currentSceneIndex, _isSceneInitRun, _repeatRunFlag);
- _isRunningScript = true;
// Confirmed: no interrupt mechanism exists. Wait states (frameWait, walkTarget,
// pcmSound, musicControl, adlibReady) are resolved by gameTick externally.
@@ -4270,7 +4264,6 @@ OpcodeResult Script::ScriptExecutor::executeOpcodes() {
if (opcodeResult == OpcodeResult::FinishScript)
break;
}
- _isRunningScript = false;
if (hasScriptError())
recordScriptErrorPosition();
debugC(kDebugScript, "----- Scripting function left");
diff --git a/engines/macs2/scriptexecutor.h b/engines/macs2/scriptexecutor.h
index dd42d067742..65a9921d90b 100644
--- a/engines/macs2/scriptexecutor.h
+++ b/engines/macs2/scriptexecutor.h
@@ -509,10 +509,6 @@ public:
uint16 _pickupActorObjectID = 0;
uint16 _pickupTargetObjectID = 0;
- bool _isRunningScript = false;
- // Mutex indicating if the A3D2 function is active
- bool _isSkipping = false;
-
Macs2::Macs2Engine *_engine;
// Button 8 skip from handleInput (1008:e8bf)
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 7bcb3ff9c87..e43914fd40f 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -58,32 +58,35 @@ Common::String joinDebugStrings(const Common::StringArray &strings) {
}
void logRenderedText(const char *kind, int x, int y, const Common::String &text) {
- Common::U32String u32text(text.c_str(), Common::kDos850);
- Common::String utf8text(u32text);
- g_engine->_textLog.push_back(Common::String::format("%s text at (%d,%d): ", kind, x, y) + utf8text);
+ const Common::U32String u32text(text.c_str(), Common::kDos850);
+ const Common::String utf8text(u32text);
+ g_engine->_textLog.emplace_back(Common::String::format("%s text at (%d,%d): %s", kind, x, y, utf8text.c_str()));
}
void resetObjectDrawBounds(GameObject *obj) {
- if (obj != nullptr)
+ if (obj != nullptr) {
obj->resetDrawBounds();
+ }
}
void setPixelClipped(Graphics::ManagedSurface &s, int x, int y, byte color) {
- if (x < 0 || y < 0 || x >= s.w || y >= s.h)
+ if (x < 0 || y < 0 || x >= s.w || y >= s.h) {
return;
+ }
s.setPixel(x, y, color);
}
void drawLine(Graphics::ManagedSurface &s, int x0, int y0, int x1, int y1, byte color) {
- int dx = ABS(x1 - x0);
- int sx = x0 < x1 ? 1 : -1;
- int dy = -ABS(y1 - y0);
- int sy = y0 < y1 ? 1 : -1;
+ const int dx = ABS(x1 - x0);
+ const int sx = x0 < x1 ? 1 : -1;
+ const int dy = -ABS(y1 - y0);
+ const int sy = y0 < y1 ? 1 : -1;
int err = dx + dy;
for (;;) {
setPixelClipped(s, x0, y0, color);
- if (x0 == x1 && y0 == y1)
+ if (x0 == x1 && y0 == y1) {
break;
+ }
const int e2 = 2 * err;
if (e2 >= dy) {
err += dy;
@@ -116,7 +119,6 @@ void drawAmigaUiPanel(const Common::Point &pos, const Common::Point &size, Graph
}
// background
- // TODO: the pattern is wrong
const byte a = remapAmigaCopperIndexToStableUi(21);
const byte bCol = remapAmigaCopperIndexToStableUi(22);
byte ehbA = a;
@@ -339,7 +341,7 @@ void View1::setViewPaletteSafely(const Graphics::Palette &colors) {
}
void View1::restoreUiPaletteEntries() {
- g_system->getPaletteManager()->setPalette(g_engine->_pal.data() + 16 * 3, 0xF0, 16);
+ g_system->getPaletteManager()->setPalette(g_engine->_pal.data() + 16 * 3, 240, 16);
}
void View1::openInventory(GameObject *newInventorySource) {
@@ -465,16 +467,16 @@ void View1::refreshProtagonistInventoryAfterLoad(uint16 actorIndex) {
}
bool View1::isInventorySourceProtagonist() const {
- return _inventorySource &&
- _inventorySource->_index == Scenes::instance()._currentActorIndex;
+ return _inventorySource && _inventorySource->_index == Scenes::instance()._currentActorIndex;
}
void View1::transferInventoryItem(GameObject *item, GameObject *targetContainer) {
const int index = findInventoryItem(item);
_inventoryItems.remove_at(index);
item->_sceneIndex = targetContainer->_index + 0x400;
- if (hasPersistentActionBar() && _actionBar)
+ if (hasPersistentActionBar() && _actionBar) {
_actionBar->syncInventory();
+ }
}
int View1::findInventoryItem(const GameObject *item) {
@@ -778,7 +780,7 @@ void View1::renderString(uint16 x, uint16 y, const Common::String &s) {
}
}
-void View1::renderString(const Common::Point pos, const Common::String &s) {
+void View1::renderString(const Common::Point &pos, const Common::String &s) {
renderString(pos.x, pos.y, s);
}
@@ -1832,8 +1834,8 @@ void View1::walkToScreenPosition(const Common::Point &pos) {
protagonist->_targetPosition = target;
}
}
- protagonist->_stepDeltaX = abs(protagonist->_targetPosition.x - charPos.x);
- protagonist->_stepDeltaY = abs(protagonist->_targetPosition.y - charPos.y);
+ protagonist->_stepDeltaX = (int16)ABS(protagonist->_targetPosition.x - charPos.x);
+ protagonist->_stepDeltaY = (int16)ABS(protagonist->_targetPosition.y - charPos.y);
protagonist->_stepError = 0;
protagonist->_stepDirectionSet = false;
g_engine->_scriptExecutor->saveWalkRuntime(protagonist, protagonist->_gameObject);
@@ -3817,7 +3819,6 @@ bool Character::calculatePath(Common::Point target) {
}
bool Character::canNodeConnectSourceToTarget(uint16 nodeIndex, const Common::Point &charPos, const Common::Point &target, const bool *reachable, int nodeCount) {
- // Binary findShortestPath (1008:14d4).
// Checks if node can connect source (charPos) to target:
// 1. Node must be able to see the target
// 2. Flood-fill connected component from node
@@ -3872,9 +3873,8 @@ uint16 Character::getVerticalOffset() const {
}
if (_gameObject->_verticalOffsetScale != 0) {
- // drawAllCharacters @ 1008:9549: scalingFactor * verticalOffsetScale / 100
const int16 charY = getPosition().y;
- int32 depthOffset = ((int32)charY - (int32)g_engine->_walkDepthThresholdY) *
+ const int32 depthOffset = ((int32)charY - (int32)g_engine->_walkDepthThresholdY) *
(int32)g_engine->_walkDepthScaleFactor / 100;
const uint16 scalingFactor = (uint16)((int32)g_engine->_walkBaseSpeedPct + depthOffset);
result = (scalingFactor * _gameObject->_verticalOffsetScale) / 100;
@@ -3884,9 +3884,6 @@ uint16 Character::getVerticalOffset() const {
}
bool Character::walkAlongPath() {
- // Binary walkAlongPath (1008:1b8f) path node advancement:
- // When arrived at current waypoint, snap position to node coords, then advance.
- // Binary: if (pathNodeIndex != 0) posX/Y = nodeCoords[pathNodes[pathNodeIndex]]
if (_currentPathIndex >= 0 && _currentPathIndex < (int16)_path.size()) {
const uint16 snapIdx = _path[_currentPathIndex];
const Common::Point &snapPos = g_engine->_pathfindingPoints[snapIdx - 1]._position;
@@ -3896,8 +3893,8 @@ bool Character::walkAlongPath() {
if (_currentPathIndex >= (int16)_path.size()) {
// Past end of path - walk to final destination, then stop
_targetPosition = _pathFinalDestination;
- _stepDeltaX = abs(_targetPosition.x - _gameObject->_position.x);
- _stepDeltaY = abs(_targetPosition.y - _gameObject->_position.y);
+ _stepDeltaX = (int16)ABS(_targetPosition.x - _gameObject->_position.x);
+ _stepDeltaY = (int16)ABS(_targetPosition.y - _gameObject->_position.y);
_stepError = 0;
_stepDirectionSet = false;
return false; // No more path segments after this
@@ -3905,40 +3902,31 @@ bool Character::walkAlongPath() {
const uint16 nodeIdx = _path[_currentPathIndex];
const Common::Point &nodePos = g_engine->_pathfindingPoints[nodeIdx - 1]._position;
_targetPosition = nodePos;
- _stepDeltaX = abs(_targetPosition.x - _gameObject->_position.x);
- _stepDeltaY = abs(_targetPosition.y - _gameObject->_position.y);
+ _stepDeltaX = (int16)ABS(_targetPosition.x - _gameObject->_position.x);
+ _stepDeltaY = (int16)ABS(_targetPosition.y - _gameObject->_position.y);
_stepError = 0;
_stepDirectionSet = false;
return true;
}
bool Character::isAnimationMirrored() const {
- return is_in_list<uint16, 6, 7, 8, 14, 15, 16>(_gameObject->_orientation);
-}
-
-uint8 Character::getMirroredAnimation(uint8 original) const {
- switch (original) {
- case 6:
- return 4;
- case 7:
- return 3;
- case 8:
- return 2;
- case 14:
- return 12;
- case 15:
- return 11;
- case 16:
- return 10;
+ switch (_gameObject->_orientation) {
+ case OrientationSouthWest:
+ case OrientationWest:
+ case OrientationNorthWest:
+ case OrientationStandingSouthWest:
+ case OrientationStandingWest:
+ case OrientationStandingNorthWest:
+ return true;
+ default:
+ break;
}
- return original;
+ return false;
}
-bool Character::fillCurrentAnimationFrame(uint16 advanceMode, Macs2::AnimFrame &out) {
+bool Character::fillCurrentAnimationFrame(uint16 advanceMode, Macs2::AnimFrame &out) const {
const uint16 animSlot = g_engine->resolveAnimSlotIndex(_gameObject);
- _shouldMirrorCurrentAnimation = false;
-
Common::Array<uint8> *blobPtr = _gameObject->getAnimSlotBlob(animSlot);
if (blobPtr == nullptr || blobPtr->empty()) {
return false;
@@ -3993,44 +3981,41 @@ Macs2::AnimFrame *Character::getCurrentPortrait(bool onRightSide, uint16 frameIn
return result;
}
-// NOTE: The original game (walkAlongPath at 1008:1b8f) does NOT use time-based
-// lerping. Instead it uses pixel-by-pixel Bresenham stepping each frame, with
-// speed scaled by depth (perspective). The walk click flow is:
-// 1. snapToWalkablePosition() adjusts target to nearest walkable pixel
-// 2. isPathWalkable() checks if direct line is clear
-// 3. If not: calculatePath() does A* pathfinding through waypoints
-// 4. walkAlongPath() steps 1 pixel per axis per frame, scaled by depth
-// The current lerp-based approach is a simplification that should eventually
-// be replaced with the original pixel-stepping for accurate movement speed.
+// Leftover lerp-era entry point. Duration and ignoreObstacles are unused.
+// Binary walkAlongPath (1008:1b8f) has no time lerp: Phase 0 sets 8-way
+// orientation and returns (1-frame delay); Phase 1 loops stepCounter 1..walkSpeed
+// with one-pixel Bresenham (error >= deltaX -> step Y else step X).
+// walkSpeed = animSpeed * (scene[0x5201] + depth) / 100, min 1;
+// depth = (posY - scene[0x51FD]) * scene[0x51FF] / 100.
+// Character::update() implements that. C++ walkAlongPath() is only the inlined
+// waypoint advance. Path setup is walkToScreenPosition / scriptWalkToPosition.
void Character::startLerpTo(const Common::Point &target, uint32 duration, bool ignoreObstacles) {
_startPosition = getPosition();
_targetPosition = target;
_startTime = g_events->currentMillis;
_duration = duration;
- _lerpIgnoresObstacles = ignoreObstacles;
// Reset Bresenham state - direction will be calculated on first Update()
_stepDirectionSet = false;
- _stepDeltaX = abs(_targetPosition.x - _startPosition.x);
- _stepDeltaY = abs(_targetPosition.y - _startPosition.y);
+ _stepDeltaX = (int16)ABS(_targetPosition.x - _startPosition.x);
+ _stepDeltaY = (int16)ABS(_targetPosition.y - _startPosition.y);
_stepError = 0;
}
void Character::startPickup(Macs2::GameObject *object) {
_pickedUpObject = object;
- // Binary (1008:c475): walk target is the pickup object's effective position.
_pathFinalDestination = getObjectEffectivePosition(object);
_pickupFrameCounter = 0;
_pickupItemTransferred = false;
- Common::Point current = getPosition();
- int16 destX = _pathFinalDestination.x;
- int16 destY = _pathFinalDestination.y;
+ const Common::Point ¤t = getPosition();
+ const int16 destX = _pathFinalDestination.x;
+ const int16 destY = _pathFinalDestination.y;
_currentPathIndex = 0;
_path.clear();
- bool directPath = g_engine->isPathWalkable(destY, destX, current.y, current.x);
+ const bool directPath = g_engine->isPathWalkable(destY, destX, current.y, current.x);
if (!directPath && Macs2Engine::isWalkabilityWalkable(g_engine->getWalkabilityAt(destY, destX))) {
calculatePath(Common::Point(destX, destY));
}
@@ -4039,8 +4024,8 @@ void Character::startPickup(Macs2::GameObject *object) {
_targetPosition = _pathFinalDestination;
}
- _stepDeltaX = abs(_targetPosition.x - current.x);
- _stepDeltaY = abs(_targetPosition.y - current.y);
+ _stepDeltaX = (int16)ABS(_targetPosition.x - current.x);
+ _stepDeltaY = (int16)ABS(_targetPosition.y - current.y);
_stepError = 0;
_stepDirectionSet = false;
}
@@ -4056,7 +4041,8 @@ bool Character::shouldStepVerticalMotion() const {
}
void Character::update() {
- if (_gameObject->_orientation == 0x11) {
+ Script::ScriptExecutor *script = g_engine->_scriptExecutor;
+ if (_gameObject->_orientation == OrientationPickup) {
if (_pickedUpObject != nullptr) {
View1 *currentView = (View1 *)g_engine->findView("View1");
@@ -4067,17 +4053,17 @@ void Character::update() {
if (_pickupFrameCounter == _gameObject->_pickupFrameEnd) {
_gameObject->_orientation = _previousOrientation;
- if (g_engine->_scriptExecutor->_pickupInProgress) {
- g_engine->_scriptExecutor->_pickupInProgress = false;
- g_engine->_scriptExecutor->_pickupActorObjectID = 0;
- g_engine->_scriptExecutor->_pickupTargetObjectID = 0;
- g_engine->setCursorMode(g_engine->_scriptExecutor->_cursorModeBeforeWait);
+ if (script->_pickupInProgress) {
+ script->_pickupInProgress = false;
+ script->_pickupActorObjectID = 0;
+ script->_pickupTargetObjectID = 0;
+ g_engine->setCursorMode(script->_cursorModeBeforeWait);
currentView->updateCursor();
}
- g_engine->_scriptExecutor->_walkTargetObjectIndex = 0;
+ script->_walkTargetObjectIndex = 0;
_pickedUpObject = nullptr;
- g_engine->_scriptExecutor->_interactedObjectID = 0x0000;
- g_engine->_scriptExecutor->_interactedInventoryItemId = 0x0000;
+ script->_interactedObjectID = 0x0000;
+ script->_interactedInventoryItemId = 0x0000;
g_engine->_movementFinishedFlag = true;
return;
}
@@ -4087,18 +4073,11 @@ void Character::update() {
return;
}
- // Binary walkAlongPath (1008:1b8f): runs unconditionally every frame.
- // No _isLerping gate exists in the binary.
Common::Point pos = getPosition();
- // Walk speed formula from walkAlongPath (1008:1b8f):
- // depth = (posY - scene[0x51FD]) * scene[0x51FF] / 100
- // walkSpeed = animSpeed * (scene[0x5201] + depth) / 100
- int32 depthOffset = ((int32)pos.y - (int32)g_engine->_walkDepthThresholdY) *
- (int32)g_engine->_walkDepthScaleFactor / 100;
- // Per-animation speed from blob data (runtime+orientation*16+0x30)
- // Walk speed from binary walkAlongPath (1008:1b8f):
- // pwVar7[orientation * 8 + 0x18] = word at runtime + orientation*16 + 0x30
- // = AnimSlot.wAnimSpeed (slot+0x0C). Stored in _blobWalkSpeeds.
+ const int32 depthOffset = ((int32)pos.y - (int32)g_engine->_walkDepthThresholdY) *
+ (int32)g_engine->_walkDepthScaleFactor / 100;
+ // Per-animation speed from blob data
+ // Walk speed from binary walkAlongPath
uint16 animSpeed = 2; // default fallback
ObjectOrientation orient = _gameObject->_orientation;
if (orient >= OrientationNorth && orient <= g_engine->maxAnimSlots() && (uint)(orient - 1) < _gameObject->_blobWalkSpeeds.size()) {
@@ -4112,16 +4091,13 @@ void Character::update() {
walkSpeed = 1;
}
- // Proximity arrival check from walkAlongPath (1008:1b8f):
- // Binary checks if character is within walkSpeed pixels of target in both axes.
- bool arrived = (abs(pos.x - _targetPosition.x) <= walkSpeed) &&
- (abs(pos.y - _targetPosition.y) <= walkSpeed);
- // Binary: arrival also requires vertical offset interpolation to be complete
+ // Proximity arrival check from walkAlongPath
+ bool arrived = (ABS(pos.x - _targetPosition.x) <= walkSpeed) &&
+ (ABS(pos.y - _targetPosition.y) <= walkSpeed);
if (arrived && hasPendingVerticalMotion()) {
arrived = false;
}
if (arrived) {
- // Binary (22cd): check if target == finalDest (at final destination)
const bool atFinalDest = (_targetPosition.x == _pathFinalDestination.x &&
_targetPosition.y == _pathFinalDestination.y);
@@ -4134,9 +4110,8 @@ void Character::update() {
// Final destination arrival (or direct walk arrival)
if (_gameObject->_snapToTarget) {
- pos = _targetPosition;
- setPosition(pos);
- _pathFinalDestination = pos;
+ setPosition(_targetPosition);
+ _pathFinalDestination = _targetPosition;
} else {
_targetPosition = pos;
_pathFinalDestination = pos;
@@ -4169,8 +4144,8 @@ void Character::update() {
_stepDirectionSet = true;
// Phase 0 from walkAlongPath (1008:1b8f): direction calculation.
// Binary returns after setting direction (1-frame turn delay).
- uint16 absDx = abs(pos.x - _targetPosition.x);
- uint16 absDy = abs(pos.y - _targetPosition.y);
+ const uint16 absDx = (uint16)ABS(pos.x - _targetPosition.x);
+ const uint16 absDy = (uint16)ABS(pos.y - _targetPosition.y);
ObjectOrientation dir = _gameObject->_orientation;
if (dir >= OrientationStandingNorth && dir <= OrientationStandingNorthWest)
dir = (ObjectOrientation)(dir - OrientationNorthWest);
@@ -4205,8 +4180,8 @@ void Character::update() {
dir = OrientationNorthWest;
}
_gameObject->_orientation = dir;
- _stepDeltaX = absDx;
- _stepDeltaY = absDy;
+ _stepDeltaX = (int16)absDx;
+ _stepDeltaY = (int16)absDy;
_stepError = 0;
// 1-frame turn delay: return after setting direction (binary Phase 0)
return;
@@ -4252,7 +4227,7 @@ void Character::update() {
}
// Walkability check - binary uses getWalkabilityAt(posY, posX) >= 0xC8
if (!isWalkable(pos)) {
- const uint16 tileArea = g_engine->_scriptExecutor->getAreaAtPoint(pos.x, pos.y);
+ const uint16 tileArea = script->getAreaAtPoint(pos.x, pos.y);
if (tileArea >= 210 && tileArea <= 215) {
debugC(kDebugPath,
"walk blocked on plate area %u at (%d,%d) walk=%u int16=%d target=(%d,%d)",
@@ -4310,9 +4285,8 @@ void Character::update() {
// Binary: loop continues unconditionally until stepCounter == walkSpeed
}
- // Binary (2280): if pixelsMoved != walkSpeed -> revert and cancel
if (pixelsMoved != walkSpeed) {
- const uint16 tileArea = g_engine->_scriptExecutor->getAreaAtPoint(pos.x, pos.y);
+ const uint16 tileArea = script->getAreaAtPoint(pos.x, pos.y);
if (tileArea >= 210 && tileArea <= 215) {
debugC(kDebugPath,
"walk cancelled pixelsMoved=%d walkSpeed=%d at (%d,%d) area=%u walk=%u finalDest=(%d,%d)",
@@ -4340,18 +4314,15 @@ void Button::render(Graphics::ManagedSurface &s) {
}
void View1::openOriginalSaveLoadPanel() {
- // Exact translation of initSaveLoadPanel (1008:6184)
- _pendingPanelRequest = kPanelRequestNone; // Binary: g_wPendingPanelRequest = 0
- _uiPanelState = kUiPanelSaveLoad; // Binary: g_wUiPanelState = 4
- _uiBackgroundRestorePending = true; // Binary: g_wUiBackgroundRestorePending = 1
+ _pendingPanelRequest = kPanelRequestNone;
+ _uiPanelState = kUiPanelSaveLoad;
+ _uiBackgroundRestorePending = true;
g_engine->setCursorMode(Script::MouseMode::PanelCursor);
- // g_wSaveConfirmArmed = 0; g_wLoadConfirmArmed = 0
_saveConfirmArmed = false;
_loadConfirmArmed = false;
- // if (g_wMusicEnabled && sceneData[g_wActiveMusicSlot] != 0) adlibStopMusic()
if (g_engine->_scriptExecutor->_musicEnabled &&
g_engine->_scriptExecutor->_activeMusicSlot != 0) {
g_engine->getMusic()->stopMusic();
@@ -4364,25 +4335,28 @@ void View1::openOriginalSaveLoadPanel() {
// First loop: calculate max icon width/height from the 7 button images
for (int i = 1; i < ARRAYSIZE(kLookupTable); i++) {
const int imgIdx = kLookupTable[i] - 1; // convert to 0-based
- if (imgIdx >= (int)g_engine->_imageResources.size())
+ if (imgIdx >= (int)g_engine->_imageResources.size()) {
continue;
+ }
const AnimFrame &frame = g_engine->_imageResources[imgIdx];
if (frame._data.empty() && frame._width == 0) {
// Binary: if no data, sets width/height fields to 0
continue;
}
- // Binary: getFrameWidth/getFrameHeight then updates max
- if (frame._width > maxW)
+ if (frame._width > maxW) {
maxW = frame._width;
- if (frame._height > maxH)
+ }
+ if (frame._height > maxH) {
maxH = frame._height;
+ }
}
// g_wUiPanelWidth = (g_wActionBarButtonWidth + 10) * 7 + 4
uint16 panelWidth = (maxW + 10) * 7 + 4;
// if (g_wUiPanelWidth < 0xD4) g_wUiPanelWidth = 0xD4
- if (panelWidth < 212)
+ if (panelWidth < 212) {
panelWidth = 212;
+ }
// g_wUiPanelHeight = g_wActionBarButtonHeight + 0x8A
const uint16 panelHeight = maxH + 138;
// g_wUiPanelX = (g_wScreenWidth >> 1) - (g_wUiPanelWidth >> 1)
@@ -4460,8 +4434,8 @@ void View1::drawOriginalSaveLoadPanel(Graphics::ManagedSurface &s) {
uint16 subMode = (uint16)_saveLoadSubMode;
for (int i = 1; i <= ARRAYSIZE(_saveLoadButtonRects); i++) {
- int imgIdx = kLookupTable[i] - 1; // 0-based
- Common::Point btnPos(_saveLoadButtonRects[i - 1].left, _saveLoadButtonRects[i - 1].top);
+ const int imgIdx = kLookupTable[i] - 1; // 0-based
+ const Common::Point btnPos(_saveLoadButtonRects[i - 1].left, _saveLoadButtonRects[i - 1].top);
// Binary: if (local_4 < 0 || local_4 != g_wSaveLoadSubMode) -> normal border
// else -> pressed border
@@ -4472,18 +4446,18 @@ void View1::drawOriginalSaveLoadPanel(Graphics::ManagedSurface &s) {
if (imgIdx >= (int)g_engine->_imageResources.size()) {
continue;
}
- AnimFrame &frame = g_engine->_imageResources[imgIdx];
+ const AnimFrame &frame = g_engine->_imageResources[imgIdx];
if (frame._data.empty() || frame._width == 0) {
continue;
}
// Determine which icon to draw
- AnimFrame *iconFrame = &frame;
+ const AnimFrame *iconFrame = &frame;
// Button 3 with sound off: use alternate icon at index 0x1B0/0x10 = 27
if (i == 3 && !g_engine->_scriptExecutor->_soundSystemActive) {
if (kAltMusicIconIdx < (int)g_engine->_imageResources.size()) {
- AnimFrame &altFrame = g_engine->_imageResources[kAltMusicIconIdx];
+ const AnimFrame &altFrame = g_engine->_imageResources[kAltMusicIconIdx];
if (!altFrame._data.empty() && altFrame._width > 0) {
iconFrame = &altFrame;
}
@@ -4498,8 +4472,8 @@ void View1::drawOriginalSaveLoadPanel(Graphics::ManagedSurface &s) {
// Pressed: +1 offset
if (pressed) {
- iconX++;
- iconY++;
+ ++iconX;
+ ++iconY;
}
drawSprite(iconX, iconY, *iconFrame, s, false);
@@ -4535,12 +4509,6 @@ void View1::drawOriginalSaveLoadPanel(Graphics::ManagedSurface &s) {
}
void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
- // Exact translation of handleSaveLoadPanelClick (1008:86a4)
- // Binary takes (clickY, clickX) - note reversed parameter order
- int clickX = pos.x;
- int clickY = pos.y;
-
- // if (g_wClickedButtonIndex == 0) { ... entire function body }
if (_clickedButtonIndex != 0) {
return;
}
@@ -4561,6 +4529,8 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
// TODO: drawSaveLoadScrollArrows
}
+ int clickX = pos.x;
+ int clickY = pos.y;
// Slot loop: local_4 = 0..9
for (int slot = 0; slot <= 9; slot++) {
// Slot hit test for sub-mode 2 (save): editSaveSlotName
@@ -4584,11 +4554,8 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
clickX <= (int)(panelX + panelW - 12) &&
(int)(panelY + 6 + slot * 12) <= clickY &&
clickY <= (int)(panelY + slot * 12 + 16)) {
- int idx = _saveLoadPageIndex * 10 + slot;
+ const int idx = _saveLoadPageIndex * 10 + slot;
if (idx < ARRAYSIZE(_saveSlotNames) && !_saveSlotNames[idx].empty()) {
- // Binary: loadGameFromFile then:
- // g_wUiPanelState = 4; g_wClickedButtonIndex = 0;
- // g_wPendingPanelRequest = 4; g_wSaveLoadSubMode = 0
g_engine->loadGameState(idx);
_uiPanelState = kUiPanelSaveLoad;
_clickedButtonIndex = 0;
@@ -4610,7 +4577,7 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
// AND (mapDisabledFlag == 0 || i > 2)
bool hasData = false;
if (imgIdx < (int)g_engine->_imageResources.size()) {
- AnimFrame &frame = g_engine->_imageResources[imgIdx];
+ const AnimFrame &frame = g_engine->_imageResources[imgIdx];
hasData = (!frame._data.empty() && frame._width > 0);
}
@@ -4676,25 +4643,19 @@ void View1::handleOriginalSaveLoadClick(const Common::Point &pos) {
}
}
- // After button loop: set subMode based on clickedButtonIndex
- // Binary: if (g_wClickedButtonIndex < 3) g_wSaveLoadSubMode = g_wClickedButtonIndex
- // else g_wSaveLoadSubMode = 0
if (_clickedButtonIndex < 3) {
_saveLoadSubMode = (SaveLoadSubMode)_clickedButtonIndex;
} else {
_saveLoadSubMode = SaveLoadSubMode::None;
}
- // Binary: if (g_wClickedButtonIndex == 7) g_wPendingPanelRequest = 0 (close)
- // else g_wPendingPanelRequest = 4 (stay open)
if (_clickedButtonIndex == 7) {
_pendingPanelRequest = kPanelRequestNone;
return;
- } else {
- _pendingPanelRequest = kPanelRequestSaveLoadActive;
}
- // Binary: if (bPageScroll && ++g_wMapPanelPageIndex == 3) g_wMapPanelPageIndex = 0
+ _pendingPanelRequest = kPanelRequestSaveLoadActive;
+
if (bPageScroll) {
_saveLoadPageIndex++;
if (_saveLoadPageIndex == 3) {
diff --git a/engines/macs2/view1.h b/engines/macs2/view1.h
index 27f79a133ab..e1f3ee15082 100644
--- a/engines/macs2/view1.h
+++ b/engines/macs2/view1.h
@@ -60,33 +60,28 @@ private:
uint32 _startTime = 0;
uint32 _duration = 0;
- bool _lerpIgnoresObstacles = false;
-
// If this is set, a lerp to a location becomes picking up
Macs2::GameObject *_pickedUpObject = nullptr;
+ // Handle when the character has moved into a non-walkable area, push them out if
+ // they did and return true, return false otherwise
+ bool handleWalkability(Character *c);
+
+ uint16 lookupWalkability(const Common::Point &p) const;
+
+public:
+ Character();
+
// Frame counter for pickup animation (runtime+0x215).
// Increments each frame while orientation == 0x11.
// At _pickupFrameStart: item is transferred to inventory.
// At _pickupFrameEnd: animation ends, orientation restored.
-public:
uint16 _pickupFrameCounter = 0;
bool _pickupItemTransferred = false;
bool _markedForDeletion = false;
ObjectOrientation _previousOrientation = OrientationNone;
-private:
- // Handle when the character has moved into a non-walkable area, push them out if
- // they did and return true, return false otherwise
- bool handleWalkability(Character *c);
-
- // fn0037_0E8C proc
- uint16 lookupWalkability(const Common::Point &p) const;
-
-public:
- Character();
-
// Walk state from walkAlongPath (1008:1b8f) - runtime offsets +0x00..+0x0A, +0x18, +0x33
Common::Point _targetPosition; // runtime[+0x00, +0x02]: next waypoint
int16 _stepDeltaX = 0; // runtime[+0x04]: abs(endX - startX)
@@ -104,6 +99,13 @@ public:
Common::Point _pathFinalDestination;
Common::Array<uint8> _pathfindingOverlay;
+ Macs2::GameObject *_gameObject = nullptr;
+ uint16 _motionTargetVerticalOffset = 0;
+ uint16 _motionVerticalOffsetDelta = 0;
+ uint16 _motionDistanceUnits = 0;
+ uint16 _motionProgress = 0;
+ uint16 _motionStartVerticalOffset = 0;
+
bool isWalkable(const Common::Point &p) const;
bool calculatePath(Common::Point target);
bool canNodeConnectSourceToTarget(uint16 nodeIndex, const Common::Point &charPos, const Common::Point &target, const bool *reachable, int nodeCount);
@@ -115,70 +117,32 @@ public:
const Common::Point &getPosition() const;
void setPosition(const Common::Point &newPosition);
- Macs2::GameObject *_gameObject = nullptr;
uint16 getVerticalOffset() const;
-
- uint8 _animationIndex = 1;
- uint16 _motionTargetVerticalOffset = 0;
- uint16 _motionVerticalOffsetDelta = 0;
- uint16 _motionDistanceUnits = 0;
- uint16 _motionProgress = 0;
- uint16 _motionStartVerticalOffset = 0;
- bool _shouldMirrorCurrentAnimation = false;
-
- // Binary walkAlongPath (1008:1b8f): no separate motion flag; active when
- // runtime+0x21D >= 0 and differs from object vertical offset (+0x08).
bool hasPendingVerticalMotion() const;
bool shouldStepVerticalMotion() const;
-
bool isAnimationMirrored() const;
- uint8 getMirroredAnimation(uint8 original) const;
-
- // advanceMode matches drawAnimFrame/advanceAnimFrame (1010:16e7): 0=current frame,
- // 2=advance sequence after returning current frame. Hit testing uses 0; drawing uses 2.
- bool fillCurrentAnimationFrame(uint16 advanceMode, Macs2::AnimFrame &out);
+ bool fillCurrentAnimationFrame(uint16 advanceMode, Macs2::AnimFrame &out) const;
Macs2::AnimFrame *getCurrentAnimationFrame(uint16 advanceMode);
Macs2::AnimFrame *getCurrentPortrait(bool onRightSide = false, uint16 frameIndex = 0);
void update();
};
-// Binary scriptMoveObject (1008:aa83): copies object x/y into runtime position and target.
void resetCharacterWalkPath(Character *character);
-// cf https://stackoverflow.com/a/51497820
-template<typename T, T V>
-struct is_in_list_value {};
-
-template<typename T, T V>
-constexpr bool is_in_list_helper(T const &t, is_in_list_value<T, V>) {
- return t == V;
-}
-
-template<typename T, T V, T W, T... Rest>
-constexpr bool is_in_list_helper(T const &t, is_in_list_value<T, V>, is_in_list_value<T, W>, is_in_list_value<T, Rest>...) {
- return (t == V) || is_in_list_helper(t, is_in_list_value<T, W>(), is_in_list_value<T, Rest>()...);
-}
-
-template<typename T, T... ts>
-constexpr bool is_in_list(T const &t) {
- return is_in_list_helper(t, is_in_list_value<T, ts>()...);
-}
-
-
struct SpeechActData {
Character *speaker = nullptr;
Common::Array<Common::String> strings;
Common::Point position;
bool onRightSide = false;
+ bool mouthAnimActive = false;
// Mouth animation counter from handleTimerCallback (1008:d38b).
// Decremented each frame. Controls which portrait frame is drawn:
// >1: draw frame 2 from primary portrait blob (+0x14C)
// ==0: draw frame 1 from alternate portrait blob (+0x15C) (mouth open)
// <0: draw frame 2 from alternate portrait blob (+0x15C) (mouth closed)
int16 mouthAnimCounter = 0;
- bool mouthAnimActive = false;
};
struct ScalingValues {
@@ -190,15 +154,6 @@ class View1 : public UIElement {
friend class ActionBar;
private:
- // drawSpriteTransparent @ 1010:0ed1 (drawAnimFrameDepth @ 1010:172c)
- void drawSpriteTransparent(int shadingTableOffset, uint8 depthThreshold, uint16 scalingFactor,
- int16 drawX, int16 drawY, uint16 srcWidth, uint16 srcHeight,
- const byte *srcPixels, Graphics::ManagedSurface &s, bool useMaskedShading = false);
- // drawSpriteScaled @ 1010:102b (drawAnimFrameShaded @ 1010:1785)
- void drawSpriteScaled(int shadingTableOffset, uint8 depthThreshold, int16 drawX, int16 drawY,
- uint16 srcWidth, uint16 srcHeight, const byte *srcPixels,
- Graphics::ManagedSurface &s, bool useMaskedShading = false);
-
// Set by action bar map button on press; enterMapMode() runs on panel release.
bool _pendingMapOpen = false;
@@ -241,22 +196,34 @@ private:
uint16 _clickedButtonIndex = 0; // g_wClickedButtonIndex: last clicked button (0=none)
Common::String _saveSlotNames[30]; // 3 pages x 10 slots
+ int _currentFadeValue = -1;
+ FadeMode _fadeMode = FadeMode::None;
+ bool _cursorSuppressedForFade = false;
+ bool _cursorWasVisibleBeforeFade = false;
+
// Save/Load panel geometry (binary globals: g_wUiPanelX/Y/Width/Height, g_wActionBarButtonWidth/Height)
Common::Rect _saveLoadPanelRect;
Common::Rect _saveLoadButtonRects[7];
uint16 _saveLoadButtonWidth = 0; // g_wActionBarButtonWidth (after +6)
uint16 _saveLoadButtonHeight = 0; // g_wActionBarButtonHeight (after +6)
+ Common::Array<Common::Rect> _mainMenuButtonLocations;
+ Common::Rect _mainMenuRect;
+ Common::Point _inventoryGridUpperLeft;
+ Common::Point _inventorySlotSize;
+ Common::Array<Common::Rect> _inventoryButtonLocations;
+ uint16 _inventoryScrollOffset = 0;
+
+ static const uint16 kMaxSceneObjects = 0x200;
+ mutable uint16 _sortedObjectCount = 0;
+ mutable uint16 _sortedObjectIndices[kMaxSceneObjects + 1];
+ mutable Character *_characterByObjectIndex[kMaxSceneObjects + 1] = {};
+
void openOriginalSaveLoadPanel();
void drawOriginalSaveLoadPanel(Graphics::ManagedSurface &s);
void handleOriginalSaveLoadClick(const Common::Point &pos);
void closeOriginalSaveLoadPanel();
- int _currentFadeValue = -1;
- FadeMode _fadeMode = FadeMode::None;
- bool _cursorSuppressedForFade = false;
- bool _cursorWasVisibleBeforeFade = false;
-
void drawDarkRectangle(uint16 x, uint16 y, uint16 width, uint16 height);
void drawBackgroundAnimations(Graphics::ManagedSurface &s);
void drawCurrentSpeaker(Graphics::ManagedSurface &s);
@@ -266,8 +233,7 @@ private:
bool handleInventoryClick(const MouseDownMessage &msg);
bool handleContainerInventoryClick(const MouseDownMessage &msg);
- // Binary handleInventoryClick / handleContainerInventoryClick epilogue:
- // if pending != 0 -> uiBackgroundRestorePending=1; flip; runScriptExecutor; pending=0.
+ // Binary handleInven uiBackgroundRestorePending=1; flip; runScriptExecutor; pending=0.
void runInventoryPanelScriptIfPending(bool excludeCloseButton);
bool handleActionBarClick(const MouseDownMessage &msg);
void walkToScreenPosition(const Common::Point &pos);
@@ -302,27 +268,24 @@ private:
// 6 = close inventory/dialogue panels
// 7 = close map panel
bool handleInput(const MouseDownMessage &msg);
- // Binary handleInput (1008:e8bf): panel close on mouse release when
- // g_wClickedButtonIndex != 0 and buttonFlags != 1.
bool handlePanelRelease(const MouseUpMessage &msg);
bool handleHelpClick(const MouseDownMessage &msg);
void showStringBox(const Common::StringArray &sa);
void renderString(uint16 x, uint16 y, const Common::String &s);
- void renderString(const Common::Point pos, const Common::String &s);
+ void renderString(const Common::Point &pos, const Common::String &s);
void renderStringTo(uint16 x, uint16 y, const Common::String &s, Graphics::ManagedSurface &surf);
void renderStringWithFont(uint16 x, uint16 y, const Common::String &s, const GlyphData *glyphs, uint16 numGlyphs);
void renderStringWithFontTo(uint16 x, uint16 y, const Common::String &s, const GlyphData *glyphs,
uint16 numGlyphs, Graphics::ManagedSurface &surf);
int measureStringWithFont(const Common::String &s, const GlyphData *glyphs, uint16 numGlyphs);
-
- Common::Array<Common::Rect> _mainMenuButtonLocations;
- Common::Rect _mainMenuRect;
- Common::Point _inventoryGridUpperLeft;
- Common::Point _inventorySlotSize;
- Common::Array<Common::Rect> _inventoryButtonLocations;
- uint16 _inventoryScrollOffset = 0;
+ void drawSpriteTransparent(int shadingTableOffset, uint8 depthThreshold, uint16 scalingFactor,
+ int16 drawX, int16 drawY, uint16 srcWidth, uint16 srcHeight,
+ const byte *srcPixels, Graphics::ManagedSurface &s, bool useMaskedShading = false);
+ void drawSpriteScaled(int shadingTableOffset, uint8 depthThreshold, int16 drawX, int16 drawY,
+ uint16 srcWidth, uint16 srcHeight, const byte *srcPixels,
+ Graphics::ManagedSurface &s, bool useMaskedShading = false);
void drawSprite(int16 x, int16 y, uint16 width, uint16 height, byte *data, Graphics::ManagedSurface &s, bool mirrored, bool useDepth = false, uint8 depth = 0, bool clipToGameArea = false);
void drawSprite(int16 x, int16 y, const Sprite &sprite, Graphics::ManagedSurface &s, bool mirrored, bool useDepth = false, uint8 depth = 0, bool clipToGameArea = false);
@@ -332,17 +295,9 @@ private:
void drawSpriteClipped(uint16 x, uint16 y, const Common::Rect &clippingRect, const Sprite &sprite, Graphics::ManagedSurface &s);
void drawSpriteFitted(const Common::Rect &bounds, const Sprite &sprite, Graphics::ManagedSurface &s, uint16 inset = 6);
- // Binary sortObjectListByY (1008:8cf2) + buildSortedObjectList (1008:8c5a):
- // scan 512 objects, collect current-scene indices at 0xFAC, quicksort by Y.
- // Table is 1-indexed: slots 1..g_wSortedObjectCount hold object indices.
- static const uint16 kMaxSceneObjects = 0x200;
void sortObjectListByY() const;
void buildSortedObjectList(int low, int high) const;
- mutable uint16 _sortedObjectCount = 0;
- mutable uint16 _sortedObjectIndices[kMaxSceneObjects + 1];
- mutable Character *_characterByObjectIndex[kMaxSceneObjects + 1] = {};
- // drawAllCharacters @ 1008:90a2 - param_1: 0=draw only, 1=walk+draw (fullUpdate).
void drawAllCharacters(Graphics::ManagedSurface *surface = nullptr, bool fullUpdate = true);
int findInventoryItem(const GameObject *item);
@@ -353,27 +308,8 @@ public:
View1();
virtual ~View1();
- bool hasPersistentActionBar() const;
- bool shouldShowActionBar() const;
- void ensureActionBar();
- /** Top Y of the persistent action bar (game area ends here when shown). */
- int actionBarTopY() const;
-
- // g_wHelpButtonDisabled (1020:23B4): when non-zero, help/map button is disabled
- // and script scene changes use applyScenePaletteEffect instead of palette fades.
- // Map overlay mode is scene+0x61db (_currentMode == VM_HELP), not this flag.
- bool isHelpButtonDisabled() const { return _helpButtonDisabled; }
-
- void restoreUiPaletteEntries();
-
- void clearClickedButtonIndex() { _clickedButtonIndex = 0; }
-
ScalingValues _scalingValues;
-
ViewMode _currentMode = ViewMode::VM_GAME;
-
- AnimFrame *getInventoryIcon(GameObject *gameObject);
-
bool _paletteDirty = true;
bool _isShowingTextBox = false;
bool _isShowingDialoguePanel = false;
@@ -390,9 +326,7 @@ public:
Common::Array<Character *> _characters;
Common::Array<Character *> _pendingCharacterDeletes;
- void flushPendingCharacterDeletes();
- // Binary drawAllCharacters (1008:90a2) pickup frame: sceneIndex + inventory sync.
- void transferPickupTarget(GameObject *targetObject);
+
// If this is the protagonist, we have our normal inventory
// If this is another object, it is the inventory of a storage container
GameObject *_inventorySource = nullptr;
@@ -416,8 +350,6 @@ public:
};
UiPanelState _uiPanelState = kUiPanelNone;
- void finishPanelCloseAfterRelease(UiPanelState closedFromState);
-
// Binary g_wPendingPanelRequest (1020:1034): deferred panel open request.
// Set while action bar is active; processed by gameTick when _uiPanelState returns to kUiPanelNone.
// Values: 0=none, 1=protagonist inventory, 2=container inventory, 3=save/load
@@ -463,6 +395,43 @@ public:
uint16 _hoverAreaId = 0;
uint16 _hoverHotspotId = 0;
+ struct BorderStyle {
+ uint32 outerEdge; // sprite for outer frame (0x1010 = black)
+ uint32 topLeft; // sprite for top/left edge
+ uint32 bottomRight; // sprite for bottom/right edge
+ };
+ static const BorderStyle kBorderRaised;
+ static const BorderStyle kBorderPressed;
+
+ struct OverlayTextEntry {
+ Common::Point position;
+ uint8 alignment = 0;
+ Common::String text;
+ };
+
+ Common::Array<OverlayTextEntry> _overlayTextEntries;
+
+ bool hasPersistentActionBar() const;
+ bool shouldShowActionBar() const;
+ void ensureActionBar();
+ /** Top Y of the persistent action bar (game area ends here when shown). */
+ int actionBarTopY() const;
+
+ // g_wHelpButtonDisabled (1020:23B4): when non-zero, help/map button is disabled
+ // and script scene changes use applyScenePaletteEffect instead of palette fades.
+ // Map overlay mode is scene+0x61db (_currentMode == VM_HELP), not this flag.
+ bool isHelpButtonDisabled() const { return _helpButtonDisabled; }
+
+ void restoreUiPaletteEntries();
+
+ void clearClickedButtonIndex() { _clickedButtonIndex = 0; }
+
+ AnimFrame *getInventoryIcon(GameObject *gameObject);
+
+ void flushPendingCharacterDeletes();
+ void transferPickupTarget(GameObject *targetObject);
+ void finishPanelCloseAfterRelease(UiPanelState closedFromState);
+
// debug tools
void drawPathfindingPoints(Graphics::ManagedSurface &s);
void drawDebugOutput(Graphics::ManagedSurface &s);
@@ -527,14 +496,6 @@ public:
void showSpeechAct(uint16 characterIndex, const Common::Array<Common::String> &strings, const Common::Point &position, bool onRightSide = false);
- struct BorderStyle {
- uint32 outerEdge; // sprite for outer frame (0x1010 = black)
- uint32 topLeft; // sprite for top/left edge
- uint32 bottomRight; // sprite for bottom/right edge
- };
- static const BorderStyle kBorderRaised;
- static const BorderStyle kBorderPressed;
-
void drawNinePatchBorder(const Common::Point &pos, const Common::Point &size,
const BorderStyle &style, bool fillCenter, bool fillSides,
Graphics::ManagedSurface &s);
@@ -552,18 +513,10 @@ public:
void triggerDialogueChoice(uint8 index);
- struct OverlayTextEntry {
- Common::Point position;
- uint8 alignment = 0;
- Common::String text;
- };
-
void addOverlayTextEntry(const OverlayTextEntry &entry);
void clearOverlayTextEntries();
void drawOverlayTextEntries();
- Common::Array<OverlayTextEntry> _overlayTextEntries;
-
uint16 getHitObjectID(const Common::Point &pos) const;
};
Commit: eb8a08731be60eed48867410149c1ac9138092a9
https://github.com/scummvm/scummvm/commit/eb8a08731be60eed48867410149c1ac9138092a9
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: savegame fixes
Changed paths:
engines/macs2/macs2.h
engines/macs2/macs2_constants.h
engines/macs2/saveload.cpp
engines/macs2/view1.cpp
engines/macs2/view1.h
diff --git a/engines/macs2/macs2.h b/engines/macs2/macs2.h
index 4ab35a80719..c365b644b9b 100644
--- a/engines/macs2/macs2.h
+++ b/engines/macs2/macs2.h
@@ -911,6 +911,8 @@ public:
* Produces binary-compatible saves with the original DOS game.
*/
Common::Error syncGame(Common::Serializer &s);
+ Common::Error syncGameV1(Common::Serializer &s);
+ Common::Error syncGameV2(Common::Serializer &s);
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override {
Common::Serializer s(nullptr, stream);
diff --git a/engines/macs2/macs2_constants.h b/engines/macs2/macs2_constants.h
index 57140a8c2c2..8b627f12034 100644
--- a/engines/macs2/macs2_constants.h
+++ b/engines/macs2/macs2_constants.h
@@ -67,6 +67,7 @@ static constexpr uint32 kMcsV1ShadingTableSize = 0x800;
static constexpr uint kMcsV1CursorImageCount = 0x21;
static constexpr uint kMcsV1MapSceneOffsetCount = 256;
static constexpr uint32 kMcsV1MapSceneOffsetsSize = kMcsV1MapSceneOffsetCount * 4; // 0x400
+static constexpr uint kPathNodeSlots = 16;
static constexpr uint32 kMcsV2ActorIndexOffset = 0x20E;
static constexpr uint32 kMcsV2DirectoryOffset = 0x212;
diff --git a/engines/macs2/saveload.cpp b/engines/macs2/saveload.cpp
index cc065549df5..feabfd36bd0 100644
--- a/engines/macs2/saveload.cpp
+++ b/engines/macs2/saveload.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/endian.h"
#include "common/util.h"
#include "macs2/gameobjects.h"
#include "macs2/macs2.h"
@@ -26,7 +27,49 @@
namespace Macs2 {
+static void packPathBlock(const Character *chr, byte pathBlock[32], uint16 &pathIndex, uint16 &pathLength) {
+ memset(pathBlock, 0, 32);
+ pathIndex = 0;
+ pathLength = 0;
+ if (chr == nullptr)
+ return;
+
+ pathLength = (uint16)MIN<uint>(chr->_path.size(), kPathNodeSlots);
+ for (uint16 i = 0; i < pathLength; i++)
+ WRITE_LE_UINT16(&pathBlock[i * 2], chr->_path[i]);
+
+ if (pathLength == 0)
+ pathIndex = (uint16)chr->_currentPathIndex;
+ else
+ pathIndex = (uint16)(chr->_currentPathIndex + 1);
+}
+
+static void unpackPathBlock(Character *chr, const byte pathBlock[32], uint16 pathIndex, uint16 pathLength) {
+ chr->_path.clear();
+ if (pathLength > kPathNodeSlots)
+ pathLength = kPathNodeSlots;
+ for (uint16 i = 0; i < pathLength; i++)
+ chr->_path.push_back(READ_LE_UINT16(&pathBlock[i * 2]));
+
+ if (pathLength == 0)
+ chr->_currentPathIndex = (int16)pathIndex;
+ else
+ chr->_currentPathIndex = (int16)pathIndex - 1;
+}
+
Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
+ if (isV2()) {
+ return syncGameV2(s);
+ }
+ return syncGameV1(s);
+}
+
+Common::Error Macs2Engine::syncGameV2(Common::Serializer &s) {
+ // TODO: not yet implemented
+ return Common::kUnknownError;
+}
+
+Common::Error Macs2Engine::syncGameV1(Common::Serializer &s) {
const byte SAVE_MAGIC[12] = {'A', 'H', 'F', 'F', 'M', 'S', 'G', 'M', '0', '1', '0', '0'};
View1 *view1 = (View1 *)findView("View1");
if (view1 == nullptr)
@@ -41,10 +84,10 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
if (s.isSaving()) {
byte magic[12];
memcpy(magic, SAVE_MAGIC, sizeof(SAVE_MAGIC));
- s.syncBytes(magic, 12);
+ s.syncBytes(magic, sizeof(magic));
} else {
byte magic[12];
- s.syncBytes(magic, 12);
+ s.syncBytes(magic, sizeof(magic));
if (memcmp(magic, SAVE_MAGIC, sizeof(SAVE_MAGIC)) != 0)
return Common::kReadingFailed;
}
@@ -55,7 +98,7 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
slotName[0] = 20;
memcpy(slotName + 1, defName, sizeof(defName));
}
- s.syncBytes(slotName, 21);
+ s.syncBytes(slotName, sizeof(slotName));
uint16 actorIndex = (uint16)Scenes::instance()._currentActorIndex;
uint16 sceneIndex = (uint16)Scenes::instance()._currentSceneIndex;
@@ -471,23 +514,15 @@ Common::Error Macs2Engine::syncGame(Common::Serializer &s) {
}
byte pathBlock[32] = {0};
- if (s.isSaving() && chr)
- memcpy(pathBlock, chr->_pathBlockRaw, 32);
+ uint16 pathIndex = 0;
+ uint16 pathLength = 0;
+ if (s.isSaving())
+ packPathBlock(chr, pathBlock, pathIndex, pathLength);
s.syncBytes(pathBlock, 32);
-
- uint16 pathIndex = chr ? (uint16)chr->_currentPathIndex : 0;
s.syncAsUint16LE(pathIndex);
-
- uint16 pathLength = chr ? (uint16)chr->_path.size() : 0;
s.syncAsUint16LE(pathLength);
-
- if (s.isLoading()) {
- memcpy(chr->_pathBlockRaw, pathBlock, 32);
- chr->_path.clear();
- for (uint16 pi = 0; pi < pathLength && pi < 32; pi++)
- chr->_path.push_back(pathBlock[pi]);
- chr->_currentPathIndex = (int)pathIndex;
- }
+ if (s.isLoading() && chr)
+ unpackPathBlock(chr, pathBlock, pathIndex, pathLength);
uint16 stepAccum = chr ? (uint16)chr->_stepError : 0;
s.syncAsUint16LE(stepAccum);
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index e43914fd40f..d2c20378219 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -3717,13 +3717,12 @@ Character::Character() : _pathfindingOverlay(g_engine->screenWidth() * g_engine-
bool Character::calculatePath(Common::Point target) {
// Binary calculatePath (1008:1966). Params: charY, charX, finalDestY, finalDestX, actorIndex.
// The binary operates on the runtime struct directly; we store equivalent state in _path etc.
- constexpr int MAX_NODES = 16;
const Common::Point &charPos = _gameObject->_position;
const int nodeCount = g_engine->getPathfindingNodeCount();
// Step 1: Mark reachability anchored on FINAL DESTINATION (not character)
// scene[i + 0x50C2] = isPathWalkable(finalDest, node[i])
- bool reachable[MAX_NODES + 1] = {};
+ bool reachable[kPathNodeSlots + 1] = {};
for (int i = 1; i <= nodeCount; i++) {
const Common::Point &nodePos = g_engine->_pathfindingPoints[i - 1]._position;
reachable[i] = g_engine->isPathWalkable(target.y, target.x, nodePos.y, nodePos.x);
@@ -3784,7 +3783,7 @@ bool Character::calculatePath(Common::Point target) {
}
currentNode = nextNode;
_path.push_back(currentNode);
- if (_path.size() > MAX_NODES)
+ if (_path.size() > kPathNodeSlots)
break; // safety
}
@@ -3828,7 +3827,7 @@ bool Character::canNodeConnectSourceToTarget(uint16 nodeIndex, const Common::Poi
return false;
// Flood-fill connected nodes
- bool visited[17] = {};
+ bool visited[kPathNodeSlots + 1] = {};
floodFillConnectedNodes(nodeIndex, visited, nodeCount);
// Check both conditions
diff --git a/engines/macs2/view1.h b/engines/macs2/view1.h
index e1f3ee15082..754516a0ad7 100644
--- a/engines/macs2/view1.h
+++ b/engines/macs2/view1.h
@@ -91,11 +91,6 @@ public:
Common::Array<uint16> _path;
int16 _currentPathIndex = 0;
- // Raw 32-byte runtime path block at object runtime +0x0C. The original game
- // stores opaque per-waypoint data here (not just node indices). We preserve
- // it verbatim across save/load so DOS saves round-trip byte-for-byte; our own
- // pathfinding uses _path. Saved/restored by syncGame.
- uint8 _pathBlockRaw[32] = {0};
Common::Point _pathFinalDestination;
Common::Array<uint8> _pathfindingOverlay;
Commit: 241e39db0ea8b222f3377e7f1934bf1f6e52b64c
https://github.com/scummvm/scummvm/commit/241e39db0ea8b222f3377e7f1934bf1f6e52b64c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: removed unused method
Changed paths:
engines/macs2/view1.cpp
engines/macs2/view1.h
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index d2c20378219..400e7101ee6 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -3943,15 +3943,6 @@ bool Character::fillCurrentAnimationFrame(uint16 advanceMode, Macs2::AnimFrame &
return true;
}
-Macs2::AnimFrame *Character::getCurrentAnimationFrame(uint16 advanceMode) {
- AnimFrame *result = new AnimFrame();
- if (!fillCurrentAnimationFrame(advanceMode, *result)) {
- delete result;
- return nullptr;
- }
- return result;
-}
-
Macs2::AnimFrame *Character::getCurrentPortrait(bool onRightSide, uint16 frameIndex) {
if (_gameObject->_blobs.size() <= 17) {
return nullptr;
diff --git a/engines/macs2/view1.h b/engines/macs2/view1.h
index 754516a0ad7..0cbde928747 100644
--- a/engines/macs2/view1.h
+++ b/engines/macs2/view1.h
@@ -68,6 +68,14 @@ private:
bool handleWalkability(Character *c);
uint16 lookupWalkability(const Common::Point &p) const;
+ bool shouldStepVerticalMotion() const;
+ bool isAnimationMirrored() const;
+ void floodFillConnectedNodes(int nodeIndex, bool *visited, int nodeCount);
+ // Returns false if we are at the end of the path already or the path is not valid
+ bool walkAlongPath();
+ void startLerpTo(const Common::Point &target, uint32 duration, bool ignoreObstacles = false);
+ bool isWalkable(const Common::Point &p) const;
+ bool canNodeConnectSourceToTarget(uint16 nodeIndex, const Common::Point &charPos, const Common::Point &target, const bool *reachable, int nodeCount);
public:
Character();
@@ -101,13 +109,7 @@ public:
uint16 _motionProgress = 0;
uint16 _motionStartVerticalOffset = 0;
- bool isWalkable(const Common::Point &p) const;
bool calculatePath(Common::Point target);
- bool canNodeConnectSourceToTarget(uint16 nodeIndex, const Common::Point &charPos, const Common::Point &target, const bool *reachable, int nodeCount);
- void floodFillConnectedNodes(int nodeIndex, bool *visited, int nodeCount);
- // Returns false if we are at the end of the path already or the path is not valid
- bool walkAlongPath();
- void startLerpTo(const Common::Point &target, uint32 duration, bool ignoreObstacles = false);
void startPickup(Macs2::GameObject *object);
const Common::Point &getPosition() const;
@@ -115,10 +117,7 @@ public:
uint16 getVerticalOffset() const;
bool hasPendingVerticalMotion() const;
- bool shouldStepVerticalMotion() const;
- bool isAnimationMirrored() const;
bool fillCurrentAnimationFrame(uint16 advanceMode, Macs2::AnimFrame &out) const;
- Macs2::AnimFrame *getCurrentAnimationFrame(uint16 advanceMode);
Macs2::AnimFrame *getCurrentPortrait(bool onRightSide = false, uint16 frameIndex = 0);
void update();
Commit: 5e961c336a14d487030b878bde7812dd86a6422c
https://github.com/scummvm/scummvm/commit/5e961c336a14d487030b878bde7812dd86a6422c
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: _offset is not used - _bgAnimTickCounter is the palette cycling counter
Changed paths:
engines/macs2/view1.cpp
engines/macs2/view1.h
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 400e7101ee6..4732624815e 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -2437,8 +2437,6 @@ void View1::drawSceneUpdate() {
}
bool View1::tick() {
- // TODO: Check if this pattern works or it would be better different
- // TODO: Check if loading also works with this pattern
if (!_started) {
g_engine->changeScene(Scenes::instance()._currentSceneIndex);
_started = true;
@@ -2449,8 +2447,6 @@ bool View1::tick() {
redraw();
return true;
}
- // Cycle the palette
- ++_offset;
// Music fade tick from gameTick (1008:e556).
// Processes volume fade in/out each frame when active.
@@ -2459,7 +2455,7 @@ bool View1::tick() {
const uint16 musicStep = MAX<uint16>(se->_musicControlStep, 1);
if (se->_musicControlMode == 1) {
// Fade out: volume -= step
- int vol = (int)se->_musicControlVolume - (int)musicStep;
+ const int vol = (int)se->_musicControlVolume - (int)musicStep;
if (vol < 1) {
se->_musicControlMode = 0;
se->_musicControlVolume = 0;
@@ -2469,7 +2465,7 @@ bool View1::tick() {
g_engine->getMusic()->setVolume(g_engine->scaledMusicVolume(se->_musicControlVolume));
} else {
// Fade in: volume += step. When >= 63: stop music.
- int vol = (int)se->_musicControlVolume + (int)musicStep;
+ const int vol = (int)se->_musicControlVolume + (int)musicStep;
if (vol >= 0x3F) {
se->_musicControlMode = 0;
se->_activeMusicSlot = 0;
@@ -2481,11 +2477,6 @@ bool View1::tick() {
}
}
- // Below is redundant since we're only cycling the palette, but it demonstrates
- // how to trigger the view to do further draws after the first time, since views
- // don't automatically keep redrawing unless you tell it to
- // if ((_offset % 256) == 0)
- // redraw();
// Background animation sequencing happens in drawBackgroundAnimations via
// drawAnimFrame(2, ...) semantics (1008:929c). Do not advance here - a
diff --git a/engines/macs2/view1.h b/engines/macs2/view1.h
index 0cbde928747..6e30fa48b43 100644
--- a/engines/macs2/view1.h
+++ b/engines/macs2/view1.h
@@ -156,7 +156,6 @@ private:
// Saved scene visuals for help screen restore (avoids changeScene on exit)
Graphics::Palette _savedPalVanilla{Graphics::PALETTE_COUNT};
Graphics::ManagedSurface _savedDepthMap;
- int _offset = 0; // TODO: palette cycling?
// Tick counter gating the mode-dependent palette brighten effect
// (updateBackgroundAnimationPalette). Matches g_wBgAnimTickCounter in the
Commit: 47d77eef7f4a65f02ed11a34450a63822f5c97b9
https://github.com/scummvm/scummvm/commit/47d77eef7f4a65f02ed11a34450a63822f5c97b9
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: moved object names
Changed paths:
engines/macs2/debugtools.cpp
engines/macs2/gameobjects.cpp
engines/macs2/gameobjects.h
engines/macs2/hotspot_names.cpp
engines/macs2/hotspot_names.h
engines/macs2/macs2.cpp
engines/macs2/view1.cpp
diff --git a/engines/macs2/debugtools.cpp b/engines/macs2/debugtools.cpp
index 7180a4432f5..f750ec2c8b7 100644
--- a/engines/macs2/debugtools.cpp
+++ b/engines/macs2/debugtools.cpp
@@ -1199,9 +1199,9 @@ static void showInventoryWindow() {
if (ImGui::CollapsingHeader("Current Inventory", ImGuiTreeNodeFlags_DefaultOpen)) {
for (uint i = 0; i < view->_inventoryItems.size(); i++) {
GameObject *obj = view->_inventoryItems[i];
- const Common::String &name = (obj->_index < GameObjects::instance()._objectNames.size() && !GameObjects::instance()._objectNames[obj->_index].empty())
- ? GameObjects::instance()._objectNames[obj->_index]
- : "???";
+ Common::String name = getObjectHotspotName(obj->_index);
+ if (name.empty())
+ name = "???";
Common::String utf8Name = Common::U32String(name.c_str(), Common::kDos850).encode(Common::kUtf8);
ImGui::PushID(obj->_index);
if (ImGui::Button("Remove")) {
@@ -1223,9 +1223,9 @@ static void showInventoryWindow() {
continue;
if (obj->_blobs.size() <= 0x13 || obj->_blobs[0x13].empty())
continue;
- const Common::String &name = (obj->_index < GameObjects::instance()._objectNames.size() && !GameObjects::instance()._objectNames[obj->_index].empty())
- ? GameObjects::instance()._objectNames[obj->_index]
- : "???";
+ Common::String name = getObjectHotspotName(obj->_index);
+ if (name.empty())
+ name = "???";
Common::String utf8Name = Common::U32String(name.c_str(), Common::kDos850).encode(Common::kUtf8);
if (filterBuf[0] != '\0' && !utf8Name.contains(filterBuf))
continue;
diff --git a/engines/macs2/gameobjects.cpp b/engines/macs2/gameobjects.cpp
index 61e9e05d554..d021880515c 100644
--- a/engines/macs2/gameobjects.cpp
+++ b/engines/macs2/gameobjects.cpp
@@ -99,256 +99,6 @@ Common::Array<uint8> Macs2::Scenes::readSpecialAnimBlob(uint16 index, Common::Se
return result;
}
-void Macs2::GameObjects::init() {
- _objectNames.resize(0xFF);
- if (!g_engine->isV1()) {
- return;
- }
- // Object names from game string dumps. Index matches the object ID used in scripts.
- if (g_engine->isDemo()) {
- _objectNames[0x02] = "Laib Brot"; // sliced
- _objectNames[0x03] = "Laib Brot"; // with key inside
- _objectNames[0x04] = "Schnapsflasche"; // wrapped with rope
- _objectNames[0x05] = "Schnapsflasche";
- _objectNames[0x07] = "Spitzhacke";
- _objectNames[0x08] = "Hackenspitze"; // rusty pick point
- _objectNames[0x09] = "Kerze"; // lit
- _objectNames[0x0A] = "Kerze"; // from dismantled lamp
- _objectNames[0x0B] = "Kerzen"; // 4 candles
- _objectNames[0x0D] = "Korkenzieher";
- _objectNames[0x0E] = "Lampe";
- _objectNames[0x10] = "Lampe"; // second instance
- _objectNames[0x11] = "Holzpfahl"; // sturdy wooden stake
- _objectNames[0x12] = "Wagenrad";
- _objectNames[0x14] = "Salpeterpulver";
- _objectNames[0x15] = "Schaufelspitze"; // blunt
- _objectNames[0x16] = "Lampenschirm";
- _objectNames[0x17] = "Lampenschirme"; // plural, from lamp
- _objectNames[0x18] = "Messingschl\x81ssel";
- _objectNames[0x19] = "Schwarzpulver";
- _objectNames[0x1A] = "Hanfseile"; // tied together
- _objectNames[0x1B] = "Streichholz";
- _objectNames[0x1C] = "Topflappen";
- _objectNames[0x1D] = "Windlicht";
- _objectNames[0x1E] = "Wolle"; // soaked in alcohol
- _objectNames[0x51] = "Stoffbeutel"; // empty
- _objectNames[0x52] = "Stoffbeutel"; // with marbles
- _objectNames[0x53] = "Blasebalg";
- _objectNames[0x54] = "Brennholz";
- _objectNames[0x56] = "Brotmesser";
- _objectNames[0x58] = "B\x81"
- "cher"; // adventure books
- _objectNames[0x59] = "Clownpuppe";
- _objectNames[0x5A] = "Blechdose"; // green, with sulphur
- _objectNames[0x5B] = "Blechdose"; // empty
- _objectNames[0x5C] = "Papierdrachen"; // with string tail
- _objectNames[0x5D] = "Papierdrachen"; // without tail
- _objectNames[0x5E] = "Blecheimer"; // empty
- _objectNames[0x5F] = "Blecheimer"; // with water
- _objectNames[0x64] = "Kartoffeln";
- _objectNames[0x6F] = "Murmeln";
- _objectNames[0x70] = "Musketen";
- _objectNames[0x74] = "Schaufel"; // old and blunt
- _objectNames[0x7C] = "Schwarzpulver"; // mixing state
- _objectNames[0x7D] = "Sch\x81ssel"; // with dough
- _objectNames[0x7F] = "Schwefel";
- _objectNames[0x80] = "Hanfseil"; // short
- _objectNames[0x81] = "Hanfschnur";
- _objectNames[0x83] = "Socken"; // red
- _objectNames[0x84] = "Spachtel";
- _objectNames[0x85] = "Holzente"; // on wheels
- _objectNames[0x87] = "Tasse"; // empty
- _objectNames[0x88] = "Tasse"; // with oil
- _objectNames[0x89] = "Teig";
- _objectNames[0x8C] = "Wolle"; // ball of wool
- _objectNames[0x8E] = "Holzw\x81rfel";
- _objectNames[0x8F] = "Brief";
-
- // Characters/NPCs - from output-demo strings + Schatz-Demo RESOURCE.MCS dialogue
- _objectNames[0x06] = "Tramp"; // strings_object006 [0]
- _objectNames[0x0C] = "Droll"; // scene 28/30 dialogue (Tante Droll)
- _objectNames[0x0F] = "Cornel"; // scene 5: Cornel Brinkley (obj_0xf)
- _objectNames[0x13] = "Tramp"; // strings_object019 [0]; tramp henchman
- _objectNames[0x45] = "Rafter"; // scene 30 dialogue
- _objectNames[0x4D] = "Tramp"; // scene 5 tramp henchman
- _objectNames[0x69] = "Wirt"; // scene 28 gatekeeper dialogue
- _objectNames[0x6E] = "Mrs. Butler"; // strings_object110 [0]
- } else {
- // Characters/NPCs - labels from strings_object*.txt [0] and/or scene dialogue (demacs2)
- _objectNames[0x01] = "Old Firehand"; // strings_object001 [0]
- _objectNames[0x02] = "Kapit\xe4n"; // strings_object002 [0-1]
- _objectNames[0x04] = "Bootsjunge"; // strings_object004 [0]
- _objectNames[0x06] = "Tramp"; // strings_object006 [0]; tramp henchman
- _objectNames[0x07] = "M\xe4""dchen"; // strings_object007 [0]
- _objectNames[0x09] = "Panther"; // strings_object009 (panther scene)
- _objectNames[0x0C] = "Droll"; // strings_object012 [0]
- _objectNames[0x0D] = "Patterson"; // strings_object013 [0]
- _objectNames[0x0F] = "Cornel"; // scene 9: Cornel Brinkley (obj_0xf)
- _objectNames[0x12] = "Wachposten"; // scene 12 dialogue
- _objectNames[0x13] = "Tramp"; // strings_object019 [0]; tramp henchman
- _objectNames[0x16] = "Passagierin"; // scene 2 dialogue
- _objectNames[0x21] = "Matrose"; // scene 10 dialogue
- _objectNames[0x27] = "Branshky"; // strings_object039 [0]
- _objectNames[0x35] = "Dieb"; // scene 24 dialogue
- _objectNames[0x45] = "Rafter"; // scene 18: "wir sind Rafter"
- _objectNames[0x4D] = "Tramp"; // tramp henchman, scenes 5/18
- _objectNames[0x69] = "Wirt"; // scene 28 barkeeper dialogue
- _objectNames[0x6E] = "Mrs. Butler"; // strings_object110 [0]
- _objectNames[0x90] = "Bandit"; // scene 29
- _objectNames[0x91] = "Bandit"; // scene 29
- _objectNames[0x92] = "Bandit"; // scene 29
- _objectNames[0x93] = "Winnetou"; // scene 29 dialogue
- _objectNames[0x95] = "Grosser B\xe4""r"; // scene 45: greeted by Winnetou
- _objectNames[0xA7] = "Winnetou"; // scene 45 dialogue
- _objectNames[0xA8] = "Kleiner B\xe4""r"; // scene 45: greeted by Winnetou
- _objectNames[0xB5] = "Winnetou"; // strings_object181; ending scenes
-
- // Full game - verified against strings_object*.txt dumps
- _objectNames[0x08] = "Brett"; // board
- _objectNames[0x0E] = "Eimer"; // bucket, full of water
- _objectNames[0x10] = "Holzfass"; // wooden barrel, empty
- _objectNames[0x11] = "Bowiemesser"; // bowie knife
- _objectNames[0x14] = "Eimer"; // bucket, full of water
- _objectNames[0x17] = "Hutschachtel"; // hatbox, empty and open
- _objectNames[0x18] = "Damenhut"; // lady's hat with veil
- _objectNames[0x19] = "Hutschachtel"; // strings_object025 [4]
- _objectNames[0x1A] = "Metalleimer"; // metal bucket, empty
- _objectNames[0x1B] = "Feuerhaken"; // fire poker
- _objectNames[0x1C] = "Topflappen"; // pot holder
- _objectNames[0x1D] = "Brett"; // board, wrapped in cloth
- _objectNames[0x1E] = "Kohlenschaufel"; // coal shovel
- _objectNames[0x20] = "Kakerlake"; // cockroach
- _objectNames[0x22] = "Tasse"; // cup, full (coffee)
- _objectNames[0x23] = "Tasse"; // cup, empty
- _objectNames[0x24] = "Axt"; // axe
- _objectNames[0x25] = "Axtklinge"; // axe blade
- _objectNames[0x26] = "Reservestiel"; // spare handle
- _objectNames[0x28] = "Brief"; // letter
- _objectNames[0x29] = "Brot"; // bread, moldy
- _objectNames[0x2A] = "Brot"; // bread, stale
- _objectNames[0x2B] = "Kuvert"; // envelope, open
- _objectNames[0x2C] = "Kuvert"; // envelope, sealed
- _objectNames[0x2D] = "Waschb\x84rm\x81tze"; // strings_object045 [0]
- _objectNames[0x2E] = "Whiskyglas"; // whisky glass
- _objectNames[0x2F] = "Lederg\x81rtel"; // leather belt
- _objectNames[0x30] = "Sch\x81rhaken"; // poker
- _objectNames[0x31] = "Wachhund"; // strings_object049 [0]
- _objectNames[0x34] = "Brett"; // board, solid
- _objectNames[0x36] = "Vogelk\x84"
- "fig"; // birdcage, with bird
- _objectNames[0x37] = "Vogelk\x84"
- "fig"; // birdcage, broken
- _objectNames[0x38] = "Vogelk\x84"
- "fig"; // birdcage, empty
- _objectNames[0x39] = "Vogelk\x84"
- "fig"; // birdcage, with bird
- _objectNames[0x3A] = "Landkarte"; // map
- _objectNames[0x3B] = "Kerze"; // candle
- _objectNames[0x3C] = "Kieselsteine"; // pebbles
- _objectNames[0x3D] = "Koffer"; // strings_object061 [0]
- _objectNames[0x3E] = "Kleider"; // strings_object062 [0]
- _objectNames[0x3F] = "Lederbeutel"; // leather pouch, empty
- _objectNames[0x40] = "Knallfr\x94sche"; // strings_object064 [5]
- _objectNames[0x41] = "Knallfr\x94sche"; // firecrackers
- _objectNames[0x42] = "Koffer"; // suitcase, open
- _objectNames[0x43] = "Koffer"; // suitcase, closed
- _objectNames[0x44] = "Papier"; // paper, crumpled
- _objectNames[0x47] = "Messer"; // knife, rusty
- _objectNames[0x48] = "Kartonschachtel"; // cardboard box, open and empty
- _objectNames[0x49] = "Kartonschachtel"; // cardboard box
- _objectNames[0x4A] = "Schal"; // strings_object074 [0-1]
- _objectNames[0x4B] = "Schilfrohr"; // reeds, dry
- _objectNames[0x4C] = "Schilfrohr"; // reeds, straight
- _objectNames[0x4F] = "Schnapsflasche"; // liquor bottle
- // Objects 81+ (0x51+)
- _objectNames[0x51] = "Stoffbeutel"; // cloth bag, empty
- _objectNames[0x52] = "Stoffbeutel"; // cloth bag, with marbles
- _objectNames[0x53] = "Blasebalg"; // bellows
- _objectNames[0x54] = "Brennholz"; // firewood
- _objectNames[0x55] = "Laib Brot"; // loaf of bread, sliced
- _objectNames[0x56] = "Brotmesser"; // bread knife
- _objectNames[0x57] = "Laib Brot"; // loaf of bread, with key
- _objectNames[0x58] = "B\x81"
- "cher"; // books
- _objectNames[0x59] = "Clownpuppe"; // clown doll
- _objectNames[0x5A] = "Blechdose"; // tin can, green with sulphur
- _objectNames[0x5B] = "Blechdose"; // tin can, empty
- _objectNames[0x5C] = "Papierdrachen"; // paper kite, with string
- _objectNames[0x5D] = "Papierdrachen"; // paper kite, without tail
- _objectNames[0x5E] = "Blecheimer"; // tin bucket, empty
- _objectNames[0x5F] = "Blecheimer"; // tin bucket, full of water
- _objectNames[0x60] = "Schnapsflasche"; // liquor bottle, wrapped
- _objectNames[0x61] = "Schnapsflasche"; // liquor bottle
- _objectNames[0x62] = "Spitzhacke"; // pickaxe
- _objectNames[0x63] = "Hackenspitze"; // pick point, rusty
- _objectNames[0x64] = "Kartoffeln"; // potatoes
- _objectNames[0x65] = "Kerze"; // candle, lit
- _objectNames[0x66] = "Kerze"; // candle, from lamp
- _objectNames[0x67] = "Kerzen"; // candles, four
- _objectNames[0x6A] = "Holzkohle"; // charcoal
- _objectNames[0x6B] = "Korkenzieher"; // corkscrew
- _objectNames[0x6C] = "Lampe"; // lamp
- _objectNames[0x6D] = "Lampe"; // lamp, second instance
- _objectNames[0x6F] = "Murmeln"; // marbles
- _objectNames[0x70] = "Musketen"; // muskets
- _objectNames[0x71] = "Holzpfahl"; // wooden stake
- _objectNames[0x72] = "Wagenrad"; // wagon wheel
- _objectNames[0x73] = "Salpeterpulver"; // saltpeter
- _objectNames[0x74] = "Schaufel"; // shovel
- _objectNames[0x75] = "Schaufelspitze"; // shovel blade
- _objectNames[0x76] = "Lampenschirm"; // lamp shade
- _objectNames[0x77] = "Lampenschirme"; // lamp shades
- _objectNames[0x78] = "Messingschl\x81ssel"; // brass key
- _objectNames[0x7C] = "Schwarzpulver"; // gunpowder, mixing
- _objectNames[0x7D] = "Sch\x81ssel"; // bowl, with dough
- _objectNames[0x7E] = "Schwarzpulver"; // gunpowder
- _objectNames[0x7F] = "Schwefel"; // sulphur
- _objectNames[0x80] = "Hanfseil"; // hemp rope, short
- _objectNames[0x81] = "Hanfschnur"; // hemp string
- _objectNames[0x82] = "Hanfseile"; // hemp ropes, tied together
- _objectNames[0x83] = "Socken"; // socks, red
- _objectNames[0x84] = "Spachtel"; // spatula
- _objectNames[0x85] = "Holzente"; // wooden duck
- _objectNames[0x86] = "Streichholz"; // match
- _objectNames[0x87] = "Tasse"; // cup, empty
- _objectNames[0x88] = "Tasse"; // cup, with oil
- _objectNames[0x89] = "Teig"; // dough
- _objectNames[0x8A] = "Topflappen"; // pot holder
- _objectNames[0x8B] = "Windlicht"; // lantern
- _objectNames[0x8C] = "Wolle"; // wool
- _objectNames[0x8D] = "Wolle"; // wool, soaked in alcohol
- _objectNames[0x8E] = "Holzw\x81rfel"; // wooden blocks
- _objectNames[0x8F] = "Brief"; // letter
- _objectNames[0x94] = "Lore"; // mine cart
- _objectNames[0x96] = "Lederbeutel"; // leather pouch, empty
- _objectNames[0x97] = "Lederbeutel"; // leather pouch, full of sand
- _objectNames[0x98] = "Bohlen"; // planks
- _objectNames[0x99] = "Brecheisen"; // crowbar
- _objectNames[0x9A] = "Sand"; // sand
- _objectNames[0x9B] = "Dynamit"; // dynamite
- _objectNames[0x9C] = "Fackel"; // torch, burning
- _objectNames[0x9D] = "Fackel"; // torch
- _objectNames[0x9E] = "Holzfigur"; // wooden figure, empty
- _objectNames[0x9F] = "Figur"; // figure, assembled
- _objectNames[0xA0] = "Holzfigur"; // wooden figure, empty
- _objectNames[0xA1] = "Flaschenzug"; // pulley
- _objectNames[0xA2] = "Haken"; // hook
- _objectNames[0xA3] = "Haken und Seil"; // hook and rope
- _objectNames[0xA4] = "Kacheln"; // tiles
- _objectNames[0xA6] = "Nase"; // nose
- _objectNames[0xAB] = "Quarzsand"; // quartz sand
- _objectNames[0xAC] = "Quarzsand"; // quartz sand
- _objectNames[0xAD] = "Griff"; // handle
- _objectNames[0xAE] = "Hanfseil"; // hemp rope
- _objectNames[0xAF] = "Sicheln"; // sickles
- _objectNames[0xB0] = "Eisen"; // irons, two angled
- _objectNames[0xB1] = "Eisen"; // iron
- _objectNames[0xB2] = "Schraubenzieher"; // screwdriver
- _objectNames[0xB3] = "Eisenstange"; // iron bar
- _objectNames[0xB4] = "Tomahawk"; // tomahawk
- }
-}
-
bool Macs2::GameObjects::isNpcIndex(uint16 objectIndex) {
if (objectIndex == 0) {
return false;
diff --git a/engines/macs2/gameobjects.h b/engines/macs2/gameobjects.h
index 927c59716aa..fe94c37d9f5 100644
--- a/engines/macs2/gameobjects.h
+++ b/engines/macs2/gameobjects.h
@@ -234,9 +234,6 @@ public:
class GameObjects : public Common::Singleton<GameObjects> {
public:
Common::Array<GameObject *> _objects;
- Common::Array<Common::String> _objectNames;
-
- void init();
/** True for character/NPC object indices (not inventory items). */
static bool isNpcIndex(uint16 objectIndex);
diff --git a/engines/macs2/hotspot_names.cpp b/engines/macs2/hotspot_names.cpp
index 955ca19a803..b1ffb11e91e 100644
--- a/engines/macs2/hotspot_names.cpp
+++ b/engines/macs2/hotspot_names.cpp
@@ -537,6 +537,247 @@ const SceneHotspotNameEntry kSceneHotspotNamesDemo[] = {
{ 38, 15, Graphics::kHotspotObject, "Holzt" "\x81" "r" },
};
+
+struct ObjectNameEntry {
+ uint16 objectIndex;
+ const char *name;
+};
+
+// Object labels keyed by object index (interaction 0x400 + index).
+// Distinct from kSceneHotspotNames (interaction 0x800 + hotspotIndex).
+const ObjectNameEntry kObjectNames[] = {
+ { 0x01, "Old Firehand" },
+ { 0x02, "Kapit" "\x84" "n" },
+ { 0x04, "Bootsjunge" },
+ { 0x06, "Tramp" },
+ { 0x07, "M" "\x84" "dchen" },
+ { 0x08, "Brett" },
+ { 0x09, "Panther" },
+ { 0x0C, "Droll" },
+ { 0x0D, "Patterson" },
+ { 0x0E, "Eimer" },
+ { 0x0F, "Cornel" },
+ { 0x10, "Holzfass" },
+ { 0x11, "Bowiemesser" },
+ { 0x12, "Wachposten" },
+ { 0x13, "Tramp" },
+ { 0x14, "Eimer" },
+ { 0x16, "Passagierin" },
+ { 0x17, "Hutschachtel" },
+ { 0x18, "Damenhut" },
+ { 0x19, "Hutschachtel" },
+ { 0x1A, "Metalleimer" },
+ { 0x1B, "Feuerhaken" },
+ { 0x1C, "Topflappen" },
+ { 0x1D, "Brett" },
+ { 0x1E, "Kohlenschaufel" },
+ { 0x20, "Kakerlake" },
+ { 0x21, "Matrose" },
+ { 0x22, "Tasse" },
+ { 0x23, "Tasse" },
+ { 0x24, "Axt" },
+ { 0x25, "Axtklinge" },
+ { 0x26, "Reservestiel" },
+ { 0x27, "Branshky" },
+ { 0x28, "Brief" },
+ { 0x29, "Brot" },
+ { 0x2A, "Brot" },
+ { 0x2B, "Kuvert" },
+ { 0x2C, "Kuvert" },
+ { 0x2D, "Waschb\x84rm\x81tze" },
+ { 0x2E, "Whiskyglas" },
+ { 0x2F, "Lederg\x81rtel" },
+ { 0x30, "Sch\x81rhaken" },
+ { 0x31, "Wachhund" },
+ { 0x34, "Brett" },
+ { 0x35, "Dieb" },
+ { 0x36, "Vogelk\x84" "fig" },
+ { 0x37, "Vogelk\x84" "fig" },
+ { 0x38, "Vogelk\x84" "fig" },
+ { 0x39, "Vogelk\x84" "fig" },
+ { 0x3A, "Landkarte" },
+ { 0x3B, "Kerze" },
+ { 0x3C, "Kieselsteine" },
+ { 0x3D, "Koffer" },
+ { 0x3E, "Kleider" },
+ { 0x3F, "Lederbeutel" },
+ { 0x40, "Knallfr\x94sche" },
+ { 0x41, "Knallfr\x94sche" },
+ { 0x42, "Koffer" },
+ { 0x43, "Koffer" },
+ { 0x44, "Papier" },
+ { 0x45, "Rafter" },
+ { 0x47, "Messer" },
+ { 0x48, "Kartonschachtel" },
+ { 0x49, "Kartonschachtel" },
+ { 0x4A, "Schal" },
+ { 0x4B, "Schilfrohr" },
+ { 0x4C, "Schilfrohr" },
+ { 0x4D, "Tramp" },
+ { 0x4F, "Schnapsflasche" },
+ { 0x51, "Stoffbeutel" },
+ { 0x52, "Stoffbeutel" },
+ { 0x53, "Blasebalg" },
+ { 0x54, "Brennholz" },
+ { 0x55, "Laib Brot" },
+ { 0x56, "Brotmesser" },
+ { 0x57, "Laib Brot" },
+ { 0x58, "B\x81" "cher" },
+ { 0x59, "Clownpuppe" },
+ { 0x5A, "Blechdose" },
+ { 0x5B, "Blechdose" },
+ { 0x5C, "Papierdrachen" },
+ { 0x5D, "Papierdrachen" },
+ { 0x5E, "Blecheimer" },
+ { 0x5F, "Blecheimer" },
+ { 0x60, "Schnapsflasche" },
+ { 0x61, "Schnapsflasche" },
+ { 0x62, "Spitzhacke" },
+ { 0x63, "Hackenspitze" },
+ { 0x64, "Kartoffeln" },
+ { 0x65, "Kerze" },
+ { 0x66, "Kerze" },
+ { 0x67, "Kerzen" },
+ { 0x69, "Wirt" },
+ { 0x6A, "Holzkohle" },
+ { 0x6B, "Korkenzieher" },
+ { 0x6C, "Lampe" },
+ { 0x6D, "Lampe" },
+ { 0x6E, "Mrs. Butler" },
+ { 0x6F, "Murmeln" },
+ { 0x70, "Musketen" },
+ { 0x71, "Holzpfahl" },
+ { 0x72, "Wagenrad" },
+ { 0x73, "Salpeterpulver" },
+ { 0x74, "Schaufel" },
+ { 0x75, "Schaufelspitze" },
+ { 0x76, "Lampenschirm" },
+ { 0x77, "Lampenschirme" },
+ { 0x78, "Messingschl\x81ssel" },
+ { 0x7C, "Schwarzpulver" },
+ { 0x7D, "Sch\x81ssel" },
+ { 0x7E, "Schwarzpulver" },
+ { 0x7F, "Schwefel" },
+ { 0x80, "Hanfseil" },
+ { 0x81, "Hanfschnur" },
+ { 0x82, "Hanfseile" },
+ { 0x83, "Socken" },
+ { 0x84, "Spachtel" },
+ { 0x85, "Holzente" },
+ { 0x86, "Streichholz" },
+ { 0x87, "Tasse" },
+ { 0x88, "Tasse" },
+ { 0x89, "Teig" },
+ { 0x8A, "Topflappen" },
+ { 0x8B, "Windlicht" },
+ { 0x8C, "Wolle" },
+ { 0x8D, "Wolle" },
+ { 0x8E, "Holzw\x81rfel" },
+ { 0x8F, "Brief" },
+ { 0x90, "Bandit" },
+ { 0x91, "Bandit" },
+ { 0x92, "Bandit" },
+ { 0x93, "Winnetou" },
+ { 0x94, "Lore" },
+ { 0x95, "Grosser B" "\x84" "r" },
+ { 0x96, "Lederbeutel" },
+ { 0x97, "Lederbeutel" },
+ { 0x98, "Bohlen" },
+ { 0x99, "Brecheisen" },
+ { 0x9A, "Sand" },
+ { 0x9B, "Dynamit" },
+ { 0x9C, "Fackel" },
+ { 0x9D, "Fackel" },
+ { 0x9E, "Holzfigur" },
+ { 0x9F, "Figur" },
+ { 0xA0, "Holzfigur" },
+ { 0xA1, "Flaschenzug" },
+ { 0xA2, "Haken" },
+ { 0xA3, "Haken und Seil" },
+ { 0xA4, "Kacheln" },
+ { 0xA6, "Nase" },
+ { 0xA7, "Winnetou" },
+ { 0xA8, "Kleiner B" "\x84" "r" },
+ { 0xAB, "Quarzsand" },
+ { 0xAC, "Quarzsand" },
+ { 0xAD, "Griff" },
+ { 0xAE, "Hanfseil" },
+ { 0xAF, "Sicheln" },
+ { 0xB0, "Eisen" },
+ { 0xB1, "Eisen" },
+ { 0xB2, "Schraubenzieher" },
+ { 0xB3, "Eisenstange" },
+ { 0xB4, "Tomahawk" },
+ { 0xB5, "Winnetou" },
+};
+
+const ObjectNameEntry kObjectNamesDemo[] = {
+ { 0x02, "Laib Brot" },
+ { 0x03, "Laib Brot" },
+ { 0x04, "Schnapsflasche" },
+ { 0x05, "Schnapsflasche" },
+ { 0x06, "Tramp" },
+ { 0x07, "Spitzhacke" },
+ { 0x08, "Hackenspitze" },
+ { 0x09, "Kerze" },
+ { 0x0A, "Kerze" },
+ { 0x0B, "Kerzen" },
+ { 0x0C, "Droll" },
+ { 0x0D, "Korkenzieher" },
+ { 0x0E, "Lampe" },
+ { 0x0F, "Cornel" },
+ { 0x10, "Lampe" },
+ { 0x11, "Holzpfahl" },
+ { 0x12, "Wagenrad" },
+ { 0x13, "Tramp" },
+ { 0x14, "Salpeterpulver" },
+ { 0x15, "Schaufelspitze" },
+ { 0x16, "Lampenschirm" },
+ { 0x17, "Lampenschirme" },
+ { 0x18, "Messingschl\x81ssel" },
+ { 0x19, "Schwarzpulver" },
+ { 0x1A, "Hanfseile" },
+ { 0x1B, "Streichholz" },
+ { 0x1C, "Topflappen" },
+ { 0x1D, "Windlicht" },
+ { 0x1E, "Wolle" },
+ { 0x45, "Rafter" },
+ { 0x4D, "Tramp" },
+ { 0x51, "Stoffbeutel" },
+ { 0x52, "Stoffbeutel" },
+ { 0x53, "Blasebalg" },
+ { 0x54, "Brennholz" },
+ { 0x56, "Brotmesser" },
+ { 0x58, "B\x81" "cher" },
+ { 0x59, "Clownpuppe" },
+ { 0x5A, "Blechdose" },
+ { 0x5B, "Blechdose" },
+ { 0x5C, "Papierdrachen" },
+ { 0x5D, "Papierdrachen" },
+ { 0x5E, "Blecheimer" },
+ { 0x5F, "Blecheimer" },
+ { 0x64, "Kartoffeln" },
+ { 0x69, "Wirt" },
+ { 0x6E, "Mrs. Butler" },
+ { 0x6F, "Murmeln" },
+ { 0x70, "Musketen" },
+ { 0x74, "Schaufel" },
+ { 0x7C, "Schwarzpulver" },
+ { 0x7D, "Sch\x81ssel" },
+ { 0x7F, "Schwefel" },
+ { 0x80, "Hanfseil" },
+ { 0x81, "Hanfschnur" },
+ { 0x83, "Socken" },
+ { 0x84, "Spachtel" },
+ { 0x85, "Holzente" },
+ { 0x87, "Tasse" },
+ { 0x88, "Tasse" },
+ { 0x89, "Teig" },
+ { 0x8C, "Wolle" },
+ { 0x8E, "Holzw\x81rfel" },
+ { 0x8F, "Brief" },
+};
+
static void activeHotspotTable(const SceneHotspotNameEntry *&table, uint &count) {
if (g_engine && g_engine->isDemo()) {
table = kSceneHotspotNamesDemo;
@@ -547,6 +788,35 @@ static void activeHotspotTable(const SceneHotspotNameEntry *&table, uint &count)
}
}
+static void activeObjectNameTable(const ObjectNameEntry *&table, uint &count) {
+ if (g_engine && g_engine->isDemo()) {
+ table = kObjectNamesDemo;
+ count = ARRAYSIZE(kObjectNamesDemo);
+ } else {
+ table = kObjectNames;
+ count = ARRAYSIZE(kObjectNames);
+ }
+}
+
+Common::String lookupObjectHotspotName(uint16 objectIndex) {
+ if (objectIndex == 0)
+ return Common::String();
+ if (g_engine && !g_engine->isV1())
+ return Common::String();
+
+ const ObjectNameEntry *table;
+ uint tableCount;
+ activeObjectNameTable(table, tableCount);
+ for (uint i = 0; i < tableCount; ++i) {
+ if (table[i].objectIndex == objectIndex) {
+ if (g_engine)
+ return g_engine->translateHotspotLabel(table[i].name);
+ return table[i].name;
+ }
+ }
+ return Common::String();
+}
+
Common::String lookupSceneHotspotName(uint16 sceneIndex, uint16 hotspotIndex) {
const SceneHotspotNameEntry *table;
uint tableCount;
diff --git a/engines/macs2/hotspot_names.h b/engines/macs2/hotspot_names.h
index 5d44c883aed..a6eb7e0ded3 100644
--- a/engines/macs2/hotspot_names.h
+++ b/engines/macs2/hotspot_names.h
@@ -28,6 +28,7 @@
namespace Macs2 {
Common::String lookupSceneHotspotName(uint16 sceneIndex, uint16 hotspotIndex);
+Common::String lookupObjectHotspotName(uint16 objectIndex);
Graphics::HotspotType lookupSceneHotspotType(uint16 sceneIndex, uint16 hotspotIndex);
} // namespace Macs2
diff --git a/engines/macs2/macs2.cpp b/engines/macs2/macs2.cpp
index 3f3bd88a5f4..5134fb45074 100644
--- a/engines/macs2/macs2.cpp
+++ b/engines/macs2/macs2.cpp
@@ -852,7 +852,7 @@ Macs2Engine::~Macs2Engine() {
}
#ifdef USE_TTS
-// Object indices and names match GameObjects::init / isNpcIndex.
+// Object indices and names match lookupObjectHotspotName / isNpcIndex.
// voiceId is reused for the same person (Tramp, Winnetou).
struct TTSSpeakerVoice {
uint16 objectIndex;
@@ -2625,14 +2625,7 @@ uint16 Macs2Engine::getHotspotAtPoint(const Common::Point &p) const {
}
Common::String getObjectHotspotName(uint16 objectIndex) {
- const GameObjects &objects = GameObjects::instance();
- if (objectIndex > 0 && objectIndex < objects._objectNames.size() && !objects._objectNames[objectIndex].empty()) {
- if (g_engine != nullptr) {
- return g_engine->translateHotspotLabel(objects._objectNames[objectIndex]);
- }
- return objects._objectNames[objectIndex];
- }
- return Common::String();
+ return lookupObjectHotspotName(objectIndex);
}
Common::String lookupInteractionDisplayName(uint16 interactionId) {
@@ -3507,7 +3500,6 @@ void Macs2Engine::setGameSpeedMode(uint16 mode) {
}
Common::Error Macs2Engine::run() {
- GameObjects::instance().init();
setGameSpeedMode(ConfMan.getInt(kGameSpeedModeConfigKey));
loadBootstrapResources();
readExecutable();
diff --git a/engines/macs2/view1.cpp b/engines/macs2/view1.cpp
index 4732624815e..46b7fd4c09e 100644
--- a/engines/macs2/view1.cpp
+++ b/engines/macs2/view1.cpp
@@ -2385,7 +2385,7 @@ void View1::draw() {
GameObject *hoveredObject = getClickedInventoryItem(mousePos);
if (hoveredObject != nullptr) {
- Common::String name = GameObjects::instance()._objectNames[hoveredObject->_index];
+ Common::String name = getObjectHotspotName(hoveredObject->_index);
if (!name.empty()) {
renderString(mousePos.x + 20, mousePos.y + 20, name);
} else {
Commit: e2499efec78921f3068c6f1846f6687146df6784
https://github.com/scummvm/scummvm/commit/e2499efec78921f3068c6f1846f6687146df6784
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-09-02T18:04:13+02:00
Commit Message:
MACS2: translations are only supported for the full game
removed unknown detection entry for adjusted variant
Changed paths:
engines/macs2/detection_tables.h
diff --git a/engines/macs2/detection_tables.h b/engines/macs2/detection_tables.h
index 89a02b9d0c8..d6dd9f062d9 100644
--- a/engines/macs2/detection_tables.h
+++ b/engines/macs2/detection_tables.h
@@ -37,14 +37,6 @@ const ADGameDescription gameDescriptions[] = {
Common::kPlatformDOS,
ADGF_UNSTABLE,
GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TTS, GAMEOPTION_ENHANCEMENTS)},
- {"sis",
- nullptr,
- // Adjusted file
- AD_ENTRY1s("RESOURCE.MCS", "5a6cdeecdabae42872ab9278ab895bad", 8621636),
- Common::DE_DEU,
- Common::kPlatformDOS,
- ADGF_UNSTABLE,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TTS, GAMEOPTION_ENHANCEMENTS)},
// GMACS II Interpreter V1.00 - Written & Copyright (C) 1993 by Arndt Hasch - Copyright by LINEL
{"sis",
@@ -64,24 +56,6 @@ const ADGameDescription gameDescriptions[] = {
Common::kPlatformDOS,
GF_TRANSLATED | ADGF_UNSTABLE,
GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TTS, GAMEOPTION_ENHANCEMENTS)},
- {"sis",
- "w/translation",
- AD_ENTRY2s("RESOURCE.MCS", "5a6cdeecdabae42872ab9278ab895bad", 8621636,
- "macs2_translation.dat", nullptr, AD_NO_SIZE),
- Common::EN_ANY,
- Common::kPlatformDOS,
- GF_TRANSLATED | ADGF_UNSTABLE,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TTS, GAMEOPTION_ENHANCEMENTS)},
-
- // Demo - English fan translation
- {"sis",
- "Demo/w/translation",
- AD_ENTRY2s("RESOURCE.MCS", "779c5f7d11ac61b7b941ec0f1778d837", 2376278,
- "macs2_translation.dat", nullptr, AD_NO_SIZE),
- Common::EN_ANY,
- Common::kPlatformDOS,
- GF_TRANSLATED | ADGF_DEMO | ADGF_UNSTABLE,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TTS, GAMEOPTION_ENHANCEMENTS)},
// Amiga demo - DataA (MXMF) + Mdir (MXDR). GMACS II / LINEL.
{"sis",
@@ -93,17 +67,6 @@ const ADGameDescription gameDescriptions[] = {
ADGF_DEMO | ADGF_UNSTABLE,
GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TTS, GAMEOPTION_ENHANCEMENTS)},
- // Amiga demo - English fan translation
- {"sis",
- "Demo/w/translation",
- AD_ENTRY3s("DataA", "30ce5b1b30f7ef60f412c0475a25b0cb", 736670,
- "Mdir", "269f4c31a50395e3ec6ae69b86e426bd", 598,
- "macs2_translation.dat", nullptr, AD_NO_SIZE),
- Common::EN_ANY,
- Common::kPlatformAmiga,
- GF_TRANSLATED | ADGF_DEMO | ADGF_UNSTABLE,
- GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_TTS, GAMEOPTION_ENHANCEMENTS)},
-
AD_TABLE_END_MARKER};
} // End of namespace Macs2
More information about the Scummvm-git-logs
mailing list