[Scummvm-git-logs] scummvm master -> 650a9dc492010bfdcdead40502b06ea4c3c2f8ed

neuromancer noreply at scummvm.org
Tue Mar 31 09:18:08 UTC 2026


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

Summary:
6f8aa6d186 FREESCAPE: cannot rest in the desert
e27a0be75d FREESCAPE: eclipse ending fixes and commands to easily reach it
43c9390cd3 FREESCAPE: avoid UB in Renderer::getRGBAtCPC
650a9dc492 FREESCAPE: show indicators in the correct color in eclipse cpc


Commit: 6f8aa6d18613ed116be617a5e4d6bd1ec7cacdcd
    https://github.com/scummvm/scummvm/commit/6f8aa6d18613ed116be617a5e4d6bd1ec7cacdcd
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-31T11:17:32+02:00

Commit Message:
FREESCAPE: cannot rest in the desert

Changed paths:
    engines/freescape/games/eclipse/eclipse.cpp


diff --git a/engines/freescape/games/eclipse/eclipse.cpp b/engines/freescape/games/eclipse/eclipse.cpp
index dc74dcebb30..feba68ffb94 100644
--- a/engines/freescape/games/eclipse/eclipse.cpp
+++ b/engines/freescape/games/eclipse/eclipse.cpp
@@ -555,7 +555,7 @@ void EclipseEngine::pressedKey(const int keycode) {
 		else
 			error("Invalid player height index: %d", _playerHeightNumber);
 	} else if (keycode == kActionRest) {
-		if (_currentArea->getAreaID() == 1) {
+		if (_currentArea->getAreaID() == 1 || _currentArea->getAreaID() == 51) {
 			playSoundFx(3, false);
 			if (_temporaryMessages.empty())
 				insertTemporaryMessage(_messagesList[6], _countdown - 2);


Commit: e27a0be75ddae7ebf1eda026d9b0231ff262aa56
    https://github.com/scummvm/scummvm/commit/e27a0be75ddae7ebf1eda026d9b0231ff262aa56
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-31T11:17:32+02:00

Commit Message:
FREESCAPE: eclipse ending fixes and commands to easily reach it

Changed paths:
    engines/freescape/debugger.cpp
    engines/freescape/debugger.h
    engines/freescape/language/instruction.cpp
    engines/freescape/movement.cpp


diff --git a/engines/freescape/debugger.cpp b/engines/freescape/debugger.cpp
index 47b58d3199f..d9cac80416c 100644
--- a/engines/freescape/debugger.cpp
+++ b/engines/freescape/debugger.cpp
@@ -21,6 +21,7 @@
 
 #include "freescape/debugger.h"
 #include "freescape/freescape.h"
+#include "freescape/games/eclipse/eclipse.h"
 #include "freescape/gfx.h"
 #include "freescape/objects/object.h"
 #include "freescape/area.h"
@@ -39,12 +40,13 @@ Debugger::Debugger(FreescapeEngine *vm) : GUI::Debugger(), _vm(vm) {
 	registerCmd("iso", WRAP_METHOD(Debugger, cmdHighlightID)); // isolate object
 	registerCmd("obj_pos", WRAP_METHOD(Debugger, cmdObjPos)); // get object pos
 	registerCmd("obj_mov", WRAP_METHOD(Debugger, cmdSetObjPos)); // move object
-	registerCmd("goto", WRAP_METHOD(Debugger, cmdGoto)); // teleport to a position
+	registerCmd("goto", WRAP_METHOD(Debugger, cmdGoto)); // teleport to area/entrance or 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
 	registerCmd("win", WRAP_METHOD(Debugger, cmdWin)); // trigger the current game's win condition
+	registerCmd("ankh", WRAP_METHOD(Debugger, cmdAnkh)); // set ankh count (Total Eclipse only)
 }
 
 Debugger::~Debugger() {}
@@ -167,15 +169,25 @@ bool Debugger::cmdSetObjPos(int argc, const char **argv) {
 }
 
 bool Debugger::cmdGoto(int argc, const char **argv) {
-	if (argc < 4) {
-		debugPrintf("Usage: goto <x> <y> <z>\n");
+	if (argc == 3) {
+		uint16 areaID = atoi(argv[1]);
+		int entranceID = atoi(argv[2]);
+		_vm->gotoArea(areaID, entranceID);
+		debugPrintf("Jumped to area %d, entrance %d\n", areaID, entranceID);
 		return true;
 	}
-	float x = atof(argv[1]);
-	float y = atof(argv[2]);
-	float z = atof(argv[3]);
-	_vm->_position = Math::Vector3d(x, y, z);
-	debugPrintf("Teleported to %f %f %f\n", x, y, z);
+
+	if (argc >= 4) {
+		float x = atof(argv[1]);
+		float y = atof(argv[2]);
+		float z = atof(argv[3]);
+		_vm->_position = Math::Vector3d(x, y, z);
+		debugPrintf("Teleported to %f %f %f\n", x, y, z);
+		return true;
+	}
+
+	debugPrintf("Usage: goto <area> <entrance>\n");
+	debugPrintf("       goto <x> <y> <z>\n");
 	return true;
 }
 
@@ -303,4 +315,22 @@ bool Debugger::cmdWin(int argc, const char **argv) {
 	return true;
 }
 
+bool Debugger::cmdAnkh(int argc, const char **argv) {
+	if (!_vm->isEclipse()) {
+		debugPrintf("This command is only available in Total Eclipse.\n");
+		return true;
+	}
+
+	if (argc < 2) {
+		debugPrintf("Current ankhs: %d\n", _vm->_gameStateVars[kVariableEclipseAnkhs]);
+		debugPrintf("Usage: ankh <count>\n");
+		return true;
+	}
+
+	int count = atoi(argv[1]);
+	_vm->_gameStateVars[kVariableEclipseAnkhs] = count;
+	debugPrintf("Ankhs set to %d\n", count);
+	return true;
+}
+
 }
diff --git a/engines/freescape/debugger.h b/engines/freescape/debugger.h
index 579a0e57649..8d66f3be8cd 100644
--- a/engines/freescape/debugger.h
+++ b/engines/freescape/debugger.h
@@ -49,6 +49,7 @@ private:
 	bool cmdArea(int argc, const char **argv);
 	bool cmdPos(int argc, const char **argv);
 	bool cmdWin(int argc, const char **argv);
+	bool cmdAnkh(int argc, const char **argv);
 };
 
 }
diff --git a/engines/freescape/language/instruction.cpp b/engines/freescape/language/instruction.cpp
index 6b2763dc616..a0457b18707 100644
--- a/engines/freescape/language/instruction.cpp
+++ b/engines/freescape/language/instruction.cpp
@@ -361,6 +361,9 @@ void FreescapeEngine::executeRedraw(FCLInstruction &instruction) {
 	if (isDriller() && (isSpectrum() || isCPC() || isC64()) && _gameStateVars[32] == 18)
 		delay = delay * 15; // Slow down redraws when the final cutscene is playing
 
+	if (isEclipse() && _currentArea->getAreaID() == 37 && getGameBit(6))
+		delay = delay * 10; // Slow down redraws in the final area of Eclipse
+
 	waitInLoop(delay);
 }
 
diff --git a/engines/freescape/movement.cpp b/engines/freescape/movement.cpp
index 49b65359ab2..a6fe607b099 100644
--- a/engines/freescape/movement.cpp
+++ b/engines/freescape/movement.cpp
@@ -347,6 +347,14 @@ bool FreescapeEngine::rise() {
 				changePlayerHeight(_playerHeightNumber);
 				if (!isCastle())
 					setGameBit(31);
+
+				Math::Ray ray(_position, _upVector);
+				Object *collidedUp = _currentArea->checkCollisionRay(ray, _playerHeight + 3);
+				if (collidedUp) {
+					GeometricObject *gobj = (GeometricObject *)collidedUp;
+					debugC(1, kFreescapeDebugMove, "Collided up with object id %d", gobj->getObjectID());
+					executeObjectConditions(gobj, false, true, false);
+				}
 			}
 		} else
 			result = true;


