[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