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

bluegr noreply at scummvm.org
Sun Apr 19 09:59: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:
4505154baf NANCY: Fix frame seeking in Bink videos
012053caff NANCY: Fix PascalCase naming
33434206b9 NANCY: Map more changes to the navigation AR functions in Nancy10+
a9b89a53c7 NANCY: Add stub for reading hotspots from secondary videos in Nancy10+


Commit: 4505154bafbbe95f31179f505f806004a0894560
    https://github.com/scummvm/scummvm/commit/4505154bafbbe95f31179f505f806004a0894560
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-04-19T12:58:09+03:00

Commit Message:
NANCY: Fix frame seeking in Bink videos

Fixes scene rotation in Nancy10+

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


diff --git a/engines/nancy/ui/viewport.cpp b/engines/nancy/ui/viewport.cpp
index 5b2075db2cd..61193cccaab 100644
--- a/engines/nancy/ui/viewport.cpp
+++ b/engines/nancy/ui/viewport.cpp
@@ -282,7 +282,7 @@ void Viewport::setFrame(uint frameNr) {
 		Video::BinkDecoder *decoder = dynamic_cast<Video::BinkDecoder *>(_decoder.get());
 		if (!decoder)
 			error("Viewport::setFrame(): Decoder is not a BinkDecoder");
-		decoder->seek(frameNr); // Seek to take advantage of caching
+		decoder->seekToFrame(frameNr); // Seek to take advantage of caching
 		newFrame = decoder->decodeNextFrame();
 	}
 


Commit: 012053caff1ce9065a413472a51c204034c176ee
    https://github.com/scummvm/scummvm/commit/012053caff1ce9065a413472a51c204034c176ee
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-04-19T12:58:15+03:00

Commit Message:
NANCY: Fix PascalCase naming

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


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 4a6b14b8ddf..0e250866bb7 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -101,7 +101,7 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 			return nullptr;
 		}
 	case 13:
-		return new HotMultiframeMultisceneChange();
+		return new HotMultiframeMultiSceneChange();
 	case 14:
 		return new Hot1FrSceneChange(CursorManager::kExit);
 	case 15:
@@ -141,7 +141,7 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 			return new HotMultiframeSceneChange(CursorManager::kMoveRight);
 		}
 	case 24:
-		return new HotMultiframeMultisceneCursorTypeSceneChange();
+		return new HotMultiframeMultiSceneCursorTypeSceneChange();
 	case 25: {
 		// Weird case; instead of storing the cursor id, they instead chose to store
 		// an AR id corresponding to one of the directional Hot1FrSceneChange variants.
diff --git a/engines/nancy/action/navigationrecords.cpp b/engines/nancy/action/navigationrecords.cpp
index 368b55e00ac..820fb1d3a43 100644
--- a/engines/nancy/action/navigationrecords.cpp
+++ b/engines/nancy/action/navigationrecords.cpp
@@ -130,7 +130,7 @@ void Hot1FrSceneChange::execute() {
 	}
 }
 