Commit: 43c9390cd3e1c3e068d0e0deef50819f5e56d8e0
    https://github.com/scummvm/scummvm/commit/43c9390cd3e1c3e068d0e0deef50819f5e56d8e0
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-31T11:17:32+02:00

Commit Message:
FREESCAPE: avoid UB in Renderer::getRGBAtCPC

Changed paths:
    engines/freescape/gfx.cpp


diff --git a/engines/freescape/gfx.cpp b/engines/freescape/gfx.cpp
index 0d8742d134b..d8172b7ad87 100644
--- a/engines/freescape/gfx.cpp
+++ b/engines/freescape/gfx.cpp
@@ -511,6 +511,18 @@ bool Renderer::getRGBAtCPC(uint8 index, uint8 &r1, uint8 &g1, uint8 &b1, uint8 &
 		return true;
 	}
 
+	if (index == 0 || index > 15) {
+		// Color indices outside the 1-15 stipple range are raw CPC ink
+		// values used for backgrounds. Read directly from the hardware
+		// palette instead of the stipple tables.
+		readFromPalette(index, r1, g1, b1);
+		r2 = r1;
+		g2 = g1;
+		b2 = b1;
+		stipple = nullptr;
+		return true;
+	}
+
 	stipple = (byte *)_stipples[index - 1];
 	byte pair = _colorPair[index - 1];
 	uint8 i1 = pair & 0xf;


