[Scummvm-git-logs] scummvm master -> 830084d92dca358581c028f02385d5a820511462
bluegr
noreply at scummvm.org
Sat Aug 8 21:00:10 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:
e877c5a63a NANCY: NANCY16: Initial work on the boot chunks
830084d92d NANCY: NANCY12: Fix regression from gas/tire gauge overlay handling
Commit: e877c5a63ac7b484e54c78d85ce0f21c6c0ec8f2
https://github.com/scummvm/scummvm/commit/e877c5a63ac7b484e54c78d85ce0f21c6c0ec8f2
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-08-09T00:00:00+03:00
Commit Message:
NANCY: NANCY16: Initial work on the boot chunks
The game now loads most of its resources, and ends up at the console
for debugging
Changed paths:
engines/nancy/detection_tables.h
engines/nancy/enginedata.cpp
engines/nancy/enginedata.h
engines/nancy/graphics.cpp
engines/nancy/nancy.cpp
diff --git a/engines/nancy/detection_tables.h b/engines/nancy/detection_tables.h
index 82462e15bfb..01e9b992609 100644
--- a/engines/nancy/detection_tables.h
+++ b/engines/nancy/detection_tables.h
@@ -853,7 +853,7 @@ static const NancyGameDescription gameDescriptions[] = {
AD_ENTRY1s("ciftree.dat", "4014eba84276281456cdba1fa9c03389", 45713842),
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_UNSUPPORTED | ADGF_DROPPLATFORM,
+ ADGF_UNSTABLE | ADGF_DROPPLATFORM,
NANCY8_GUIOPTIONS
},
kGameTypeNancy16
diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index 4254c70a819..6fd618fd24b 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -43,35 +43,53 @@ BSUM::BSUM(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
s.skip(0x17, kGameTypeVampire, kGameTypeVampire);
s.skip(0x49, kGameTypeNancy1, kGameTypeNancy1);
s.skip(0x43, kGameTypeNancy2, kGameTypeNancy9);
- s.skip(0x41, kGameTypeNancy10);
+ s.skip(0x41, kGameTypeNancy10, kGameTypeNancy15);
+ s.skip(0x55, kGameTypeNancy16);
readFilename(s, conversationTextsFilename, kGameTypeNancy6);
readFilename(s, autotextFilename, kGameTypeNancy6);
readFilename(s, fontFilename, kGameTypeNancy12);
readFilename(s, flagsFilename, kGameTypeNancy12);
- s.skip(1, kGameTypeNancy14);
+ // Nancy16 went back to the pre-Nancy14 field order, and dropped both vertical offsets
+ s.syncAsUint16LE(firstScene.sceneID, kGameTypeNancy16);
+ s.syncAsUint16LE(firstScene.frameID, kGameTypeNancy16);
+ s.syncAsUint16LE(startTimeHours, kGameTypeNancy16);
+ s.syncAsUint16LE(startTimeMinutes, kGameTypeNancy16);
+ s.skip(1, kGameTypeNancy16); // Unknown
+ s.syncAsUint16LE(adScene.sceneID, kGameTypeNancy16);
+ s.syncAsUint16LE(adScene.frameID, kGameTypeNancy16);
+ s.skip(2, kGameTypeNancy16); // Unknown
+
+ s.skip(1, kGameTypeNancy14, kGameTypeNancy15);
s.syncAsUint16LE(firstScene.sceneID, kGameTypeVampire, kGameTypeNancy13);
s.skip(0xC, kGameTypeVampire, kGameTypeVampire); // Palette name + unknown 2 bytes
- s.syncAsUint16LE(firstScene.frameID);
- s.syncAsUint16LE(firstScene.sceneID, kGameTypeNancy14);
- s.skip(2, kGameTypeNancy14); // Unknown
- s.syncAsUint16LE(firstScene.verticalOffset);
+ s.syncAsUint16LE(firstScene.frameID, kGameTypeVampire, kGameTypeNancy15);
+ s.syncAsUint16LE(firstScene.sceneID, kGameTypeNancy14, kGameTypeNancy15);
+ s.skip(2, kGameTypeNancy14, kGameTypeNancy15); // Unknown
+ s.syncAsUint16LE(firstScene.verticalOffset, kGameTypeVampire, kGameTypeNancy15);
s.syncAsUint16LE(startTimeHours, kGameTypeVampire, kGameTypeNancy13);
s.syncAsUint16LE(startTimeMinutes, kGameTypeVampire, kGameTypeNancy13);
- s.skip(1, kGameTypeNancy14);
+ s.skip(1, kGameTypeNancy14, kGameTypeNancy15);
- s.skip(1, kGameTypeNancy14);
+ s.skip(1, kGameTypeNancy14, kGameTypeNancy15);
s.syncAsUint16LE(adScene.sceneID, kGameTypeNancy7, kGameTypeNancy13);
- s.syncAsUint16LE(adScene.frameID, kGameTypeNancy7);
- s.syncAsUint16LE(adScene.sceneID, kGameTypeNancy14);
- s.skip(2, kGameTypeNancy14); // Unknown
- s.syncAsUint16LE(adScene.verticalOffset, kGameTypeNancy7);
+ s.syncAsUint16LE(adScene.frameID, kGameTypeNancy7, kGameTypeNancy15);
+ s.syncAsUint16LE(adScene.sceneID, kGameTypeNancy14, kGameTypeNancy15);
+ s.skip(2, kGameTypeNancy14, kGameTypeNancy15); // Unknown
+ s.syncAsUint16LE(adScene.verticalOffset, kGameTypeNancy7, kGameTypeNancy15);
s.skip(0xA4, kGameTypeVampire, kGameTypeNancy2);
- s.skip(3); // Number of object, frame, and logo images
+
+ // Nancy15 added the studio URL, preceded by a few unknown values
+ s.skip(4, kGameTypeNancy15, kGameTypeNancy15); // Unknown
+ s.skip(2, kGameTypeNancy15); // Unknown
+ s.skip(256, kGameTypeNancy15); // Studio URL
+
+ // Nancy16 dropped the image counts together with the OB0/FR0/LG0 chunks they describe
+ s.skip(3, kGameTypeVampire, kGameTypeNancy15); // Number of object, frame, and logo images
if (g_nancy->getEngineData("PLG0")) {
// Partner logos were introduced with nancy4, but at least one nancy3 release
// had one as well. For some reason they didn't port over the code from the
@@ -80,16 +98,16 @@ BSUM::BSUM(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
s.skip(1);
}
- s.skip(4, kGameTypeNancy11); // Unknown
+ s.skip(4, kGameTypeNancy11, kGameTypeNancy14); // Unknown
s.skip(8, kGameTypeVampire, kGameTypeVampire);
readRect(s, extraButtonHotspot, kGameTypeVampire, kGameTypeVampire);
- readRect(s, extraButtonHotspot, kGameTypeNancy2);
- readRect(s, extraButtonHighlightDest, kGameTypeNancy1);
+ readRect(s, extraButtonHotspot, kGameTypeNancy2, kGameTypeNancy14);
+ readRect(s, extraButtonHighlightDest, kGameTypeNancy1, kGameTypeNancy15);
s.skip(0x10, kGameTypeVampire, kGameTypeVampire);
- readRect(s, textboxScreenPosition);
- readRect(s, inventoryBoxScreenPosition);
-
+ readRect(s, textboxScreenPosition, kGameTypeVampire, kGameTypeNancy15);
+ readRect(s, inventoryBoxScreenPosition, kGameTypeVampire, kGameTypeNancy14);
+
readRect(s, menuButtonSrc, kGameTypeVampire, kGameTypeNancy9);
readRect(s, helpButtonSrc, kGameTypeVampire, kGameTypeNancy9);
readRect(s, menuButtonDest, kGameTypeVampire, kGameTypeNancy9);
@@ -97,24 +115,27 @@ BSUM::BSUM(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
readRect(s, menuButtonHighlightSrc, kGameTypeNancy2, kGameTypeNancy9);
readRect(s, helpButtonHighlightSrc, kGameTypeNancy2, kGameTypeNancy9);
- readRect(s, clockHighlightSrc, kGameTypeNancy2);
+ readRect(s, clockHighlightSrc, kGameTypeNancy2, kGameTypeNancy14);
s.skip(0x2, kGameTypeVampire, kGameTypeVampire);
s.syncAsByte(paletteTrans, kGameTypeVampire, kGameTypeVampire);
s.skip(0x2, kGameTypeVampire, kGameTypeVampire);
- s.syncAsByte(rTrans);
- s.syncAsByte(gTrans);
- s.syncAsByte(bTrans);
- s.skip(6); // Black and white
+ s.syncAsByte(rTrans, kGameTypeVampire, kGameTypeNancy15);
+ s.syncAsByte(gTrans, kGameTypeVampire, kGameTypeNancy15);
+ s.syncAsByte(bTrans, kGameTypeVampire, kGameTypeNancy15);
+ s.skip(6, kGameTypeVampire, kGameTypeNancy15); // Black and white
s.syncAsUint16LE(horizontalEdgesSize);
s.syncAsUint16LE(verticalEdgesSize);
- s.syncAsUint16LE(numFonts);
+ // Nancy16 replaced the bitmap fonts with system fonts, and the font count
+ // is now implied by the number of FONT chunks inside the font IFF
+ s.syncAsUint16LE(numFonts, kGameTypeVampire, kGameTypeNancy15);
// Skip data for debug features (diagnostics, version...)
s.skip(0x18, kGameTypeVampire, kGameTypeVampire);
- s.skip(0x1A, kGameTypeNancy1);
+ s.skip(0x1A, kGameTypeNancy1, kGameTypeNancy15);
+ s.skip(0x18, kGameTypeNancy16);
s.syncAsSint16LE(playerTimeMinuteLength);
s.syncAsUint16LE(buttonPressTimeDelay);
@@ -1339,6 +1360,11 @@ LVLN::LVLN(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
PCUI::PCUI(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
flag = chunkStream->readByte();
+
+ if (g_nancy->getGameType() >= kGameTypeNancy16) {
+ readFilename(*chunkStream, uiName);
+ }
+
const uint16 count = chunkStream->readUint16LE();
characters.resize(count);
@@ -1369,6 +1395,27 @@ PUIH::PUIH(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
flag = chunkStream->readByte();
readFilename(*chunkStream, themeName);
readFilename(*chunkStream, swatchImageName);
+
+ if (g_nancy->getGameType() >= kGameTypeNancy16) {
+ readFilename(*chunkStream, journalPrepName);
+ readFilename(*chunkStream, tasklistPrepName);
+ }
+}
+
+TSKL::TSKL(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
+ // The chunk holds a fixed pair of banks, with no count in front of them
+ for (uint i = 0; i < 2; ++i) {
+ SoundBank &bank = soundBanks[i];
+ const uint16 numSounds = chunkStream->readUint16LE();
+ bank.soundNames.resize(numSounds);
+ for (uint16 j = 0; j < numSounds; ++j) {
+ readFilename(*chunkStream, bank.soundNames[j]);
+ }
+
+ bank.channelID = chunkStream->readUint16LE();
+ bank.numLoops = chunkStream->readUint32LE();
+ bank.volume = chunkStream->readUint16LE();
+ }
}
PUIV::PUIV(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index 94a60407fe5..5dfd55342bd 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -80,7 +80,8 @@ struct BSUM : public EngineData {
uint16 horizontalEdgesSize;
uint16 verticalEdgesSize;
- uint16 numFonts;
+ // Nancy16 switched to system fonts, and no longer stores a count here
+ uint16 numFonts = 0;
uint16 playerTimeMinuteLength;
uint16 buttonPressTimeDelay;
@@ -875,6 +876,7 @@ struct PCUI : public EngineData {
PCUI(Common::SeekableReadStream *chunkStream);
byte flag = 0;
+ Common::Path uiName; // Nancy 16+, e.g. "UI_Main"
Common::Array<Character> characters; // indexed by the on-disk slot byte
};
@@ -897,6 +899,25 @@ struct PUIH : public EngineData {
byte flag = 0;
Common::String themeName; // e.g. "Nancy Classic Look (Default)"
Common::String swatchImageName; // e.g. "UI_Swatch_ND"
+
+ // Nancy 16+. Names of the IFFs describing the journal and task list popups
+ Common::Path journalPrepName; // e.g. "Journal_Prep"
+ Common::Path tasklistPrepName; // e.g. "Tasklist_Prep"
+};
+
+// Task list sounds. Introduced in Nancy 16 (per-character boot). Holds two
+// banks of interchangeable sound names, sharing a channel, loop count and volume.
+struct TSKL : public EngineData {
+ struct SoundBank {
+ Common::Array<Common::Path> soundNames;
+ uint16 channelID = 0;
+ uint32 numLoops = 0;
+ uint16 volume = 0;
+ };
+
+ TSKL(Common::SeekableReadStream *chunkStream);
+
+ SoundBank soundBanks[2];
};
// Player-UI random-sound bank. Introduced in Nancy 15 (per-character boot).
diff --git a/engines/nancy/graphics.cpp b/engines/nancy/graphics.cpp
index 2dc26f8cdc6..ee931391d9d 100644
--- a/engines/nancy/graphics.cpp
+++ b/engines/nancy/graphics.cpp
@@ -61,10 +61,10 @@ void GraphicsManager::init() {
_screen.setTransparentColor(getTransColor());
_screen.clear();
+ // OB0 has been dropped in Nancy16+
const ImageChunk *ob0 = (const ImageChunk *)g_nancy->getEngineData("OB0");
- assert(ob0);
-
- g_nancy->_resource->loadImage(ob0->imageName, _object0);
+ if (ob0)
+ g_nancy->_resource->loadImage(ob0->imageName, _object0);
}
void GraphicsManager::draw(bool updateScreen) {
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index e2579c6b2cd..b40777ad715 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -484,7 +484,7 @@ void NancyEngine::bootGameEngine() {
_resource->readCifTree("ciftree", "dat", 1);
_resource->readCifTree("promotree", "dat", 1);
- if (getGameType() >= kGameTypeNancy15) {
+ if (getGameType() == kGameTypeNancy15) {
_resource->readCifTree("PUI_CRE_Nancy_Default", "dat", 1);
// Other player character CIF trees are loaded on demand,
// based on the PCUI chunk:
@@ -494,6 +494,9 @@ void NancyEngine::bootGameEngine() {
// - PUI_CRE_Frank_Default
// - PUI_CRE_HB_Default
// - PUI_CRE_Joe_Default
+ } else if (getGameType() >= kGameTypeNancy16) {
+ // Nancy16 only has a single player character, but kept the per-character tree
+ _resource->readCifTree("PUI_ICE_Nancy_Default", "dat", 1);
}
// Read the static data. Up to Nancy11 it lives in nancy.dat; from Nancy12
@@ -514,10 +517,11 @@ void NancyEngine::bootGameEngine() {
// Load BOOT chunks data
Common::SeekableReadStream *chunkStream = nullptr;
- #define LOAD_BOOT_L(t, s) if (chunkStream = iff->getChunkStream(s), chunkStream) { \
- _engineData.setVal(s, new t(chunkStream)); \
- delete chunkStream; \
- }
+ #define LOAD_BOOT_L2(t, s, k) if (chunkStream = iff->getChunkStream(s), chunkStream) { \
+ _engineData.setVal(k, new t(chunkStream)); \
+ delete chunkStream; \
+ }
+ #define LOAD_BOOT_L(t, s) LOAD_BOOT_L2(t, s, s)
#define LOAD_BOOT(t) LOAD_BOOT_L(t, #t)
#define LOAD_CHUNK(n, t, s, k) iff = _resource->loadIFF(n); \
@@ -531,7 +535,16 @@ void NancyEngine::bootGameEngine() {
LOAD_BOOT_L(ImageChunk, "OB0")
LOAD_BOOT_L(ImageChunk, "FR0")
- LOAD_BOOT_L(ImageChunk, "LG0")
+
+ if (getGameType() <= kGameTypeNancy15) {
+ LOAD_BOOT_L(ImageChunk, "LG0")
+ } else {
+ // Nancy16 shifted the logo chunks by one: LG0 now holds the HeR logo that used to
+ // be in PLGO, while LG1 holds the intro splash that used to be in LG0. Load them
+ // under the keys the logo state expects.
+ LOAD_BOOT_L2(ImageChunk, "LG1", "LG0")
+ LOAD_BOOT_L2(ImageChunk, "LG0", "PLGO")
+ }
// One weird version of nancy3 has a partner logo implemented the same way as the other image chunks
LOAD_BOOT_L(ImageChunk, "PLG0")
@@ -549,7 +562,13 @@ void NancyEngine::bootGameEngine() {
LOAD_BOOT(HELP)
LOAD_BOOT(CRED)
LOAD_BOOT(MENU)
- LOAD_BOOT(LOAD)
+
+ // Nancy16 reused the LOAD chunk name for a small block of savegame naming data;
+ // the save/load screen layout moved to the LOADGAME/SAVEGAME IFFs of the new UI
+ if (getGameType() <= kGameTypeNancy15) {
+ LOAD_BOOT(LOAD)
+ }
+
LOAD_BOOT(SET)
LOAD_BOOT(SDLG)
LOAD_BOOT(MAP)
@@ -597,6 +616,12 @@ void NancyEngine::bootGameEngine() {
LOAD_BOOT(PCUI) // Player-character selector (Nancy / Frank / Joe)
LOAD_BOOT(LDSN) // Player-character "Design Select" screen layout
+ // Nancy 16
+ // Only BSUM, PCUI, LVLN, PCAL, LGx, LOAD, CURS, VIEW and MMIX are left in BOOT.
+ // The LDSN chunk has been removed along with the player-character switcher, and
+ // everything else has moved into the per-character CIF tree, where the popup UI
+ // is now described by one IFF per widget instead of a chunk per widget.
+
_cursor->init(iff->getChunkStream("CURS"));
_graphics->init();
@@ -621,19 +646,27 @@ void NancyEngine::bootGameEngine() {
if (getGameType() >= kGameTypeNancy15) {
const PCUI *pcui = GetEngineData(PCUI);
// Note: the default character is Nancy, so we load her boot chunks here. Her CIF name is
- // PUI_CRE_NANCY_DEFAULT_BOOT.
+ // PUI_CRE_NANCY_DEFAULT_BOOT (PUI_ICE_NANCY_DEFAULT_BOOT in Nancy16).
iff = _resource->loadIFF(Common::Path(pcui->characters[0].defaultImageName + "_boot"));
- LOAD_BOOT(TASK)
- LOAD_BOOT(UIIV)
- LOAD_BOOT(UICO)
- LOAD_BOOT(UICL)
- LOAD_BOOT(UIBW)
- LOAD_BOOT(UINB)
- LOAD_BOOT(SCTB)
+
+ // Nancy16 moved the popup UI descriptions out into one IFF per widget
+ // (named by the PCUI and PUIH chunks), leaving only these behind
+ if (getGameType() <= kGameTypeNancy15) {
+ LOAD_BOOT(TASK)
+ LOAD_BOOT(UIIV)
+ LOAD_BOOT(UICO)
+ LOAD_BOOT(UICL)
+ LOAD_BOOT(UIBW)
+ LOAD_BOOT(UINB)
+ LOAD_BOOT(SCTB)
+ LOAD_BOOT(PUIV) // Player-UI random-sound bank ("can't" responses)
+ } else {
+ LOAD_BOOT(TSKL) // Task list sounds
+ }
+
LOAD_BOOT(UIRC)
LOAD_BOOT(UICM)
LOAD_BOOT(PUIH) // Player-UI header (theme name + swatch image)
- LOAD_BOOT(PUIV) // Player-UI random-sound bank ("can't" responses)
delete iff;
}
@@ -656,8 +689,13 @@ void NancyEngine::bootGameEngine() {
LOAD_CHUNK(bsum->autotextFilename.toString().c_str(), CVTX, "CVTX", "AUTOTEXT")
}
+ #undef LOAD_BOOT_L2
#undef LOAD_BOOT_L
#undef LOAD_BOOT
+
+ if (getGameType() >= kGameTypeNancy16) {
+ error("Game not supported; Use console to inspect game data");
+ }
}
State::State *NancyEngine::getStateObject(NancyState::NancyState state) const {
Commit: 830084d92dca358581c028f02385d5a820511462
https://github.com/scummvm/scummvm/commit/830084d92dca358581c028f02385d5a820511462
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-08-09T00:00:01+03:00
Commit Message:
NANCY: NANCY12: Fix regression from gas/tire gauge overlay handling
Changed paths:
engines/nancy/action/overlay.cpp
diff --git a/engines/nancy/action/overlay.cpp b/engines/nancy/action/overlay.cpp
index ddb0ff76a28..11fae30bb30 100644
--- a/engines/nancy/action/overlay.cpp
+++ b/engines/nancy/action/overlay.cpp
@@ -38,6 +38,21 @@
namespace Nancy {
namespace Action {
+// Nancy12 repurposes the kElapsedPlayerDay dependency as a UI-resource check (fuel/tire).
+// An overlay gated by one - a gas/tire gauge - has a visibility that changes at runtime as
+// the resource does, unlike the usual set-once event-flag overlays.
+static bool hasResourceDependency(const DependencyRecord &dep) {
+ if (dep.type == DependencyType::kElapsedPlayerDay) {
+ return true;
+ }
+ for (uint i = 0; i < dep.children.size(); ++i) {
+ if (hasResourceDependency(dep.children[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
void Overlay::init() {
// Autotext overlays need special handling when blitting
if (_imageName.baseName().hasPrefix("USE_")) {
@@ -76,11 +91,14 @@ void Overlay::handleInput(NancyInput &input) {
}
void Overlay::updateGraphics() {
- // A static overlay gated by a dynamic dependency - e.g. a Nancy12 gas/tire gauge,
- // which is one of a set of sprites each shown for a different resource range - must be
- // visible only while its dependency currently holds. (With the usual set-once event
- // flags _isActive never drops back to false, so this is a no-op there.)
- if (g_nancy->getGameType() >= kGameTypeNancy12 && _state == kRun && _overlayType == kPlayOverlayStatic) {
+ // A static overlay gated by a resource dependency - a Nancy12 gas/tire gauge, one of a
+ // set of sprites each shown for a different resource range - must be visible only while
+ // its dependency currently holds, so track _isActive every frame. This is limited to
+ // resource-gated overlays: ordinary static overlays manage their own per-viewport-frame
+ // visibility in execute() (e.g. appearing only on some frames of a 360 panorama), which
+ // forcing setVisible() here would override.
+ if (g_nancy->getGameType() >= kGameTypeNancy12 && _state == kRun &&
+ _overlayType == kPlayOverlayStatic && hasResourceDependency(_dependencies)) {
setVisible(_isActive);
}
More information about the Scummvm-git-logs
mailing list