[Scummvm-git-logs] scummvm master -> 0d818b9f416b2f1d0a42b0f82c81980c19dcb829

bluegr noreply at scummvm.org
Wed Jun 10 23:16:23 UTC 2026


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

Summary:
0b94cea8c6 NANCY: More work on multibuildpuzzle for Nancy10
0d818b9f41 NANCY: Fix cake baking video in Nancy 10


Commit: 0b94cea8c6814743fcd85b41e4238d3dffbbab24
    https://github.com/scummvm/scummvm/commit/0b94cea8c6814743fcd85b41e4238d3dffbbab24
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-11T02:16:10+03:00

Commit Message:
NANCY: More work on multibuildpuzzle for Nancy10

The cake puzzle is solvable now. The mixing animation is still missing

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


diff --git a/engines/nancy/action/puzzle/multibuildpuzzle.cpp b/engines/nancy/action/puzzle/multibuildpuzzle.cpp
index 91a03ab0300..5e52f8e20d3 100644
--- a/engines/nancy/action/puzzle/multibuildpuzzle.cpp
+++ b/engines/nancy/action/puzzle/multibuildpuzzle.cpp
@@ -33,6 +33,10 @@
 namespace Nancy {
 namespace Action {
 
+// Nancy 10 TODOs:
+//  - completion-animation playback (data read, never rendered)
+//  - _retainState save/restore via a PuzzleData entry
+//  - 4th cursor id, 7 × 33-byte string slots, per-piece reserved rect
 void MultiBuildPuzzle::init() {
 	g_nancy->_resource->loadImage(_primaryImageName, _primaryImage);
 	_primaryImage.setTransparentColor(_drawSurface.getTransparentColor());
@@ -407,9 +411,7 @@ void MultiBuildPuzzle::handleInput(NancyInput &input) {
 		return;
 	Common::Rect vpScreen = viewData->screenPosition;
 
-	// Exit hotspots are checked against full-screen coords, so they work even
-	// when the cursor strays below the viewport (cake mixing's bottom-edge
-	// exit at y=340 sits outside the viewport in Nancy 10).
+	// Exit hotspots can sit below the viewport (cake mixing).
 	if (!_isDragging && _selectedPiece == -1 && !vpScreen.contains(input.mousePos)) {
 		if (!checkExitHotspot(_exitHotspot, _exitCursorID1, input))
 			checkExitHotspot(_exitHotspot2, _exitCursorID2, input);
@@ -458,19 +460,27 @@ void MultiBuildPuzzle::handleInput(NancyInput &input) {
 
 			if (validDrop) {
 				pp.isPlaced = true;
+				const bool isNancy10 = g_nancy->getGameType() >= kGameTypeNancy10;
+				if (isNancy10) {
+					// Clone placements bump the source piece's counter.
+					int srcIdx = (pp.typeIdx >= 0) ? pp.typeIdx : placedIdx;
+					if (_pieces[srcIdx].placeCount < 255)
+						_pieces[srcIdx].placeCount++;
+				}
 				g_nancy->_sound->playSound(_dropSound);
 
 				// Counter pieces respawn at home for unlimited supply.
 				if (pp.counterByte != 0)
 					spawnCounterPiece(placedIdx);
+
+				if (isNancy10)
+					updateSolveFlags();
 			} else {
 				pp.gameRect = pp.homeRect;
 			}
 
 			updatePieceRender(placedIdx);
 
-			// Solve check runs on drop for puzzles with _autoSolveOnDrop, and
-			// also once piece count grows past the original's auto-solve trigger.
 			if (_autoSolveOnDrop || _pieces.size() > 79)
 				checkIfSolved();
 
@@ -615,30 +625,66 @@ void MultiBuildPuzzle::checkIfSolvedOnExit() {
 	}
 }
 
-void MultiBuildPuzzle::checkIfSolved() {
-	// Count = placed pieces with counterByte == 0, plus the spawn delta
-	// (so counter-piece puzzles like sandwich count each placement).
-	uint16 count = 0;
+bool MultiBuildPuzzle::updateSolveFlags() {
+	uint16 total = 0;
 	for (uint i = 0; i < _numPieces; ++i) {
-		if (_pieces[i].isPlaced && _pieces[i].counterByte == 0)
-			++count;
+		if (_pieces[i].counterByte == 0 || _allowAltZoneSnap)
+			total += _pieces[i].placeCount;
 	}
-	count += (uint16)(_pieces.size() - _numPieces);
+	total += (uint16)(_pieces.size() - _numPieces);
 
-	if (count < _requiredPieces)
-		return;
+	if (total < _requiredPieces)
+		return false;
+
+	if (_cancelScene._flag.label != kFlagNoLabel)
+		NancySceneState.setEventFlag(_cancelScene._flag);
+
+	// Preemptively clear the solve flag; the exact-match check below re-sets it.
+	if (_solveScene._flag.label != kFlagNoLabel)
+		NancySceneState.setEventFlag(_solveScene._flag.label, _solveScene._flag.flag ? 0 : 1);
 
-	// Bail without solving on any constraint failure.
 	for (uint i = 0; i < _numPieces; ++i) {
-		if (_pieces[i].isPlaced && _pieces[i].mustNotPlace)
+		if (_pieces[i].placeCount > 0 && _pieces[i].mustNotPlace > 0)
+			return false;
+		if (_pieces[i].placeCount != _pieces[i].mustPlace)
+			return false;
+	}
+
+	if (_solveScene._flag.label != kFlagNoLabel)
+		NancySceneState.setEventFlag(_solveScene._flag);
+
+	return true;
+}
+
+void MultiBuildPuzzle::checkIfSolved() {
+	const bool isNancy10 = g_nancy->getGameType() >= kGameTypeNancy10;
+
+	if (isNancy10) {
+		// Exact-count match; solveScene == kNoScene means the dialog handles
+		// the transition via the solve flag set in updateSolveFlags.
+		bool exactMatch = updateSolveFlags();
+		if (!exactMatch || _solveScene._sceneChange.sceneID == kNoScene)
 			return;
-		if (!_pieces[i].isPlaced && _pieces[i].mustPlace)
+	} else {
+		// Nancy 9: bool placement semantics, no per-drop flag setting.
+		uint16 count = 0;
+		for (uint i = 0; i < _numPieces; ++i) {
+			if (_pieces[i].isPlaced && _pieces[i].counterByte == 0)
+				++count;
+		}
+		count += (uint16)(_pieces.size() - _numPieces);
+
+		if (count < _requiredPieces)
 			return;
+
+		for (uint i = 0; i < _numPieces; ++i) {
+			if (_pieces[i].isPlaced && _pieces[i].mustNotPlace)
+				return;
+			if (!_pieces[i].isPlaced && _pieces[i].mustPlace)
+				return;
+		}
 	}
 
-	// Play sound + caption inline (rather than parking in kPlaySolveSound for
-	// execute() to pick up) so the transition is deterministic regardless of
-	// action-record processing order.
 	_isSolved = true;
 	g_nancy->_sound->playSound(_solveSound);
 
@@ -669,10 +715,8 @@ void MultiBuildPuzzle::updatePieceRender(int pieceIdx) {
 	bool isSelected = (!_isDragging && pieceIdx == _selectedPiece);
 	bool isDragging  = (_isDragging  && pieceIdx == _pickedUpPiece);
 
-	// Nancy 10: at-rest pieces are already painted into the primary scene
-	// overlay at their home positions, so the engine doesn't draw them.
-	// Hide the placed piece too when a completion-animation overlay handles
-	// the visual (cake mixing).
+	// Nancy 10: at-rest pieces are baked into the primary overlay; placed
+	// pieces hide too when the completion animation will cover them.
 	if (g_nancy->getGameType() >= kGameTypeNancy10 && !isDragging && !isSelected) {
 		if (!p.isPlaced || _hasAnimImage) {
 			p.setVisible(false);
diff --git a/engines/nancy/action/puzzle/multibuildpuzzle.h b/engines/nancy/action/puzzle/multibuildpuzzle.h
index df8e5b7a686..c47b1382355 100644
--- a/engines/nancy/action/puzzle/multibuildpuzzle.h
+++ b/engines/nancy/action/puzzle/multibuildpuzzle.h
@@ -66,8 +66,9 @@ protected:
 		Common::Rect cuSrcRect;   // Source in closeup image
 		Common::Rect placedDstRect; // Nancy 10: placement destination on screen
 		uint8 counterByte = 0;    // Non-zero: respawns on placement; doesn't count toward solve
-		uint8 mustPlace = 0;      // Must be placed for solution
-		uint8 mustNotPlace = 0;   // Placing this fails the solution check
+		uint8 mustPlace = 0;      // Required placement count (exact match for solve). 0/1 in Nancy 9; arbitrary in Nancy 10+ (e.g. cake mixing recipe quantities)
+		uint8 mustNotPlace = 0;   // Non-zero: placing this fails the solution check
+		uint8 placeCount = 0;     // Runtime: number of times this piece (or any clone of it) has been placed
 
 		Common::Rect gameRect;    // Current viewport-space rect
 		int curRotation = 0;
@@ -149,6 +150,10 @@ protected:
 
 	void checkIfSolved();
 	void checkIfSolvedOnExit();
+	// Updates the global cancel/solve event flags from the current placement
+	// state. Returns true on exact match (all placeCounts == mustPlace, no
+	// mustNotPlace pieces placed).
+	bool updateSolveFlags();
 	void updatePieceRender(int pieceIdx);
 	static void rotateSurface90CW(const Graphics::ManagedSurface &src, Graphics::ManagedSurface &dst);
 	// Clone an existing piece at the end of _pieces (counter-piece respawn).


Commit: 0d818b9f416b2f1d0a42b0f82c81980c19dcb829
    https://github.com/scummvm/scummvm/commit/0d818b9f416b2f1d0a42b0f82c81980c19dcb829
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-11T02:16:12+03:00

Commit Message:
NANCY: Fix cake baking video in Nancy 10

Extend setting video format to large in secondary movies for Nancy 10

Changed paths:
    engines/nancy/action/secondarymovie.cpp


diff --git a/engines/nancy/action/secondarymovie.cpp b/engines/nancy/action/secondarymovie.cpp
index 499d7b07791..c8194710fc5 100644
--- a/engines/nancy/action/secondarymovie.cpp
+++ b/engines/nancy/action/secondarymovie.cpp
@@ -56,7 +56,7 @@ void PlaySecondaryMovie::readData(Common::SeekableReadStream &stream) {
 	ser.syncAsUint16LE(_videoType, kGameTypeNancy7);
 	ser.skip(2, kGameTypeVampire, kGameTypeNancy9); // videoPlaySource
 	ser.syncAsUint16LE(_videoFormat);
-	if (g_nancy->getGameType() >= kGameTypeNancy11)
+	if (g_nancy->getGameType() >= kGameTypeNancy10)
 		_videoFormat = kLargeVideoFormat;
 	ser.skip(4, kGameTypeVampire, kGameTypeVampire); // paletteStart, paletteSize
 	ser.skip(2, kGameTypeVampire, kGameTypeNancy9);  // hasBitmapOverlaySurface




More information about the Scummvm-git-logs mailing list