-void HotMultiframeMultisceneChange::readData(Common::SeekableReadStream &stream) {
+void HotMultiframeMultiSceneChange::readData(Common::SeekableReadStream &stream) {
 	if (g_nancy->getGameType() <= kGameTypeNancy2) {
 		_onTrue._sceneChange.readData(stream);
 		_onFalse._sceneChange.readData(stream);
@@ -151,7 +151,7 @@ void HotMultiframeMultisceneChange::readData(Common::SeekableReadStream &stream)
 	}
 }
 
-void HotMultiframeMultisceneChange::execute() {
+void HotMultiframeMultiSceneChange::execute() {
 	switch (_state) {
 	case kBegin:
 		// set something to 1
@@ -199,7 +199,7 @@ void HotMultiframeMultisceneChange::execute() {
 	}
 }
 
-void HotMultiframeMultisceneCursorTypeSceneChange::readData(Common::SeekableReadStream &stream) {
+void HotMultiframeMultiSceneCursorTypeSceneChange::readData(Common::SeekableReadStream &stream) {
 	uint16 numScenes = stream.readUint16LE();
 	_scenes.resize(numScenes);
 	_cursorTypes.resize(numScenes);
@@ -218,7 +218,7 @@ void HotMultiframeMultisceneCursorTypeSceneChange::readData(Common::SeekableRead
 	}
 }
 
-void HotMultiframeMultisceneCursorTypeSceneChange::execute() {
+void HotMultiframeMultiSceneCursorTypeSceneChange::execute() {
 	switch (_state) {
 	case kBegin:
 		// turn main rendering on
diff --git a/engines/nancy/action/navigationrecords.h b/engines/nancy/action/navigationrecords.h
index 705a847f872..091a83d89db 100644
--- a/engines/nancy/action/navigationrecords.h
+++ b/engines/nancy/action/navigationrecords.h
@@ -145,7 +145,7 @@ protected:
 // Changes the scene when clicked. Hotspot can move along with scene background frame.
 // However, the scene it changes to can be one of two options, picked based on
 // a provided condition.
-class HotMultiframeMultisceneChange : public ActionRecord {
+class HotMultiframeMultiSceneChange : public ActionRecord {
 public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
@@ -165,7 +165,7 @@ protected:
 // Changes the scene when clicked. Hotspot can move along with scene background frame.
 // However, the scene it changes to can be one of several options, picked based on
 // the item the player is currently holding.
-class HotMultiframeMultisceneCursorTypeSceneChange : public ActionRecord {
+class HotMultiframeMultiSceneCursorTypeSceneChange : public ActionRecord {
 public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;


Commit: 33434206b97d65a3b74efd408f591d7720975d75
    https://github.com/scummvm/scummvm/commit/33434206b97d65a3b74efd408f591d7720975d75
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-04-19T12:58:17+03:00

Commit Message:
NANCY: Map more changes to the navigation AR functions in Nancy10+

Fixes a lot of navigation issues in Nancy10+. Nancy11 hotspots are
still not working, because there's heavier usage of opcode 12 (a
simplified version of HotMultiframeSceneChange), which is still not
implemented

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


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 0e250866bb7..aa28ee7bf88 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -81,27 +81,28 @@ namespace Action {
 ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableReadStream *recordStream) {
 	switch (type) {
 	case 10:
-		if (g_nancy->getGameType() <= kGameTypeNancy9) {
+		if (g_nancy->getGameType() <= kGameTypeNancy9)
 			return new Hot1FrSceneChange(CursorManager::kHotspot);
-		} else {
-			return new SceneChange();
-		}
+		else
+			return new SceneChange();	// Moved from 12 in Nancy10
 	case 11:
-		if (g_nancy->getGameType() <= kGameTypeNancy9) {
+		if (g_nancy->getGameType() <= kGameTypeNancy9)
 			return new HotMultiframeSceneChange(CursorManager::kHotspot);
-		} else {
-			return new HotSingleFrameSceneChange(true);
-		}
+		else
+			return new Hot1FrSceneChange(CursorManager::kExit);	// TODO: cursor
 	case 12:
 		if (g_nancy->getGameType() <= kGameTypeNancy9) {
 			return new SceneChange();
 		} else {
-			// Nancy11+
+			// Nancy10+. A simplified version of HotMultiframeSceneChange
 			// TODO: Handle this correctly
 			return nullptr;
 		}
 	case 13:
-		return new HotMultiframeMultiSceneChange();
+		if (g_nancy->getGameType() <= kGameTypeNancy9)
+			return new HotMultiframeMultiSceneChange();
+		else
+			return new Hot1FrSceneChange(CursorManager::kExit); // TODO: cursor
 	case 14:
 		return new Hot1FrSceneChange(CursorManager::kExit);
 	case 15:
@@ -113,60 +114,79 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 	case 18:
 		return new Hot1FrSceneChange(CursorManager::kMoveDown);
 	case 19:
-		return new HotMultiframeSceneChange(CursorManager::kMoveForward);
+		if (g_nancy->getGameType() <= kGameTypeNancy9)
+			return new HotMultiframeSceneChange(CursorManager::kMoveForward);
+		else
+			return new Hot1FrSceneChange(CursorManager::kMoveLeft);		// Moved from 22 in Nancy10
 	case 20:
-		if (g_nancy->getGameType() == kGameTypeVampire) {
+		if (g_nancy->getGameType() == kGameTypeVampire)
 			return new PaletteThisScene();
-		} else {
+		else if (g_nancy->getGameType() <= kGameTypeNancy9)
 			return new HotMultiframeSceneChange(CursorManager::kMoveUp);
-		}
+		else
+			return new Hot1FrSceneChange(CursorManager::kMoveRight);	// Moved from 23 in Nancy10
 	case 21:
-		if (g_nancy->getGameType() == kGameTypeVampire) {
+		if (g_nancy->getGameType() == kGameTypeVampire)
 			return new PaletteNextScene();
-		} else if (g_nancy->getGameType() <= kGameTypeNancy9) {
+		else if (g_nancy->getGameType() <= kGameTypeNancy9)
 			return new HotMultiframeSceneChange(CursorManager::kMoveDown);
-		} else {
+		else
 			return new HotSingleFrameSceneChange();
-		}
 	case 22:
-		if (g_nancy->getGameType() <= kGameTypeNancy9) {
+		if (g_nancy->getGameType() <= kGameTypeNancy9)
 			return new Hot1FrSceneChange(CursorManager::kMoveLeft);
-		} else {
-			return new HotMultiframeSceneChange(CursorManager::kMoveLeft);
-		}
+		else
+			return new HotMultiframeSceneChange(CursorManager::kHotspot);		// Moved from 11 in Nancy 10
 	case 23:
-		if (g_nancy->getGameType() <= kGameTypeNancy9) {
+		if (g_nancy->getGameType() <= kGameTypeNancy9)
 			return new Hot1FrSceneChange(CursorManager::kMoveRight);
-		} else {
-			return new HotMultiframeSceneChange(CursorManager::kMoveRight);
-		}
+		else
+			return new HotMultiframeSceneChange(CursorManager::kMoveForward);	// Moved from 19 in Nancy 10
 	case 24:
-		return new HotMultiframeMultiSceneCursorTypeSceneChange();
+		if (g_nancy->getGameType() <= kGameTypeNancy9)
+			return new HotMultiframeMultiSceneCursorTypeSceneChange();
+		else
+			return new HotMultiframeSceneChange(CursorManager::kMoveUp);		// Moved from 20 in Nancy 10
 	case 25: {
-		// Weird case; instead of storing the cursor id, they instead chose to store
-		// an AR id corresponding to one of the directional Hot1FrSceneChange variants.
-		// Thus, we need to scan the incoming chunk and make another call to createActionRecord().
-		// This is not the most elegant solution, but it works :)
-		assert(recordStream);
-		uint16 innerID = recordStream->readUint16LE();
-		Hot1FrSceneChange *newRec = dynamic_cast<Hot1FrSceneChange *>(createActionRecord(innerID));
-		assert(newRec);
-		newRec->_isTerse = true;
-		return newRec;
+		if (g_nancy->getGameType() <= kGameTypeNancy9) {
+			// Weird case; instead of storing the cursor id, they instead chose to store
+			// an AR id corresponding to one of the directional Hot1FrSceneChange variants.
+			// Thus, we need to scan the incoming chunk and make another call to createActionRecord().
+			// This is not the most elegant solution, but it works :)
+			assert(recordStream);
+			uint16 innerID = recordStream->readUint16LE();
+			Hot1FrSceneChange *newRec = dynamic_cast<Hot1FrSceneChange *>(createActionRecord(innerID));
+			assert(newRec);
+			newRec->_isTerse = true;
+			return newRec;
+		} else {
+			return new HotMultiframeSceneChange(CursorManager::kMoveDown);		// Moved from 21 in Nancy 10
+		}
 	}
 	case 26:
-		return new InteractiveVideo();
+		if (g_nancy->getGameType() <= kGameTypeNancy9)
+			return new InteractiveVideo();
+		else
+			return new HotMultiframeMultiSceneChange();	// Moved from 13 in Nancy 10
+	case 27:
+		if (g_nancy->getGameType() >= kGameTypeNancy10)
+			return new HotMultiframeMultiSceneCursorTypeSceneChange(); // Moved from 24 to 27 in Nancy10
+	case 28:
+		if (g_nancy->getGameType() >= kGameTypeNancy10)
+			return new InteractiveVideo();	// Moved from 26 to 28 in Nancy10
 	case 29:
 		// Nancy 10+
 		warning("ControlUIItems - not implemented yet");
 		return nullptr;
+	case 32:
+		// Nancy 10+
+		warning("UIPopupPrepScene - not implemented yet");
+		return nullptr;
 	case 40:
-		if (g_nancy->getGameType() < kGameTypeNancy2) {
-			// Only used in TVD
-			return new LightningOn();
-		} else {
+		if (g_nancy->getGameType() <= kGameTypeNancy1)
+			return new LightningOn();	// Only used in TVD
+		else
 			return new SpecialEffect();
-		}
 	case 50:
 		return new ConversationVideo(); // PlayPrimaryVideoChan0
 	case 51:
@@ -175,25 +195,22 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 	case 53:
 		return new PlaySecondaryMovie();
 	case 54:
-		if (g_nancy->getGameType() <= kGameTypeNancy1) {
+		if (g_nancy->getGameType() <= kGameTypeNancy1)
 			return new Overlay(false); // PlayStaticBitmapAnimation
-		} else {
+		else
 			return new Overlay(true);
-		}
 	case 55:
-		if (g_nancy->getGameType() <= kGameTypeNancy1) {
+		if (g_nancy->getGameType() <= kGameTypeNancy1)
 			return new Overlay(true); // PlayIntStaticBitmapAnimation
-		} else if (g_nancy->getGameType() >= kGameTypeNancy7) {
+		else if (g_nancy->getGameType() >= kGameTypeNancy7)
 			return new OverlayStaticTerse();
-		}
-		return nullptr;
+		else
+			return nullptr;
 	case 56:
-		if (g_nancy->getGameType() <= kGameTypeNancy6) {
+		if (g_nancy->getGameType() <= kGameTypeNancy6)
 			return new ConversationVideo();
-		} else {
+		else
 			return new OverlayAnimTerse();
-		}
-		return nullptr;
 	case 57:
 		return new ConversationCel();
 	case 58:
@@ -215,11 +232,10 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 			return new Autotext();
 		}
 	case 62:
-		if (g_nancy->getGameType() <= kGameTypeNancy7) {
+		if (g_nancy->getGameType() <= kGameTypeNancy7)
 			return new MapCallHotMultiframe(); // TVD/nancy1 only
-		} else {
+		else
 			return new ConversationCelTerse(); // nancy8 and up
-		}
 	case 63:
 		return new ConversationSoundTerse();
 	case 65:
@@ -238,12 +254,15 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 		return new ModifyListEntry(ModifyListEntry::kDelete);
 	case 73:
 		return new ModifyListEntry(ModifyListEntry::kMark);
-	case 74:	// Nancy 10
+	case 74:	// Added in Nancy 10
+	case 75:	// Changed in Nancy 10
 	case 81:	// Nancy 11+
-		warning("FrameTextBox - not implemented yet");
-		return nullptr;
-	case 75:
-		return new TextBoxWrite();
+		if (g_nancy->getGameType() <= kGameTypeNancy9 && type == 75) {
+			return new TextBoxWrite();
+		} else {
+			warning("FrameTextBox - not implemented yet");
+			return nullptr;
+		}
 	case 76:
 		return new TextboxClear();
 	case 77:
@@ -275,11 +294,10 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 	case 107:
 		return new EventFlags();
 	case 108:
-		if (g_nancy->getGameType() <= kGameTypeNancy6) {
+		if (g_nancy->getGameType() <= kGameTypeNancy6)
 			return new OrderingPuzzle(OrderingPuzzle::kOrdering);
-		} else {
+		else
 			return new GotoMenu();
-		}
 	case 109:
 		return new LoseGame();
 	case 110:
@@ -335,11 +353,10 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 		// TODO: Used in Nancy 9, sand castle puzzle
 		return nullptr;
 	case 149:
-		if (g_nancy->getGameType() >= kGameTypeNancy9) {
-			// This got moved in nancy9
-			return new SetVolume();
-		}
-		return nullptr;
+		if (g_nancy->getGameType() >= kGameTypeNancy9)
+			return new SetVolume();	// Moved from 140 in Nancy9
+		else
+			return nullptr;
 	case 150:
 		return new PlaySound();
 	case 151:


Commit: a9b89a53c7f8322c2b0500e0f5dac49107b5fc8c
    https://github.com/scummvm/scummvm/commit/a9b89a53c7f8322c2b0500e0f5dac49107b5fc8c
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-04-19T12:58:19+03:00

Commit Message:
NANCY: Add stub for reading hotspots from secondary videos in Nancy10+

These are used in character conversations. They're still not working,
but at least we're no longer getting errors from incorrect data reads

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


diff --git a/engines/nancy/action/secondaryvideo.cpp b/engines/nancy/action/secondaryvideo.cpp
index dfbcd6783b8..bc2966b8a9b 100644
--- a/engines/nancy/action/secondaryvideo.cpp
+++ b/engines/nancy/action/secondaryvideo.cpp
@@ -184,6 +184,16 @@ void PlaySecondaryVideo::readData(Common::SeekableReadStream &stream) {
 	for (uint i = 0; i < numVideoDescs; ++i) {
 		_videoDescs[i].readData(stream);
 	}
+
+	if (g_nancy->getGameType() >= kGameTypeNancy10) {
+		// TODO: Hotspot data
+		uint32 num;
+		ser.syncAsUint32LE(num);
+		Common::Array<Common::Rect> rects;
+		readRectArray(stream, rects, 4);
+
+		stream.skip(16);
+	}
 }
 
 void PlaySecondaryVideo::execute() {




More information about the Scummvm-git-logs mailing list