[Scummvm-git-logs] scummvm master -> bcd1006a9f9b6c2b40a83fd6388696e26b89bd5c

bluegr noreply at scummvm.org
Mon Jun 29 21:11:50 UTC 2026


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

Summary:
99ac983ee7 NANCY: NANCY12: Implement differences in RippedLetterPuzzle
56ef8f3aad NANCY: NANCY10: Use the correct white font for the text box
fe8bd554f5 NANCY: NANCY10: Fix cursors set from some ARs
2cee36c78c NANCY: NANCY12: Implement differences in MemoryPuzzle
3bff2e67b3 NANCY: NANCY12: Implement differences for SafeDialPuzzle
fdae801637 NANCY: NANCY12: Implement differences for TurningPuzzle
bcd1006a9f NANCY: NANCY12: Implement differences for TwoDialPuzzle


Commit: 99ac983ee71a3e0224605662bce086d4a172e232
    https://github.com/scummvm/scummvm/commit/99ac983ee71a3e0224605662bce086d4a172e232
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-30T00:11:32+03:00

Commit Message:
NANCY: NANCY12: Implement differences in RippedLetterPuzzle

Changed paths:
    engines/nancy/action/puzzle/rippedletterpuzzle.cpp


diff --git a/engines/nancy/action/puzzle/rippedletterpuzzle.cpp b/engines/nancy/action/puzzle/rippedletterpuzzle.cpp
index da4957803ed..74990ba1e82 100644
--- a/engines/nancy/action/puzzle/rippedletterpuzzle.cpp
+++ b/engines/nancy/action/puzzle/rippedletterpuzzle.cpp
@@ -120,8 +120,8 @@ void RippedLetterPuzzle::readData(Common::SeekableReadStream &stream) {
 	stream.skip((maxWidth > width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * elemSize);
 
 	if (g_nancy->getGameType() >= kGameTypeNancy9) {
-		uint16 numDoubledElements = stream.readUint16LE();
-		_doubles.resize(numDoubledElements);
+		uint16 numDoubledElements = stream.readUint16LE();	// 0 in Nancy 12
+		_doubles.resize(numDoubledElements > 0 ? numDoubledElements : 20);
 		uint i = 0;
 		for (uint j = 0; j < 20; ++j) {
 			int16 id = stream.readSint16LE();


Commit: 56ef8f3aadb6a41393dcd2c20c0e7fc1c793ddee
    https://github.com/scummvm/scummvm/commit/56ef8f3aadb6a41393dcd2c20c0e7fc1c793ddee
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-30T00:11:34+03:00

Commit Message:
NANCY: NANCY10: Use the correct white font for the text box

Partial fix for #16888

Changed paths:
    engines/nancy/ui/scrolltextbox.cpp


diff --git a/engines/nancy/ui/scrolltextbox.cpp b/engines/nancy/ui/scrolltextbox.cpp
index 0c74fd0db84..6d1e7e5373d 100644
--- a/engines/nancy/ui/scrolltextbox.cpp
+++ b/engines/nancy/ui/scrolltextbox.cpp
@@ -131,7 +131,9 @@ void ScrollTextBox::drawContent() {
 	textBounds.top  += _tboxData->scrollbarDefaultPos.y;
 	textBounds.left += _tboxData->scrollbarDefaultPos.x;
 
-	const uint16 fontID = _fontIDOverride != -1 ? (uint16)_fontIDOverride : _tboxData->conversationFontID;
+	// Narration/caption text uses the (white) highlight font, not the (cyan)
+	// conversation body font that the ConversationPopup uses.
+	const uint16 fontID = _fontIDOverride != -1 ? (uint16)_fontIDOverride : _tboxData->highlightConversationFontID;
 	drawAllText(textBounds, 0, fontID, _tboxData->highlightConversationFontID);
 
 	// Two discrete states: "mini" (<= 2 lines) is a short strip above the


Commit: fe8bd554f5056cf652ef0bdb974dee3517f714aa
    https://github.com/scummvm/scummvm/commit/fe8bd554f5056cf652ef0bdb974dee3517f714aa
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-30T00:11:34+03:00

Commit Message:
NANCY: NANCY10: Fix cursors set from some ARs

- Correctly flag cursors set from the EventFlagsMultiHS AR as
  script-based
- Add another mapping table for the cursors set from the
  HotSingleFrameSceneChange AR

Fix #16889

Changed paths:
    engines/nancy/action/datarecords.cpp
    engines/nancy/action/datarecords.h
    engines/nancy/action/navigationrecords.cpp
    engines/nancy/action/navigationrecords.h


diff --git a/engines/nancy/action/datarecords.cpp b/engines/nancy/action/datarecords.cpp
index 46bf2f41328..852248d260b 100644
--- a/engines/nancy/action/datarecords.cpp
+++ b/engines/nancy/action/datarecords.cpp
@@ -359,6 +359,12 @@ void EventFlagsMultiHS::readData(Common::SeekableReadStream &stream) {
 	}
 }
 
+bool EventFlagsMultiHS::cursorSetFromScript() const {
+	if (g_nancy->getGameType() >= kGameTypeNancy10 && NancySceneState.getHeldItem() >= 0)
+		return false;
+	return _isCursor;
+}
+
 CursorManager::CursorType EventFlagsMultiHS::getHoverCursor() const {
 	if (g_nancy->getGameType() >= kGameTypeNancy10 && NancySceneState.getHeldItem() >= 0)
 		return CursorManager::kHotspot;
diff --git a/engines/nancy/action/datarecords.h b/engines/nancy/action/datarecords.h
index 9dba69646af..cf4cecacb34 100644
--- a/engines/nancy/action/datarecords.h
+++ b/engines/nancy/action/datarecords.h
@@ -122,7 +122,7 @@ public:
 	void execute() override;
 
 	CursorManager::CursorType getHoverCursor() const override;
-	bool cursorSetFromScript() const override { return true; }
+	bool cursorSetFromScript() const override;
 
 	CursorManager::CursorType _hoverCursor = CursorManager::kHotspot;
 	Common::Array<HotspotDescription> _hotspots;
diff --git a/engines/nancy/action/navigationrecords.cpp b/engines/nancy/action/navigationrecords.cpp
index cb37292cd28..6761c82da4e 100644
--- a/engines/nancy/action/navigationrecords.cpp
+++ b/engines/nancy/action/navigationrecords.cpp
@@ -82,8 +82,34 @@ void HotMultiframeSceneChange::execute() {
 	}
 }
 
+// The hover cursor is stored as the id of the matching directional scene-change
+// action record type, which gets translated into the actual cursor to display.
+static CursorManager::CursorType getNavigationCursor(uint16 id) {
+	switch (id) {
+	case 14:
+		return CursorManager::kExit;
+	case 15:
+	case 23:
+		return CursorManager::kMoveForward;
+	case 16:
+		return CursorManager::kMoveBackward;
+	case 17:
+	case 24:
+		return CursorManager::kMoveUp;
+	case 18:
+	case 25:
+		return CursorManager::kMoveDown;
+	case 19:
+		return CursorManager::kMoveLeft;
+	case 20:
+		return CursorManager::kMoveRight;
+	default:
+		return CursorManager::kHotspot;
+	}
+}
+
 void HotSingleFrameSceneChange::readData(Common::SeekableReadStream &stream) {
-	_hoverCursor = (CursorManager::CursorType)stream.readUint16LE();
+	_hoverCursor = getNavigationCursor(stream.readUint16LE());
 	_sceneChange.sceneID = stream.readUint16LE();
 	_sceneChange.continueSceneSound = kContinueSceneSound;
 	_sceneChange.listenerFrontVector.set(0, 0, 1);
diff --git a/engines/nancy/action/navigationrecords.h b/engines/nancy/action/navigationrecords.h
index 45647d57f88..4d224fe2a55 100644
--- a/engines/nancy/action/navigationrecords.h
+++ b/engines/nancy/action/navigationrecords.h
@@ -52,7 +52,7 @@ public:
 	void execute() override;
 
 	CursorManager::CursorType getHoverCursor() const override { return _hoverCursor; }
-	bool cursorSetFromScript() const override { return true; }
+	bool cursorSetFromScript() const override { return false; }
 
 	HotspotDescription _sceneHotspot;
 


Commit: 2cee36c78cdd8905e914cbc54adcbfb32edfa8ff
    https://github.com/scummvm/scummvm/commit/2cee36c78cdd8905e914cbc54adcbfb32edfa8ff
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-30T00:11:35+03:00

Commit Message:
NANCY: NANCY12: Implement differences in MemoryPuzzle

Changed paths:
    engines/nancy/action/puzzle/memorypuzzle.cpp


diff --git a/engines/nancy/action/puzzle/memorypuzzle.cpp b/engines/nancy/action/puzzle/memorypuzzle.cpp
index d70e39ac382..c67a21973d7 100644
--- a/engines/nancy/action/puzzle/memorypuzzle.cpp
+++ b/engines/nancy/action/puzzle/memorypuzzle.cpp
@@ -145,7 +145,7 @@ void MemoryPuzzle::readDataNancy11(Common::SeekableReadStream &stream) {
 	_winScene._sceneChange.continueSceneSound = stream.readUint16LE();
 	_winScene._flag.label = stream.readSint16LE();
 	_winScene._flag.flag = stream.readSint16LE() ? g_nancy->_true : g_nancy->_false;
-	stream.skip(26); // alternate scene
+	stream.skip(g_nancy->getGameType() >= kGameTypeNancy12 ? 24 : 26);	// alternate scene
 }
 
 // Shuffles type IDs (0..numPairs-1) into the 72-card array so that every type


Commit: 3bff2e67b38d0ddf1d80416b566dd672a9f743cc
    https://github.com/scummvm/scummvm/commit/3bff2e67b38d0ddf1d80416b566dd672a9f743cc
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-30T00:11:36+03:00

Commit Message:
NANCY: NANCY12: Implement differences for SafeDialPuzzle

Changed paths:
    engines/nancy/action/puzzle/safedialpuzzle.cpp


diff --git a/engines/nancy/action/puzzle/safedialpuzzle.cpp b/engines/nancy/action/puzzle/safedialpuzzle.cpp
index 3c6e6bdbc70..20de6afa520 100644
--- a/engines/nancy/action/puzzle/safedialpuzzle.cpp
+++ b/engines/nancy/action/puzzle/safedialpuzzle.cpp
@@ -90,7 +90,10 @@ void SafeDialPuzzle::updateGraphics() {
 void SafeDialPuzzle::readData(Common::SeekableReadStream &stream) {
 	readFilename(stream, _imageName1);
 	readFilename(stream, _imageName2);
-	readFilename(stream, _resetImageName);
+	if (g_nancy->getGameType() < kGameTypeNancy12) {
+		// Nancy 12 dropped the separate reset image from the header
+		readFilename(stream, _resetImageName);
+	}
 
 	_numInbetweens = (!_imageName2.empty() ? 1 : 0);
 
@@ -108,7 +111,7 @@ void SafeDialPuzzle::readData(Common::SeekableReadStream &stream) {
 	readRect(stream, _arrowDest);
 	readRect(stream, _arrowSrc);
 
-	readRectArray(stream, _resetDialSrcs, 10);
+	readRectArray(stream, _resetDialSrcs, g_nancy->getGameType() >= kGameTypeNancy12 ? 12 : 10);
 
 	_resetTurns = stream.readUint16LE();
 


Commit: fdae801637d7c5187d670b7e0481f635e7238a2e
    https://github.com/scummvm/scummvm/commit/fdae801637d7c5187d670b7e0481f635e7238a2e
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-30T00:11:37+03:00

Commit Message:
NANCY: NANCY12: Implement differences for TurningPuzzle

Changed paths:
    engines/nancy/action/puzzle/turningpuzzle.cpp


diff --git a/engines/nancy/action/puzzle/turningpuzzle.cpp b/engines/nancy/action/puzzle/turningpuzzle.cpp
index 3c6476337b7..878e8fe1636 100644
--- a/engines/nancy/action/puzzle/turningpuzzle.cpp
+++ b/engines/nancy/action/puzzle/turningpuzzle.cpp
@@ -182,12 +182,22 @@ void TurningPuzzle::readData(Common::SeekableReadStream &stream) {
 	}
 	stream.skip((16 - numSpindles) * 2);
 
+	if (g_nancy->getGameType() >= kGameTypeNancy12) {
+		// Nancy 12 inserts 3 bytes here (zero in the samples seen); purpose unknown.
+		stream.skip(3);
+	}
+
 	_solveScene.readData(stream);
 	_solveSoundDelay = stream.readUint16LE();
 	_solveSound.readNormal(stream);
 
 	_exitScene.readData(stream);
 	readRect(stream, _exitHotspot);
+
+	if (g_nancy->getGameType() >= kGameTypeNancy12) {
+		// Nancy 12 appends a uint16 here (5 in the sample seen); purpose unknown.
+		stream.skip(2);
+	}
 }
 
 void TurningPuzzle::execute() {


Commit: bcd1006a9f9b6c2b40a83fd6388696e26b89bd5c
    https://github.com/scummvm/scummvm/commit/bcd1006a9f9b6c2b40a83fd6388696e26b89bd5c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-30T00:11:38+03:00

Commit Message:
NANCY: NANCY12: Implement differences for TwoDialPuzzle

Changed paths:
    engines/nancy/action/puzzle/twodialpuzzle.cpp
    engines/nancy/action/puzzle/twodialpuzzle.h


diff --git a/engines/nancy/action/puzzle/twodialpuzzle.cpp b/engines/nancy/action/puzzle/twodialpuzzle.cpp
index 8b74dbbf96e..e1021b188f2 100644
--- a/engines/nancy/action/puzzle/twodialpuzzle.cpp
+++ b/engines/nancy/action/puzzle/twodialpuzzle.cpp
@@ -64,18 +64,55 @@ void TwoDialPuzzle::readData(Common::SeekableReadStream &stream) {
 	readRectArray(stream, _srcs[0], num1, 20);
 	readRectArray(stream, _srcs[1], num2, 20);
 
-	_correctPositions[0] = stream.readUint16LE();
-	_correctPositions[1] = stream.readUint16LE();
+	if (g_nancy->getGameType() < kGameTypeNancy12) {
+		_correctPositions[0] = stream.readUint16LE();
+		_correctPositions[1] = stream.readUint16LE();
+	}
 
 	_rotateSounds[0].readNormal(stream);
 	_rotateSounds[1].readNormal(stream);
 
-	_solveScene.readData(stream);
-	_solveSoundDelay = stream.readUint16LE();
-	_solveSound.readNormal(stream);
+	if (g_nancy->getGameType() >= kGameTypeNancy12) {
+		// Nancy 12 reworked this puzzle (see execute()): the single correctPositions
+		// pair was replaced by an event-flag-gated solution list at the end. The
+		// solve scene here carries NO sceneID of its own (it is taken from the matched
+		// solution), so it is read manually starting from the frameID.
+		_solveScene._sceneChange.frameID = stream.readUint16LE();
+		_solveScene._sceneChange.verticalOffset = stream.readUint16LE();
+		_solveScene._sceneChange.continueSceneSound = stream.readUint16LE();
+		int32 x = stream.readSint32LE();
+		int32 y = stream.readSint32LE();
+		int32 z = stream.readSint32LE();
+		_solveScene._sceneChange.listenerFrontVector.set(x, y, z);
+		_solveScene._sceneChange.frontVectorFrameID = _solveScene._sceneChange.frameID;
+		stream.skip(2); // shouldStopRendering
+		_solveScene._flag.label = stream.readSint16LE();
+		_solveScene._flag.flag = stream.readByte();
+
+		_solveSoundDelay = stream.readUint16LE();
+		_solveSound.readNormal(stream);
+
+		_exitScene.readData(stream);
+		stream.skip(2); // unknown
+		readRect(stream, _exitHotspot);
+
+		uint16 numSolutions = stream.readUint16LE();
+		_solutions.resize(numSolutions);
+		for (uint i = 0; i < numSolutions; ++i) {
+			_solutions[i].positions[0] = stream.readUint16LE();
+			_solutions[i].positions[1] = stream.readUint16LE();
+			_solutions[i].sceneID = stream.readUint16LE();
+			_solutions[i].condition.label = stream.readSint16LE();
+			_solutions[i].condition.flag = stream.readByte();
+		}
+	} else {
+		_solveScene.readData(stream);
+		_solveSoundDelay = stream.readUint16LE();
+		_solveSound.readNormal(stream);
 
-	_exitScene.readData(stream);
-	readRect(stream, _exitHotspot);
+		_exitScene.readData(stream);
+		readRect(stream, _exitHotspot);
+	}
 }
 
 void TwoDialPuzzle::execute() {
@@ -100,7 +137,24 @@ void TwoDialPuzzle::execute() {
 			return;
 		}
 
-		if ((uint)_currentPositions[0] == _correctPositions[0] && (uint)_currentPositions[1] == _correctPositions[1]) {
+		if (g_nancy->getGameType() >= kGameTypeNancy12) {
+			// A combo solves only while one of its solutions is active: the dial
+			// positions match and that solution's condition flag is currently set.
+			// The matched solution supplies the scene to change to.
+			for (uint i = 0; i < _solutions.size(); ++i) {
+				const DialSolution &sol = _solutions[i];
+				if (sol.sceneID != 9999 &&
+						_currentPositions[0] == sol.positions[0] &&
+						_currentPositions[1] == sol.positions[1] &&
+						NancySceneState.getEventFlag(sol.condition.label, sol.condition.flag)) {
+					_solveScene._sceneChange.sceneID = sol.sceneID;
+					_state = kActionTrigger;
+					_isSolved = true;
+					_solveSoundDelayTime = g_nancy->getTotalPlayTime() + (_solveSoundDelay * 1000);
+					break;
+				}
+			}
+		} else if ((uint)_currentPositions[0] == _correctPositions[0] && (uint)_currentPositions[1] == _correctPositions[1]) {
 			_state = kActionTrigger;
 			_isSolved = true;
 			_solveSoundDelayTime = g_nancy->getTotalPlayTime() + (_solveSoundDelay * 1000);
diff --git a/engines/nancy/action/puzzle/twodialpuzzle.h b/engines/nancy/action/puzzle/twodialpuzzle.h
index b4ae24c33d2..ce2948812df 100644
--- a/engines/nancy/action/puzzle/twodialpuzzle.h
+++ b/engines/nancy/action/puzzle/twodialpuzzle.h
@@ -56,6 +56,16 @@ protected:
 
 	uint16 _correctPositions[2] = { 0, 0 };
 
+	// Nancy 12+ replaced the single correctPositions pair with a list of
+	// event-flag-gated solutions: a combo only solves while its condition flag
+	// matches, and it changes to its own target scene.
+	struct DialSolution {
+		uint16 positions[2] = { 0, 0 };
+		uint16 sceneID = 0;
+		FlagDescription condition;
+	};
+	Common::Array<DialSolution> _solutions;
+
 	SoundDescription _rotateSounds[2];
 
 	SceneChangeWithFlag _solveScene;




More information about the Scummvm-git-logs mailing list