[Scummvm-git-logs] scummvm master -> 69be41bc2e05081d8889483c18989a8a82099d35
neuromancer
noreply at scummvm.org
Wed Mar 25 20:27:15 UTC 2026
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
f71240750d FREESCAPE: implemented temporary messages in castle for amiga/atari
eb35932c37 FREESCAPE: fixed original typos in castle dos spanish
4098630c93 FREESCAPE: avoid crash in castle zx
2813abb296 FREESCAPE: better touchscreen integration and debug code
0c102e65e2 FREESCAPE: added pos and area commands into the debugger
69be41bc2e FREESCAPE: presort by distance from camera (furthest first) to provide a stable initial ordering in depth computation
Commit: f71240750d183d98a21ed296de2c625ff459d706
https://github.com/scummvm/scummvm/commit/f71240750d183d98a21ed296de2c625ff459d706
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-25T21:12:21+01:00
Commit Message:
FREESCAPE: implemented temporary messages in castle for amiga/atari
Changed paths:
engines/freescape/games/castle/amiga.cpp
engines/freescape/games/castle/castle.cpp
engines/freescape/games/castle/castle.h
engines/freescape/games/castle/dos.cpp
diff --git a/engines/freescape/games/castle/amiga.cpp b/engines/freescape/games/castle/amiga.cpp
index 1d51207ba19..6e6795138a4 100644
--- a/engines/freescape/games/castle/amiga.cpp
+++ b/engines/freescape/games/castle/amiga.cpp
@@ -474,9 +474,30 @@ void CastleEngine::drawAmigaAtariSTUI(Graphics::Surface *surface) {
drawLiftingGate(surface);
drawDroppingGate(surface);
- drawStringInSurface(_currentArea->_name, 97, 182, 0, 0, surface);
+ uint8 r, g, b;
+ _gfx->readFromPalette(15, r, g, b);
+ uint32 front = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b);
uint32 black = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0x00, 0x00, 0x00);
+ Common::Rect backRect(97, 181, 232, 190);
+ surface->fillRect(backRect, black);
+
+ Common::String message;
+ int deadline = -1;
+ getLatestMessages(message, deadline);
+ if (deadline > 0 && deadline <= _countdown) {
+ drawStringInSurface(message, 97, 182, front, black, surface);
+ _temporaryMessages.push_back(message);
+ _temporaryMessageDeadlines.push_back(deadline);
+ } else {
+ if (_gameStateControl != kFreescapeGameStateEnd) {
+ if (ghostInArea())
+ drawStringInSurface(_ghostInAreaMessage, 97, 182, front, black, surface);
+ else
+ drawStringInSurface(_currentArea->_name, 97, 182, front, black, surface);
+ }
+ }
+
// TODO: Draw collected keys - key sprites location in binary still unknown
// Draw flag animation at (288, 5)
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index c28eea204bc..46ea7687a0c 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -59,6 +59,8 @@ CastleEngine::CastleEngine(OSystem *syst, const ADGameDescription *gd) : Freesca
else if (isCPC())
initCPC();
+ // Messages are assigned after loading in initGameState()
+
_playerHeightNumber = 1;
_playerHeightMaxNumber = 1;
_lastTenSeconds = -1;
@@ -676,6 +678,23 @@ void CastleEngine::initGameState() {
FreescapeEngine::initGameState();
_playerHeightNumber = 1;
+ // Platform-specific message strings (indices differ between DOS and Amiga)
+ if (isAmiga() || isAtariST()) {
+ _notEnoughRoomMessage = _messagesList[21];
+ _tooWeakMessage = _messagesList[22];
+ _crawlSelectedMessage = _messagesList[23];
+ _walkSelectedMessage = _messagesList[24];
+ _runSelectedMessage = _messagesList[25];
+ _ghostInAreaMessage = _messagesList[126];
+ } else {
+ _notEnoughRoomMessage = _messagesList[11];
+ _tooWeakMessage = _messagesList[12];
+ _crawlSelectedMessage = _messagesList[13];
+ _walkSelectedMessage = _messagesList[14];
+ _runSelectedMessage = _messagesList[15];
+ _ghostInAreaMessage = _messagesList[116];
+ }
+
_gameStateVars[k8bitVariableShield] = 16;
_gameStateVars[k8bitVariableEnergy] = 1;
_gameStateVars[8] = 128; // -1
@@ -750,30 +769,30 @@ void CastleEngine::pressedKey(const int keycode) {
} else if (keycode == kActionRunMode) {
if (_playerHeightNumber == 0) {
if (_gameStateVars[k8bitVariableShield] <= 3) {
- insertTemporaryMessage(_messagesList[12], _countdown - 2);
+ insertTemporaryMessage(_tooWeakMessage, _countdown - 2);
return;
}
if (!rise()) {
_playerStepIndex = 0;
- insertTemporaryMessage(_messagesList[11], _countdown - 2);
+ insertTemporaryMessage(_notEnoughRoomMessage, _countdown - 2);
return;
}
_gameStateVars[k8bitVariableCrawling] = 0;
}
// TODO: raising can fail if there is no room, so the action should fail
_playerStepIndex = 2;
- insertTemporaryMessage(_messagesList[15], _countdown - 2);
+ insertTemporaryMessage(_runSelectedMessage, _countdown - 2);
} else if (keycode == kActionWalkMode) {
if (_playerHeightNumber == 0) {
if (_gameStateVars[k8bitVariableShield] <= 3) {
- insertTemporaryMessage(_messagesList[12], _countdown - 2);
+ insertTemporaryMessage(_tooWeakMessage, _countdown - 2);
return;
}
if (!rise()) {
_playerStepIndex = 0;
- insertTemporaryMessage(_messagesList[11], _countdown - 2);
+ insertTemporaryMessage(_notEnoughRoomMessage, _countdown - 2);
return;
}
_gameStateVars[k8bitVariableCrawling] = 0;
@@ -781,14 +800,14 @@ void CastleEngine::pressedKey(const int keycode) {
// TODO: raising can fail if there is no room, so the action should fail
_playerStepIndex = 1;
- insertTemporaryMessage(_messagesList[14], _countdown - 2);
+ insertTemporaryMessage(_walkSelectedMessage, _countdown - 2);
} else if (keycode == kActionCrawlMode) {
if (_playerHeightNumber == 1) {
lower();
_gameStateVars[k8bitVariableCrawling] = 128;
}
_playerStepIndex = 0;
- insertTemporaryMessage(_messagesList[13], _countdown - 2);
+ insertTemporaryMessage(_crawlSelectedMessage, _countdown - 2);
} else if (keycode == kActionRunModifier) {
// Shift-to-run: save current mode, switch to run while held
if (_playerStepIndex == 2)
@@ -1343,6 +1362,9 @@ void CastleEngine::executePrint(FCLInstruction &instruction) {
drawFullscreenRiddleAndWait(index);
return;
}
+ if (isAmiga() || isAtariST()) {
+ index = index + 10;
+ }
debugC(1, kFreescapeDebugCode, "Printing message %d: \"%s\"", index, _messagesList[index].c_str());
insertTemporaryMessage(_messagesList[index], _countdown - 3);
}
diff --git a/engines/freescape/games/castle/castle.h b/engines/freescape/games/castle/castle.h
index 207c0ec9b5f..8a0d150b367 100644
--- a/engines/freescape/games/castle/castle.h
+++ b/engines/freescape/games/castle/castle.h
@@ -158,6 +158,13 @@ public:
Common::Array<Graphics::ManagedSurface *> loadFramesWithHeaderCPCIndexed(Common::SeekableReadStream *file, int pos, int numFrames);
void updateCPCSpritesPalette();
+ Common::String _notEnoughRoomMessage;
+ Common::String _tooWeakMessage;
+ Common::String _crawlSelectedMessage;
+ Common::String _walkSelectedMessage;
+ Common::String _runSelectedMessage;
+ Common::String _ghostInAreaMessage;
+
Common::Array<byte> _modData; // Embedded ProTracker module (Amiga demo)
Common::Array<int> _keysCollected;
bool _useRockTravel;
diff --git a/engines/freescape/games/castle/dos.cpp b/engines/freescape/games/castle/dos.cpp
index 19bccb8e23f..19c543f8e2f 100644
--- a/engines/freescape/games/castle/dos.cpp
+++ b/engines/freescape/games/castle/dos.cpp
@@ -466,7 +466,7 @@ void CastleEngine::drawDOSUI(Graphics::Surface *surface) {
} else {
if (_gameStateControl != kFreescapeGameStateEnd) {
if (ghostInArea())
- drawStringInSurface(_messagesList[116], 97, 182, front, back, surface);
+ drawStringInSurface(_ghostInAreaMessage, 97, 182, front, back, surface);
else
drawStringInSurface(_currentArea->_name, 97, 182, front, back, surface);
}
Commit: eb35932c375cecc1abdbcc518337f19e965e0811
https://github.com/scummvm/scummvm/commit/eb35932c375cecc1abdbcc518337f19e965e0811
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-25T21:12:21+01:00
Commit Message:
FREESCAPE: fixed original typos in castle dos spanish
Changed paths:
engines/freescape/games/castle/castle.cpp
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index 46ea7687a0c..44eaa4cf2c3 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -695,6 +695,14 @@ void CastleEngine::initGameState() {
_ghostInAreaMessage = _messagesList[116];
}
+ // Fix typos in the original Spanish releases
+ if (_language == Common::ES_ESP) {
+ for (uint i = 0; i < _messagesList.size(); i++) {
+ Common::replace(_messagesList[i], "ELIGIDO", "ELEGIDO");
+ Common::replace(_messagesList[i], "BRILLIANTE", "BRILLANTE");
+ }
+ }
+
_gameStateVars[k8bitVariableShield] = 16;
_gameStateVars[k8bitVariableEnergy] = 1;
_gameStateVars[8] = 128; // -1
Commit: 4098630c938652503f5e57bd83415f69d8da2092
https://github.com/scummvm/scummvm/commit/4098630c938652503f5e57bd83415f69d8da2092
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-25T21:12:21+01:00
Commit Message:
FREESCAPE: avoid crash in castle zx
Changed paths:
engines/freescape/games/castle/castle.cpp
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index 44eaa4cf2c3..11d6ade40d7 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -686,13 +686,21 @@ void CastleEngine::initGameState() {
_walkSelectedMessage = _messagesList[24];
_runSelectedMessage = _messagesList[25];
_ghostInAreaMessage = _messagesList[126];
- } else {
+ } else if (isDOS()) {
_notEnoughRoomMessage = _messagesList[11];
_tooWeakMessage = _messagesList[12];
_crawlSelectedMessage = _messagesList[13];
_walkSelectedMessage = _messagesList[14];
_runSelectedMessage = _messagesList[15];
_ghostInAreaMessage = _messagesList[116];
+ } else {
+ // ZX/CPC: same indices for movement messages, no ghost warning message
+ _notEnoughRoomMessage = _messagesList[11];
+ _tooWeakMessage = _messagesList[12];
+ _crawlSelectedMessage = _messagesList[13];
+ _walkSelectedMessage = _messagesList[14];
+ _runSelectedMessage = _messagesList[15];
+ _ghostInAreaMessage = "";
}
// Fix typos in the original Spanish releases
Commit: 2813abb296f601945befb1103c8bf9ef9352f2e6
https://github.com/scummvm/scummvm/commit/2813abb296f601945befb1103c8bf9ef9352f2e6
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-25T21:12:21+01:00
Commit Message:
FREESCAPE: better touchscreen integration and debug code
Changed paths:
engines/freescape/freescape.cpp
engines/freescape/freescape.h
engines/freescape/games/castle/castle.cpp
engines/freescape/games/driller/driller.cpp
engines/freescape/ui.cpp
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index d8ee03c26bc..d97a10aa3de 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -135,6 +135,8 @@ FreescapeEngine::FreescapeEngine(OSystem *syst, const ADGameDescription *gd)
if (ConfMan.hasKey("wasd_controls"))
Common::parseBool(ConfMan.get("wasd_controls"), _useWASDControls);
+ _debugSimulateTouchscreen = ConfMan.hasKey("debug_touchscreen") && ConfMan.getBool("debug_touchscreen");
+
if (isDriller() || isSpaceStationOblivion() || isDark())
_smoothMovement = false;
@@ -280,6 +282,10 @@ FreescapeEngine::FreescapeEngine(OSystem *syst, const ADGameDescription *gd)
setDebugger(g_debugger);
}
+bool FreescapeEngine::isTouchscreenActive() const {
+ return _debugSimulateTouchscreen || g_system->hasFeature(OSystem::kFeatureTouchscreen);
+}
+
FreescapeEngine::~FreescapeEngine() {
removeTimers();
delete _rnd;
@@ -843,13 +849,8 @@ Common::Error FreescapeEngine::run() {
loadAssets();
loadColorPalette();
- if (g_system->getFeatureState(OSystem::kFeatureTouchscreen)) {
- g_system->showMouse(true);
- g_system->lockMouse(false);
- } else {
- g_system->showMouse(false);
- g_system->lockMouse(true);
- }
+ g_system->showMouse(false);
+ g_system->lockMouse(true);
// Simple main event loop
int saveSlot = ConfMan.getInt("save_slot");
diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h
index 6f191661109..61ad126f2a4 100644
--- a/engines/freescape/freescape.h
+++ b/engines/freescape/freescape.h
@@ -354,6 +354,8 @@ public:
bool _smoothMovement;
bool _useWASDControls;
+ bool _debugSimulateTouchscreen;
+ bool isTouchscreenActive() const;
// Player movement state
bool _moveForward;
bool _moveBackward;
diff --git a/engines/freescape/games/castle/castle.cpp b/engines/freescape/games/castle/castle.cpp
index 11d6ade40d7..4ba98a56eda 100644
--- a/engines/freescape/games/castle/castle.cpp
+++ b/engines/freescape/games/castle/castle.cpp
@@ -1574,7 +1574,7 @@ void CastleEngine::drawFullscreenRiddleAndWait(uint16 riddle) {
case Common::EVENT_RBUTTONDOWN:
// fallthrough
case Common::EVENT_LBUTTONDOWN:
- if (g_system->hasFeature(OSystem::kFeatureTouchscreen))
+ if (isTouchscreenActive())
cont = false;
break;
default:
@@ -1994,10 +1994,47 @@ void CastleEngine::selectCharacterScreen() {
drawFullscreenSurface(surface);
}
+ if (isTouchscreenActive()) {
+ CursorMan.setDefaultArrowCursor();
+ CursorMan.showMouse(true);
+ }
_system->lockMouse(false);
_system->showMouse(true);
- Common::Rect princeSelector(82, 100, 163, 109);
- Common::Rect princessSelector(82, 110, 181, 120);
+
+ // Calculate tap/click rectangles from actual rendered text positions.
+ // lines[5] = prince, lines[6] = princess for ZX/CPC.
+ // For DOS, use riddle text line positions.
+ Common::Rect princeSelector, princessSelector;
+ if (isSpectrum() || isCPC()) {
+ int x = _viewArea.left + 3;
+ int lineHeight = 12; // Castle Master line spacing in drawStringsInSurface
+ int princeY = _viewArea.top + 3 + 5 * lineHeight;
+ int princessY = _viewArea.top + 3 + 6 * lineHeight;
+ // Use the full padded line (what's actually rendered on screen)
+ princeSelector = _font.getBoundingBox(lines[5], x, princeY);
+ princessSelector = _font.getBoundingBox(lines[6], x, princessY);
+ } else {
+ // DOS: text comes from _riddleList[21], calculate from actual riddle line positions
+ Common::Array<RiddleText> selectMessage = _riddleList[21]._lines;
+ int x = 0, y = 0;
+ for (int i = 0; i < int(selectMessage.size()); i++) {
+ x += selectMessage[i]._dx;
+ y += selectMessage[i]._dy;
+ if (i == int(selectMessage.size()) - 2)
+ princeSelector = _font.getBoundingBox(selectMessage[i]._text, x, y);
+ else if (i == int(selectMessage.size()) - 1)
+ princessSelector = _font.getBoundingBox(selectMessage[i]._text, x, y);
+ }
+ }
+
+ // On touchscreen, highlight the tap areas with red outlines (expand 1px for readability)
+ princeSelector.grow(1);
+ princessSelector.grow(1);
+ if (isTouchscreenActive()) {
+ uint32 red = _gfx->_texturePixelFormat.ARGBToColor(0xFF, 0xFF, 0x00, 0x00);
+ surface->frameRect(princeSelector, red);
+ surface->frameRect(princessSelector, red);
+ }
bool selected = false;
while (!selected) {
@@ -2010,7 +2047,7 @@ void CastleEngine::selectCharacterScreen() {
quitGame();
return;
- // Left mouse click
+ // Left mouse click or touchscreen tap
case Common::EVENT_LBUTTONDOWN:
// fallthrough
case Common::EVENT_RBUTTONDOWN:
@@ -2057,6 +2094,7 @@ void CastleEngine::selectCharacterScreen() {
}
_system->lockMouse(true);
_system->showMouse(false);
+ CursorMan.showMouse(false);
_gfx->clear(0, 0, 0, true);
}
diff --git a/engines/freescape/games/driller/driller.cpp b/engines/freescape/games/driller/driller.cpp
index fa4691b37a5..0075625553c 100644
--- a/engines/freescape/games/driller/driller.cpp
+++ b/engines/freescape/games/driller/driller.cpp
@@ -474,7 +474,7 @@ void DrillerEngine::drawInfoMenu() {
case Common::EVENT_RBUTTONDOWN:
// fallthrough
case Common::EVENT_LBUTTONDOWN:
- if (g_system->hasFeature(OSystem::kFeatureTouchscreen))
+ if (isTouchscreenActive())
cont = false;
break;
default:
diff --git a/engines/freescape/ui.cpp b/engines/freescape/ui.cpp
index d4712ff1898..eff56e7b54a 100644
--- a/engines/freescape/ui.cpp
+++ b/engines/freescape/ui.cpp
@@ -130,7 +130,7 @@ void FreescapeEngine::titleScreen() {
case Common::EVENT_RBUTTONDOWN:
// fallthrough
case Common::EVENT_LBUTTONDOWN:
- if (g_system->hasFeature(OSystem::kFeatureTouchscreen))
+ if (isTouchscreenActive())
maxWait = -1;
break;
default:
@@ -337,7 +337,7 @@ void FreescapeEngine::drawBorderScreenAndWait(Graphics::Surface *surface, int ma
case Common::EVENT_RBUTTONDOWN:
// fallthrough
case Common::EVENT_LBUTTONDOWN:
- if (g_system->hasFeature(OSystem::kFeatureTouchscreen))
+ if (isTouchscreenActive())
maxWait = -1;
break;
default:
Commit: 0c102e65e2cb375b3d3d4156900a7d4b7714a655
https://github.com/scummvm/scummvm/commit/0c102e65e2cb375b3d3d4156900a7d4b7714a655
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-25T21:12:21+01:00
Commit Message:
FREESCAPE: added pos and area commands into the debugger
Changed paths:
engines/freescape/area.h
engines/freescape/debugger.cpp
engines/freescape/debugger.h
diff --git a/engines/freescape/area.h b/engines/freescape/area.h
index 30d5406fb55..fba98d02378 100644
--- a/engines/freescape/area.h
+++ b/engines/freescape/area.h
@@ -51,6 +51,8 @@ public:
ObjectArray getSensors();
uint16 getAreaID();
Common::Array<Object *> &getSortedObjects() { return _sortedObjects; }
+ ObjectMap *getObjectsByID() { return _objectsByID; }
+ ObjectMap *getEntrancesByID() { return _entrancesByID; }
uint16 getAreaFlags();
uint8 getScale();
void remapColor(int index, int color);
diff --git a/engines/freescape/debugger.cpp b/engines/freescape/debugger.cpp
index 7f05fa6433e..15dd7d0bff9 100644
--- a/engines/freescape/debugger.cpp
+++ b/engines/freescape/debugger.cpp
@@ -42,6 +42,8 @@ Debugger::Debugger(FreescapeEngine *vm) : GUI::Debugger(), _vm(vm) {
registerCmd("goto", WRAP_METHOD(Debugger, cmdGoto)); // teleport to a position
registerCmd("sort_order", WRAP_METHOD(Debugger, cmdSortOrder)); // print current draw order of objects
registerCmd("occ", WRAP_METHOD(Debugger, cmdShowOcclusion)); // toggle occlussion boxes
+ registerCmd("area", WRAP_METHOD(Debugger, cmdArea)); // show current area info
+ registerCmd("pos", WRAP_METHOD(Debugger, cmdPos)); // show camera position and direction
}
Debugger::~Debugger() {}
@@ -184,8 +186,8 @@ bool Debugger::cmdSortOrder(int argc, const char** argv) {
Common::Array<Object *> &objs = _vm->_currentArea->getSortedObjects();
- debugPrintf("Current Draw Order:\n");
- debugPrintf("Total Objects: %d\n", objs.size());
+ debugPrintf("Draw order (back-to-front, first drawn first):\n");
+ debugPrintf("Total visible objects: %d\n", objs.size());
for (uint i = 0; i < objs.size(); i++) {
Object *obj = objs[i];
debugPrintf("%d ", obj->getObjectID());
@@ -203,4 +205,86 @@ bool Debugger::cmdShowOcclusion(int argc, const char **argv) {
return true;
}
+static const char *objectTypeNames[] = {
+ "Entrance",
+ "Cube",
+ "Sensor",
+ "Rectangle",
+ "EastPyramid",
+ "WestPyramid",
+ "UpPyramid",
+ "DownPyramid",
+ "NorthPyramid",
+ "SouthPyramid",
+ "Line",
+ "Triangle",
+ "Quadrilateral",
+ "Pentagon",
+ "Hexagon",
+ "Group"
+};
+
+bool Debugger::cmdArea(int argc, const char **argv) {
+ if (!_vm->_currentArea) {
+ debugPrintf("No area loaded.\n");
+ return true;
+ }
+
+ Area *area = _vm->_currentArea;
+ debugPrintf("Area ID: %d\n", area->getAreaID());
+ debugPrintf("Area name: %s\n", area->_name.c_str());
+ debugPrintf("Area flags: %04x\n", area->getAreaFlags());
+ debugPrintf("Scale: %d\n", area->getScale());
+ debugPrintf("Sky color: %d | Ground color: %d\n", area->_skyColor, area->_groundColor);
+ debugPrintf("Ink: %d | Paper: %d\n", area->_inkColor, area->_paperColor);
+ debugPrintf("Color cycling: %s\n", area->_colorCycling ? "yes" : "no");
+ debugPrintf("Outside: %s\n", area->isOutside() ? "yes" : "no");
+ debugPrintf("\n");
+
+ ObjectMap *objectsByID = area->getObjectsByID();
+ debugPrintf("Objects (%d):\n", objectsByID->size());
+ for (auto &it : *objectsByID) {
+ Object *obj = it._value;
+ int type = obj->getType();
+ const char *typeName = (type >= 0 && type <= 15) ? objectTypeNames[type] : "Unknown";
+ debugPrintf(" ID: %3d | Type: %-14s | Flags: %04x", obj->getObjectID(), typeName, obj->getObjectFlags());
+ if (obj->isInvisible()) {
+ debugPrintf(" [invisible]");
+ }
+ if (obj->isDestroyed()) {
+ debugPrintf(" [destroyed]");
+ }
+ if (obj->isGeometric()) {
+ Math::Vector3d origin = obj->getOrigin();
+ Math::Vector3d size = obj->getSize();
+ debugPrintf(" | Pos: (%.0f, %.0f, %.0f) Size: (%.0f, %.0f, %.0f)",
+ origin.x(), origin.y(), origin.z(),
+ size.x(), size.y(), size.z());
+ }
+ debugPrintf("\n");
+ }
+
+ ObjectMap *entrancesByID = area->getEntrancesByID();
+ if (entrancesByID->size() > 0) {
+ debugPrintf("\nEntrances (%d):\n", entrancesByID->size());
+ for (auto &it : *entrancesByID) {
+ Object *obj = it._value;
+ Math::Vector3d origin = obj->getOrigin();
+ debugPrintf(" ID: %3d | Pos: (%.0f, %.0f, %.0f)\n",
+ obj->getObjectID(), origin.x(), origin.y(), origin.z());
+ }
+ }
+
+ return true;
+}
+
+bool Debugger::cmdPos(int argc, const char **argv) {
+ Math::Vector3d pos = _vm->_position;
+ Math::Vector3d front = _vm->_cameraFront;
+ debugPrintf("Position: (%.2f, %.2f, %.2f)\n", pos.x(), pos.y(), pos.z());
+ debugPrintf("Direction: (%.2f, %.2f, %.2f)\n", front.x(), front.y(), front.z());
+ debugPrintf("Yaw: %.2f | Pitch: %.2f | Roll: %d\n", _vm->_yaw, _vm->_pitch, _vm->_roll);
+ return true;
+}
+
}
diff --git a/engines/freescape/debugger.h b/engines/freescape/debugger.h
index 1c7c549e166..fd10ae47d33 100644
--- a/engines/freescape/debugger.h
+++ b/engines/freescape/debugger.h
@@ -46,6 +46,8 @@ private:
bool cmdSetObjPos(int argc, const char **argv);
bool cmdSortOrder(int argc, const char **argv);
bool cmdShowOcclusion(int argc, const char **argv);
+ bool cmdArea(int argc, const char **argv);
+ bool cmdPos(int argc, const char **argv);
};
}
Commit: 69be41bc2e05081d8889483c18989a8a82099d35
https://github.com/scummvm/scummvm/commit/69be41bc2e05081d8889483c18989a8a82099d35
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-25T21:12:21+01:00
Commit Message:
FREESCAPE: presort by distance from camera (furthest first) to provide a stable initial ordering in depth computation
Changed paths:
engines/freescape/area.cpp
diff --git a/engines/freescape/area.cpp b/engines/freescape/area.cpp
index e25e31cffc0..cfa95dd4fbc 100644
--- a/engines/freescape/area.cpp
+++ b/engines/freescape/area.cpp
@@ -327,6 +327,17 @@ void Area::draw(Freescape::Renderer *gfx, uint32 animationTicks, Math::Vector3d
// It is only applied to the vertices during the projection phase (L850f/L9177).
int n = _sortedObjects.size();
if (n > 1 && sort) {
+ // Pre-sort by distance from camera (furthest first) to provide a stable initial
+ // ordering for the non-transitive bubble sort below. The original game achieves
+ // this by culling off-screen objects via a rendering volume check (L8bb7/L845b)
+ // before sorting, which prevents distant off-screen objects from interfering with
+ // the depth ordering of visible objects through non-transitive comparisons.
+ Common::sort(_sortedObjects.begin(), _sortedObjects.end(),
+ [&camera](Object *a, Object *b) {
+ Math::Vector3d centerA = (a->_occlusionBox.getMin() + a->_occlusionBox.getMax()) * 0.5f;
+ Math::Vector3d centerB = (b->_occlusionBox.getMin() + b->_occlusionBox.getMax()) * 0.5f;
+ return (centerA - camera).getSquareMagnitude() > (centerB - camera).getSquareMagnitude();
+ });
for (int i = 0; i < n; i++) { // L9c31_whole_object_pass_loop
bool changed = false;
for (int j = 0; j < n - 1; j++) { // L9c45_objects_loop
More information about the Scummvm-git-logs
mailing list