Commit: 650a9dc492010bfdcdead40502b06ea4c3c2f8ed
    https://github.com/scummvm/scummvm/commit/650a9dc492010bfdcdead40502b06ea4c3c2f8ed
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-03-31T11:17:32+02:00

Commit Message:
FREESCAPE: show indicators in the correct color in eclipse cpc

Changed paths:
    engines/freescape/games/eclipse/cpc.cpp
    engines/freescape/games/eclipse/eclipse.cpp
    engines/freescape/games/eclipse/eclipse.h


diff --git a/engines/freescape/games/eclipse/cpc.cpp b/engines/freescape/games/eclipse/cpc.cpp
index 628a43e10aa..f7809096510 100644
--- a/engines/freescape/games/eclipse/cpc.cpp
+++ b/engines/freescape/games/eclipse/cpc.cpp
@@ -64,38 +64,20 @@ byte kCPCPaletteEclipseBorderData[4][3] = {
 
 
 void EclipseEngine::loadHeartFramesCPC(Common::SeekableReadStream *file, int restOffset, int beatOffset) {
-	// Decode into _eclipseSprites[0] (beat) and _eclipseSprites[1] (rest),
-	// matching the Atari ST convention for future unification.
-	// Uses loadFrameCPCIndexed (shared with Castle) for pixel decoding,
-	// then converts CLUT8→ARGB via convertImageFormatIfNecessary.
+	// Decode heart frames as indexed (CLUT8) pixel data.
+	// The actual palette is applied at draw time from the current area's
+	// ink/paper colors, since CPC pen assignments change per area.
 	int offsets[2] = { beatOffset, restOffset };
 
-	byte palette[4 * 3];
-	for (int c = 0; c < 4; c++) {
-		uint8 r, g, b;
-		_gfx->selectColorFromFourColorPalette(c, r, g, b);
-		palette[c * 3 + 0] = r;
-		palette[c * 3 + 1] = g;
-		palette[c * 3 + 2] = b;
-	}
-
 	for (int f = 0; f < 2; f++) {
 		file->seek(offsets[f]);
 		int height = file->readByte();
 		int widthBytes = file->readByte();
 
-		Graphics::ManagedSurface clut8;
-		clut8.create(widthBytes * 4, height, Graphics::PixelFormat::createFormatCLUT8());
-		loadFrameCPCIndexed(file, &clut8, widthBytes, height);
-		clut8.setPalette(palette, 0, 4);
-
-		Graphics::Surface *converted = _gfx->convertImageFormatIfNecessary(&clut8);
-		auto *surf = new Graphics::ManagedSurface();
-		surf->copyFrom(*converted);
-		converted->free();
-		delete converted;
-
-		_eclipseSprites.push_back(surf);
+		auto *indexed = new Graphics::ManagedSurface();
+		indexed->create(widthBytes * 4, height, Graphics::PixelFormat::createFormatCLUT8());
+		loadFrameCPCIndexed(file, indexed, widthBytes, height);
+		_heartFramesCPCIndexed.push_back(indexed);
 	}
 }
 
@@ -149,8 +131,10 @@ void EclipseEngine::loadAssetsCPCFullGame() {
 	loadColorPalette();
 	swapPalette(1);
 
-	if (!isEclipse2())
+	if (!isEclipse2()) {
 		loadHeartFramesCPC(&file, 0x0CDB, 0x0D0D);
+		updateHeartFramesCPC();
+	}
 
 	_indicators.push_back(loadBundledImage("eclipse_ankh_indicator"));
 
@@ -182,6 +166,7 @@ void EclipseEngine::loadAssetsCPCDemo() {
 	loadColorPalette();
 	swapPalette(1);
 	loadHeartFramesCPC(&file, 0x0D17, 0x0D49);
+	updateHeartFramesCPC();
 
 	// This patch forces a solid color to the bottom of the chest in the area 5
 	// It was transparent in the original game
@@ -195,6 +180,40 @@ void EclipseEngine::loadAssetsCPCDemo() {
 		it->convertToInPlace(_gfx->_texturePixelFormat);
 }
 
+void EclipseEngine::updateHeartFramesCPC() {
+	if (_heartFramesCPCIndexed.empty())
+		return;
+
+	uint8 r, g, b;
+	byte palette[4 * 3];
+	for (int c = 0; c < 4; c++) {
+		_gfx->selectColorFromFourColorPalette(c, r, g, b);
+		palette[c * 3 + 0] = r;
+		palette[c * 3 + 1] = g;
+		palette[c * 3 + 2] = b;
+	}
+
+	for (auto &sprite : _eclipseSprites) {
+		sprite->free();
+		delete sprite;
+	}
+	_eclipseSprites.clear();
+
+	for (uint i = 0; i < _heartFramesCPCIndexed.size(); i++) {
+		Graphics::ManagedSurface clut8;
+		clut8.copyFrom(*_heartFramesCPCIndexed[i]);
+		clut8.setPalette(palette, 0, 4);
+
+		Graphics::Surface *converted = _gfx->convertImageFormatIfNecessary(&clut8);
+		auto *surf = new Graphics::ManagedSurface();
+		surf->copyFrom(*converted);
+		converted->free();
+		delete converted;
+
+		_eclipseSprites.push_back(surf);
+	}
+}
+
 void EclipseEngine::drawCPCUI(Graphics::Surface *surface) {
 	uint32 color = _currentArea->_underFireBackgroundColor;
 	uint8 r, g, b;
@@ -256,14 +275,14 @@ void EclipseEngine::drawCPCUI(Graphics::Surface *surface) {
 	if (energy < 0)
 		energy = 0;
 
-	_gfx->readFromPalette(19, r, g, b);
-	uint32 blue = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b);
+	_gfx->readFromPalette(_currentArea->_paperColor, r, g, b);
+	uint32 waterColor = _gfx->_texturePixelFormat.ARGBToColor(0xFF, r, g, b);
 
 	Common::Rect jarBackground(124, 165, 148, 192);
 	surface->fillRect(jarBackground, back);
 
 	Common::Rect jarWater(124, 192 - energy, 148, 192);
-	surface->fillRect(jarWater, blue);
+	surface->fillRect(jarWater, waterColor);
 
 	drawHeartIndicator(surface, 176, 168);
 
diff --git a/engines/freescape/games/eclipse/eclipse.cpp b/engines/freescape/games/eclipse/eclipse.cpp
index feba68ffb94..97b417cb188 100644
--- a/engines/freescape/games/eclipse/eclipse.cpp
+++ b/engines/freescape/games/eclipse/eclipse.cpp
@@ -372,6 +372,8 @@ void EclipseEngine::gotoArea(uint16 areaID, int entranceID) {
 
 	_gfx->_keyColor = 0;
 	swapPalette(areaID);
+	if (isCPC())
+		updateHeartFramesCPC();
 	if (isAmiga() || isAtariST())
 		_currentArea->_skyColor = 15;
 
diff --git a/engines/freescape/games/eclipse/eclipse.h b/engines/freescape/games/eclipse/eclipse.h
index 88eadf1862d..508bd07d7db 100644
--- a/engines/freescape/games/eclipse/eclipse.h
+++ b/engines/freescape/games/eclipse/eclipse.h
@@ -107,6 +107,10 @@ public:
 	void loadHeartFramesDOS(Common::SeekableReadStream *file, int restOffset, int beatOffset);
 	void drawHeartIndicator(Graphics::Surface *surface, int x, int y);
 
+	// CPC heart frames stored as indexed (CLUT8) for per-area re-paletting
+	Common::Array<Graphics::ManagedSurface *> _heartFramesCPCIndexed;
+	void updateHeartFramesCPC();
+
 	Common::Array<byte> _musicData; // TEMUSIC.ST TEXT segment (Atari ST)
 	Common::Array<byte> _c64MusicData;
 	EclipseC64MusicPlayer *_playerC64Music;




More information about the Scummvm-git-logs mailing list