[Scummvm-git-logs] scummvm master -> 761f47ebe9cba0d3015ebe59766fe194a29bb09d

bluegr noreply at scummvm.org
Wed Jul 15 20:07:31 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:
31c60e2c3b NANCY: NANCY10: Cleanup comments
46c52f9911 NANCY: NANCY13: Implement changes in the PlaySound AR
ae9a22d545 NANCY: NANCY13: Adapt text view coordinates in ScrollTextBox
761f47ebe9 ENGINES: Remove the default keymap for showing hotspots


Commit: 31c60e2c3b416d447eb59922a8c22c24b9099d4d
    https://github.com/scummvm/scummvm/commit/31c60e2c3b416d447eb59922a8c22c24b9099d4d
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-15T23:07:19+03:00

Commit Message:
NANCY: NANCY10: Cleanup comments

Changed paths:
    engines/nancy/action/puzzle/onebuildpuzzle.cpp
    engines/nancy/enginedata.cpp
    engines/nancy/ui/cellphonepopup.cpp


diff --git a/engines/nancy/action/puzzle/onebuildpuzzle.cpp b/engines/nancy/action/puzzle/onebuildpuzzle.cpp
index f5dcfddccdf..6606a8e27a8 100644
--- a/engines/nancy/action/puzzle/onebuildpuzzle.cpp
+++ b/engines/nancy/action/puzzle/onebuildpuzzle.cpp
@@ -847,8 +847,7 @@ void OneBuildPuzzle::startFinalAnimation() {
 
 void OneBuildPuzzle::stepFinalAnimation() {
 	// animLayout = {cols, framesPerStep, baseX, baseY, spacing, totalRows}.
-	// Matches `case 3` in OneBuildPuzzle @ 0x0047fb75: counter wraps to next
-	// row when (counter / framesPerStep) >= cols.
+	// Counter wraps to the next row when (counter / framesPerStep) >= cols.
 	const int16 cols          = _animLayout[0];
 	const int16 framesPerStep = _animLayout[1] ? _animLayout[1] : 1;
 	const int16 baseX         = _animLayout[2];
diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index d355a9e4704..267443139f0 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -159,8 +159,7 @@ INV::INV(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
 	s.syncAsUint16LE(captionAutoClearTime, kGameTypeNancy3);
 
 	readFilename(s, inventoryBoxIconsImageName);
-	// Nancy13 split the cursor sheet into two images and moved both cursor
-	// image names into the CURS chunk, so the inventory cursors name is no
+	// Nancy13 moved the inventory cursors name into the CURS chunk, so it is no
 	// longer stored here.
 	readFilename(s, inventoryCursorsImageName, kGameTypeVampire, kGameTypeNancy12);
 
@@ -1087,9 +1086,8 @@ UIIV::UIIV(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
 	readRectArray(*chunkStream, slotSrcRects, 16);
 	readRectArray(*chunkStream, slotDestRects, 16);
 
-	// Nancy13 inserted a 16-byte Rect here (before the original 2-byte field):
-	// the clickable bounding region of the inventory item slots, used as a
-	// PtInRect gate before hit-testing the individual slots.
+	// Nancy13 inserted a Rect here (the clickable region of the item slots)
+	// before the original 2-byte field.
 	if (g_nancy->getGameType() >= kGameTypeNancy13)
 		readRect(*chunkStream, slotsHotspot);
 
diff --git a/engines/nancy/ui/cellphonepopup.cpp b/engines/nancy/ui/cellphonepopup.cpp
index 539a5d5cf55..192ca7c6cd8 100644
--- a/engines/nancy/ui/cellphonepopup.cpp
+++ b/engines/nancy/ui/cellphonepopup.cpp
@@ -868,8 +868,8 @@ void CellPhonePopup::openContentView(const Common::String &key, const UICL::SrcD
 
 void CellPhonePopup::openBrowserHome() {
 	// The Web button opens the browser home page (UIBW page 0 — the "River
-	// Heights Wireless" homepage), matching the original's FUN_004dae28(0).
-	// Its in-page hyperlinks then navigate to further pages / the search list.
+	// Heights Wireless" homepage). Its in-page hyperlinks then navigate to
+	// further pages / the search list.
 	const UIBW *browserData = GetEngineData(UIBW);
 	if (browserData && !browserData->pages.empty()) {
 		openContentView(browserData->pages[0].imageName.toString(), _uiclData->browserHeading);


Commit: 46c52f991120763ae2269be06ea8217fcf426ead
    https://github.com/scummvm/scummvm/commit/46c52f991120763ae2269be06ea8217fcf426ead
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-15T23:07:20+03:00

Commit Message:
NANCY: NANCY13: Implement changes in the PlaySound AR

Nancy13 has a list of sounds and a list of event flags in this AR. Now,
the sounds are loaded correctly, and it's possible to start a new game

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


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 34d0726dff1..9034a9cf00e 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -388,9 +388,7 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 		// TODO: debug-only feature, not implemented
 		return nullptr;
 	case 145:
-		// Nancy13 renumbered the sound-playing AR block downwards; PlaySound
-		// moved here (it was 150 up to Nancy12).
-		// TODO: verify the Nancy13 PlaySound on-disk layout matches PlaySound::readData.
+		// Nancy13 moved PlaySound here (was 150).
 		if (g_nancy->getGameType() >= kGameTypeNancy13)
 			return new PlaySound();
 		return nullptr;
diff --git a/engines/nancy/action/soundrecords.cpp b/engines/nancy/action/soundrecords.cpp
index 18ef66d6693..1b0609006ed 100644
--- a/engines/nancy/action/soundrecords.cpp
+++ b/engines/nancy/action/soundrecords.cpp
@@ -34,6 +34,20 @@
 namespace Nancy {
 namespace Action {
 
+// A name beginning with '*' is the forced selection (the marker is stripped);
+// otherwise the played sound is picked at random. The choice is made once, when
+// the record is loaded.
+static uint selectRandomSound(Common::Array<Common::String> &soundNames) {
+	for (uint i = 0; i < soundNames.size(); ++i) {
+		if (soundNames[i].hasPrefix("*")) {
+			soundNames[i].deleteChar(0);
+			return i;
+		}
+	}
+
+	return g_nancy->_randomSource->getRandomNumber(soundNames.size() - 1);
+}
+
 void SetVolume::readData(Common::SeekableReadStream &stream) {
 	channel = stream.readUint16LE();
 	volume = stream.readByte();
@@ -111,6 +125,11 @@ void Set3DSoundListenerPosition::execute() {
 }
 
 void PlaySound::readData(Common::SeekableReadStream &stream) {
+	if (g_nancy->getGameType() >= kGameTypeNancy13) {
+		readDataNancy13(stream);
+		return;
+	}
+
 	_sound.readDIGI(stream);
 
 	if (g_nancy->getGameType() >= kGameTypeNancy3) {
@@ -129,13 +148,50 @@ void PlaySound::readData(Common::SeekableReadStream &stream) {
 	stream.skip(2); // VIDEO_STOP_RENDERING, VIDEO_CONTINUE_RENDERING
 }
 
+void PlaySound::readDataNancy13(Common::SeekableReadStream &stream) {
+	// The sound is a set of candidate names, one picked at random (0 = no sound).
+	const uint16 numNames = stream.readUint16LE();
+	if (numNames > 0) {
+		Common::Array<Common::String> names;
+		names.resize(numNames);
+		for (uint16 i = 0; i < numNames; ++i) {
+			readFilename(stream, names[i]);
+		}
+
+		_sound.channelID = stream.readUint16LE();
+		_sound.numLoops = stream.readUint32LE();
+		_sound.volume = stream.readUint16LE();
+
+		_sound.name = names[selectRandomSound(names)];
+	}
+
+	// No inline SoundEffectDescription anymore, and the scene change is just a
+	// scene ID (frame/vertical offset stay 0).
+	_changeSceneImmediately = stream.readByte();
+	_sceneChange.sceneID = stream.readUint16LE();
+	_afterSoundAction = stream.readByte();	// overlay-refresh control; unused
+
+	// The single event flag became a list of { label, value } pairs.
+	const uint16 numFlags = stream.readUint16LE();
+	_flags.resize(numFlags);
+	for (uint16 i = 0; i < numFlags; ++i) {
+		_flags[i].label = stream.readSint16LE();
+		_flags[i].flag = (byte)stream.readSint16LE();
+	}
+}
+
 void PlaySound::execute() {
 	switch (_state) {
 	case kBegin:
 		g_nancy->_sound->loadSound(_sound, &_soundEffect);
 		g_nancy->_sound->playSound(_sound);
 
-		if (g_nancy->getGameType() >= kGameTypeNancy8) {
+		if (g_nancy->getGameType() >= kGameTypeNancy13) {
+			// Nancy13 sets a list of event flags.
+			for (const FlagDescription &flag : _flags) {
+				NancySceneState.setEventFlag(flag);
+			}
+		} else if (g_nancy->getGameType() >= kGameTypeNancy8) {
 			NancySceneState.setEventFlag(_flag);
 		}
 
@@ -148,6 +204,7 @@ void PlaySound::execute() {
 		}
 
 		if (_changeSceneImmediately) {
+			applyAfterSoundAction();
 			NancySceneState.changeScene(_sceneChange);
 			finishExecution();
 			break;
@@ -162,6 +219,7 @@ void PlaySound::execute() {
 
 		break;
 	case kActionTrigger:
+		applyAfterSoundAction();
 		NancySceneState.changeScene(_sceneChange);
 
 		if (g_nancy->getGameType() <= kGameTypeNancy7) {
@@ -175,6 +233,14 @@ void PlaySound::execute() {
 	}
 }
 
+void PlaySound::applyAfterSoundAction() {
+	// Nancy13: afterSoundAction 1 dismisses the game text box overlay. Value 2
+	// flashes a second overlay that ScummVM doesn't model.
+	if (g_nancy->getGameType() >= kGameTypeNancy13 && _afterSoundAction == 1) {
+		NancySceneState.getTextbox().clear();
+	}
+}
+
 Common::String PlaySound::getRecordTypeName() const {
 	if (g_nancy->getGameType() <= kGameTypeNancy2) {
 		return "PlayDigiSoundAndDie";
@@ -331,20 +397,6 @@ void StopSound::execute() {
 	_sceneChange.execute();
 }
 
-// A name beginning with '*' is the forced selection (the marker is stripped);
-// otherwise the played sound is picked at random. The choice is made once, when
-// the record is loaded.
-static uint selectRandomSound(Common::Array<Common::String> &soundNames) {
-	for (uint i = 0; i < soundNames.size(); ++i) {
-		if (soundNames[i].hasPrefix("*")) {
-			soundNames[i].deleteChar(0);
-			return i;
-		}
-	}
-
-	return g_nancy->_randomSource->getRandomNumber(soundNames.size() - 1);
-}
-
 void PlayRandomSound::readData(Common::SeekableReadStream &stream) {
 	uint16 numSounds = stream.readUint16LE();
 	readFilenameArray(stream, _soundNames, numSounds - 1);
diff --git a/engines/nancy/action/soundrecords.h b/engines/nancy/action/soundrecords.h
index 26e7e79500d..ef60b81c1d2 100644
--- a/engines/nancy/action/soundrecords.h
+++ b/engines/nancy/action/soundrecords.h
@@ -110,10 +110,17 @@ public:
 	SceneChangeDescription _sceneChange;
 	FlagDescription _flag;
 
+	// Nancy13+: a list of flags (was a single flag) and a multi-name random sound.
+	Common::Array<FlagDescription> _flags;
+	byte _afterSoundAction = 0;	// Nancy13+: 1 dismisses the text box overlay
+
 	Common::String getRecordExtraInfo() const override { return Common::String::format("Scene %d", _sceneChange.sceneID); }
 
 protected:
 	Common::String getRecordTypeName() const override;
+
+	void readDataNancy13(Common::SeekableReadStream &stream);
+	void applyAfterSoundAction();
 };
 
 // The same as PlaySound, but with the addition of captioning text,


Commit: ae9a22d5455e00ccdf45ecf6d6b64c0e69f02cb9
    https://github.com/scummvm/scummvm/commit/ae9a22d5455e00ccdf45ecf6d6b64c0e69f02cb9
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-15T23:07:21+03:00

Commit Message:
NANCY: NANCY13: Adapt text view coordinates in ScrollTextBox

Nancy13 stores the viewport as a source rect within the overlay image, so
it's already popup-local. Fixes text display in ScrollTextBox.

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


diff --git a/engines/nancy/ui/scrolltextbox.cpp b/engines/nancy/ui/scrolltextbox.cpp
index 45960a84d06..311deb4a184 100644
--- a/engines/nancy/ui/scrolltextbox.cpp
+++ b/engines/nancy/ui/scrolltextbox.cpp
@@ -104,11 +104,14 @@ void ScrollTextBox::updateGraphics() {
 }
 
 Common::Rect ScrollTextBox::textViewportLocal() const {
-	// The viewport is in screen space; the overlay shares it, so subtract the
-	// dest origin to get popup-local coordinates.
+	// Nancy13 stores the viewport as a source rect within the overlay image, so
+	// it's already popup-local. Earlier games store it in screen space and share
+	// the popup origin, so subtract the dest origin there.
 	Common::Rect r = _textViewportScreen;
-	r.translate(-_header->normalDestRect.left,
-				-_header->normalDestRect.top);
+	if (g_nancy->getGameType() < kGameTypeNancy13) {
+		r.translate(-_header->normalDestRect.left,
+					-_header->normalDestRect.top);
+	}
 	return r;
 }
 


Commit: 761f47ebe9cba0d3015ebe59766fe194a29bb09d
    https://github.com/scummvm/scummvm/commit/761f47ebe9cba0d3015ebe59766fe194a29bb09d
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-15T23:07:22+03:00

Commit Message:
ENGINES: Remove the default keymap for showing hotspots

This resulted in eating the "h" key from all engines.
Engines that utilize the hotspot feature should set their own keymap
to toggle it - existing engines that utilize it, such as touche and
MACS2 already add the keymap themselves.

Changed paths:
    engines/metaengine.cpp


diff --git a/engines/metaengine.cpp b/engines/metaengine.cpp
index 23f10114393..5a2bfb0f09b 100644
--- a/engines/metaengine.cpp
+++ b/engines/metaengine.cpp
@@ -29,7 +29,6 @@
 #include "common/savefile.h"
 #include "common/system.h"
 #include "common/translation.h"
-#include "common/events.h"
 
 #include "engines/dialogs.h"
 
@@ -159,11 +158,6 @@ Common::KeymapArray MetaEngine::initKeymaps(const char *target) const {
 	act->allowKbdRepeats();
 	engineKeyMap->addAction(act);
 
-	act = new Action(kStandardActionToggleHotspots, _("Show hotspots"));
-	act->setEvent(Common::EVENT_HOTSPOTS_SHOW);
-	act->addDefaultInputMapping("h");
-	engineKeyMap->addAction(act);
-
 	return Keymap::arrayOf(engineKeyMap);
 }
 




More information about the Scummvm-git-logs mailing list