[Scummvm-git-logs] scummvm master -> 80c4eb59f959f94247df00acfe080757567dcffe

bluegr noreply at scummvm.org
Tue Jun 23 17:42:45 UTC 2026


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

Summary:
7868ab7fe6 NANCY: Implement RandomizeEventFlags AR for Nancy11+
47f3113ed9 NANCY: Implement the Update3DSound AR for Nancy11+
80c4eb59f9 NANCY: Implement Nancy11+ ARs StartPlayerScrolling, StopPlayerScrolling


Commit: 7868ab7fe6517a24d21643a70c18c7fe62c98d78
    https://github.com/scummvm/scummvm/commit/7868ab7fe6517a24d21643a70c18c7fe62c98d78
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-23T20:42:30+03:00

Commit Message:
NANCY: Implement RandomizeEventFlags AR for Nancy11+

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


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 3d2b434f847..836994490f8 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -290,8 +290,7 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 		//warning("AutotextTextBoxWrite");	// TODO
 		return nullptr;
 	case 96:	// Nancy11
-		warning("UnknownAR96");	// TODO
-		return nullptr;
+		return new RandomizeEventFlags();
 	case 97:
 		return new EventFlags(true);
 	case 98:
diff --git a/engines/nancy/action/datarecords.cpp b/engines/nancy/action/datarecords.cpp
index fec5fbc1676..b5ac2380c8c 100644
--- a/engines/nancy/action/datarecords.cpp
+++ b/engines/nancy/action/datarecords.cpp
@@ -19,6 +19,8 @@
  *
  */
 
+#include "common/random.h"
+
 #include "engines/nancy/nancy.h"
 #include "engines/nancy/util.h"
 
@@ -396,6 +398,23 @@ void EventFlagsMultiHS::execute() {
 	}
 }
 
+void RandomizeEventFlags::readData(Common::SeekableReadStream &stream) {
+	uint16 numFlags = stream.readUint16LE();
+	_flagLabels.resize(numFlags);
+	for (uint i = 0; i < numFlags; ++i) {
+		_flagLabels[i] = stream.readSint16LE();
+	}
+}
+
+void RandomizeEventFlags::execute() {
+	for (uint i = 0; i < _flagLabels.size(); ++i) {
+		NancySceneState.setEventFlag(_flagLabels[i],
+			g_nancy->_randomSource->getRandomBit() ? g_nancy->_true : g_nancy->_false);
+	}
+
+	_isDone = true;
+}
+
 void DifficultyLevel::readData(Common::SeekableReadStream &stream) {
 	_difficulty = stream.readUint16LE();
 	_flag.label = stream.readSint16LE();
diff --git a/engines/nancy/action/datarecords.h b/engines/nancy/action/datarecords.h
index 9022aac7a49..9dba69646af 100644
--- a/engines/nancy/action/datarecords.h
+++ b/engines/nancy/action/datarecords.h
@@ -135,6 +135,18 @@ protected:
 	Common::String getRecordTypeName() const override { return _isCursor ? (_isTerse ? "EventFlagsHSTerse" : "EventFlagsCursorHS") : "EventFlagsMultiHS"; }
 };
 
+// Nancy 11+ AR 96. Sets each of a list of event flags to a random boolean value.
+class RandomizeEventFlags : public ActionRecord {
+public:
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+
+	Common::Array<int16> _flagLabels;
+
+protected:
+	Common::String getRecordTypeName() const override { return "RandomizeEventFlags"; }
+};
+
 // Sets the difficulty level for the current save. Only appears at the start of the game.
 // First appears in nancy1. Nancy1 and nancy2 have three difficulty values, while later games
 // only have two: 0 and 2.


Commit: 47f3113ed98a6d820785b9bd7fe78262f18858a2
    https://github.com/scummvm/scummvm/commit/47f3113ed98a6d820785b9bd7fe78262f18858a2
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-23T20:42:32+03:00

Commit Message:
NANCY: Implement the Update3DSound AR for Nancy11+

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


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 836994490f8..cdb32517d49 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -400,8 +400,7 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 	case 155:
 		return new StopSound(); // StopAndUnloadSound, but we always unload
 	case 156:	// Nancy11
-		warning("Update3DSound");	// TODO
-		return nullptr;
+		return new Update3DSound();
 	case 157:
 		return new PlaySoundCC();
 	case 158:
diff --git a/engines/nancy/action/soundrecords.cpp b/engines/nancy/action/soundrecords.cpp
index 9a84bbbfe5d..1571a1b6375 100644
--- a/engines/nancy/action/soundrecords.cpp
+++ b/engines/nancy/action/soundrecords.cpp
@@ -74,6 +74,31 @@ void FadeSoundToSilence::execute() {
 	}
 }
 
+void Update3DSound::readData(Common::SeekableReadStream &stream) {
+	_channelID = stream.readUint16LE();
+	_posX = stream.readSint32LE();
+	_posY = stream.readSint32LE();
+	_posZ = stream.readSint32LE();
+	_minDistance = stream.readSint32LE();
+	_maxDistance = stream.readSint32LE();
+}
+
+void Update3DSound::execute() {
+	if (_posX != kNoChange && _posY != kNoChange && _posZ != kNoChange) {
+		g_nancy->_sound->update3DSoundPosition(_channelID, _posX, _posY, _posZ);
+	}
+
+	if (_minDistance != kNoChange) {
+		g_nancy->_sound->update3DSoundMinDistance(_channelID, _minDistance);
+	}
+
+	if (_maxDistance != kNoChange) {
+		g_nancy->_sound->update3DSoundMaxDistance(_channelID, _maxDistance);
+	}
+
+	_isDone = true;
+}
+
 void PlaySound::readData(Common::SeekableReadStream &stream) {
 	_sound.readDIGI(stream);
 
diff --git a/engines/nancy/action/soundrecords.h b/engines/nancy/action/soundrecords.h
index 02f5d34cc5a..3700c8454bb 100644
--- a/engines/nancy/action/soundrecords.h
+++ b/engines/nancy/action/soundrecords.h
@@ -58,6 +58,26 @@ private:
 	uint16 _startVolume = 0;
 };
 
+// Nancy 11+ AR 156. Adjusts a playing 3D sound's position and/or its
+// min/max audible distance. A field set to kNoChange is left untouched.
+class Update3DSound : public ActionRecord {
+public:
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+
+	static const int32 kNoChange = 10000;
+
+	uint16 _channelID = 0;
+	int32 _posX = 0;
+	int32 _posY = 0;
+	int32 _posZ = 0;
+	int32 _minDistance = 0;
+	int32 _maxDistance = 0;
+
+protected:
+	Common::String getRecordTypeName() const override { return "Update3DSound"; }
+};
+
 // Used for sound effects. From nancy3 up it includes 3D sound data, which lets
 // the sound move in 3D space as the player rotates/changes scenes. Also supports
 // changing the scene and/or setting a flag
diff --git a/engines/nancy/sound.cpp b/engines/nancy/sound.cpp
index 1d5f606cef3..6be6300ae40 100644
--- a/engines/nancy/sound.cpp
+++ b/engines/nancy/sound.cpp
@@ -532,6 +532,48 @@ void SoundManager::setVolume(const Common::String &chunkName, uint16 volume) {
 	setVolume(_commonSounds[chunkName], volume);
 }
 
+void SoundManager::update3DSoundPosition(uint16 channelID, int32 x, int32 y, int32 z) {
+	if (channelID >= _channels.size())
+		return;
+
+	Channel &chan = _channels[channelID];
+
+	// The original only repositions sounds that play at a fixed point in 3D space
+	if (!chan.effectData || chan.playCommands != kPlaySequentialPosition)
+		return;
+
+	chan.effectData->fixedPosX = x;
+	chan.effectData->fixedPosY = y;
+	chan.effectData->fixedPosZ = z;
+	chan.position.set(x, y, z);
+
+	_shouldRecalculate = true;
+}
+
+void SoundManager::update3DSoundMinDistance(uint16 channelID, uint32 minDistance) {
+	if (channelID >= _channels.size())
+		return;
+
+	Channel &chan = _channels[channelID];
+	if (!chan.effectData)
+		return;
+
+	chan.effectData->minDistance = minDistance;
+	_shouldRecalculate = true;
+}
+
+void SoundManager::update3DSoundMaxDistance(uint16 channelID, uint32 maxDistance) {
+	if (channelID >= _channels.size())
+		return;
+
+	Channel &chan = _channels[channelID];
+	if (!chan.effectData)
+		return;
+
+	chan.effectData->maxDistance = maxDistance;
+	_shouldRecalculate = true;
+}
+
 uint32 SoundManager::getRate(uint16 channelID) {
 	if (channelID >= _channels.size())
 		return 0;
diff --git a/engines/nancy/sound.h b/engines/nancy/sound.h
index 6f6d219081c..50f35796a54 100644
--- a/engines/nancy/sound.h
+++ b/engines/nancy/sound.h
@@ -94,6 +94,12 @@ public:
 	void setVolume(const SoundDescription &description, uint16 volume);
 	void setVolume(const Common::String &chunkName, uint16 volume);
 
+	// Nancy 11+ Update3DSound (AR 156). Adjusts a playing fixed-position
+	// 3D sound's position and/or its min/max audible distance.
+	void update3DSoundPosition(uint16 channelID, int32 x, int32 y, int32 z);
+	void update3DSoundMinDistance(uint16 channelID, uint32 minDistance);
+	void update3DSoundMaxDistance(uint16 channelID, uint32 maxDistance);
+
 	uint32 getRate(uint16 channelID);
 	uint32 getRate(const SoundDescription &description);
 	uint32 getRate(const Common::String &chunkName);


Commit: 80c4eb59f959f94247df00acfe080757567dcffe
    https://github.com/scummvm/scummvm/commit/80c4eb59f959f94247df00acfe080757567dcffe
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-06-23T20:42:34+03:00

Commit Message:
NANCY: Implement Nancy11+ ARs StartPlayerScrolling, StopPlayerScrolling

This is used to disable viewport movement entirely.
Since this flag is now synced in saved games, this will *break* existing
Nancy11 saved games

Changed paths:
    engines/nancy/action/arfactory.cpp
    engines/nancy/action/miscrecords.cpp
    engines/nancy/action/miscrecords.h
    engines/nancy/state/scene.cpp
    engines/nancy/state/scene.h
    engines/nancy/ui/viewport.cpp


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index cdb32517d49..f12443812a0 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -181,11 +181,9 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 		// Nancy 10+
 		return new ControlUIItems();
 	case 30:	// Nancy11
-		warning("StopPlayerScrolling");	// TODO
-		return nullptr;
+		return new StopPlayerScrolling();
 	case 31:	// Nancy11
-		warning("StartPlayerScrolling");	// TODO
-		return nullptr;
+		return new StartPlayerScrolling();
 	case 32:
 		// Nancy 10+
 		return new UIPopupPrepScene();
diff --git a/engines/nancy/action/miscrecords.cpp b/engines/nancy/action/miscrecords.cpp
index 7ac1e104dcd..bdb2ce9b121 100644
--- a/engines/nancy/action/miscrecords.cpp
+++ b/engines/nancy/action/miscrecords.cpp
@@ -413,6 +413,24 @@ void StopTimer::execute() {
 	_isDone = true;
 }
 
+void StopPlayerScrolling::readData(Common::SeekableReadStream &stream) {
+	stream.skip(1);
+}
+
+void StopPlayerScrolling::execute() {
+	NancySceneState.setPlayerScrolling(false);
+	_isDone = true;
+}
+
+void StartPlayerScrolling::readData(Common::SeekableReadStream &stream) {
+	stream.skip(1);
+}
+
+void StartPlayerScrolling::execute() {
+	NancySceneState.setPlayerScrolling(true);
+	_isDone = true;
+}
+
 void GotoMenu::readData(Common::SeekableReadStream &stream) {
 	stream.skip(1);
 }
diff --git a/engines/nancy/action/miscrecords.h b/engines/nancy/action/miscrecords.h
index b5dd38cc958..ac589091ae9 100644
--- a/engines/nancy/action/miscrecords.h
+++ b/engines/nancy/action/miscrecords.h
@@ -293,6 +293,27 @@ protected:
 	Common::String getRecordTypeName() const override { return "StopTimer"; }
 };
 
+// Nancy 11+ AR 30. Disables the player's ability to scroll/pan the viewport
+// (both mouse-edge and keyboard movement). State persists across scene changes.
+class StopPlayerScrolling : public ActionRecord {
+public:
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+
+protected:
+	Common::String getRecordTypeName() const override { return "StopPlayerScrolling"; }
+};
+
+// Nancy 11+ AR 31. Re-enables the player's ability to scroll/pan the viewport.
+class StartPlayerScrolling : public ActionRecord {
+public:
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+
+protected:
+	Common::String getRecordTypeName() const override { return "StartPlayerScrolling"; }
+};
+
 // Returns the player back to the main menu
 class GotoMenu : public ActionRecord {
 public:
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index 503c202f03d..11368fef74f 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -822,6 +822,8 @@ void Scene::synchronize(Common::Serializer &ser) {
 		}
 	}
 
+	ser.syncAsByte(_playerScrollingEnabled, kGameTypeNancy11);
+
 	_isRunningAd = false;
 	ConfMan.removeKey("restore_after_ad", Common::ConfigManager::kTransientDomain);
 
@@ -1315,6 +1317,9 @@ void Scene::initStaticData() {
 	auto *bootSummary = GetEngineData(BSUM);
 	assert(bootSummary);
 
+	// Nancy 11+ AR 30/31. Player scrolling defaults to enabled at game start.
+	_playerScrollingEnabled = true;
+
 	Common::Path imageName = "FRAME";
 
 	if (g_nancy->getGameType() <= kGameTypeNancy9) {
diff --git a/engines/nancy/state/scene.h b/engines/nancy/state/scene.h
index 049557d6f61..f99ba40d4d9 100644
--- a/engines/nancy/state/scene.h
+++ b/engines/nancy/state/scene.h
@@ -170,6 +170,11 @@ public:
 
 	Time getMovementTimeDelta(bool fast) const { return fast ? _sceneState.summary.fastMoveTimeDelta : _sceneState.summary.slowMoveTimeDelta; }
 
+	// Nancy 11+ AR 30/31. Toggles whether the player may scroll/pan the viewport.
+	// Persists across scene changes until changed by another StartPlayerScrolling/StopPlayerScrolling.
+	void setPlayerScrolling(bool enabled) { _playerScrollingEnabled = enabled; }
+	bool getPlayerScrolling() const { return _playerScrollingEnabled; }
+
 	void registerGraphics();
 
 	void synchronize(Common::Serializer &serializer);
@@ -333,6 +338,9 @@ private:
 	bool _destroyOnExit;
 	bool _isRunningAd;
 
+	// Nancy 11+ AR 30/31. Whether the player is currently allowed to scroll the viewport.
+	bool _playerScrollingEnabled = true;
+
 	State _state;
 };
 
diff --git a/engines/nancy/ui/viewport.cpp b/engines/nancy/ui/viewport.cpp
index 5d67681aad8..fc7e1b116d1 100644
--- a/engines/nancy/ui/viewport.cpp
+++ b/engines/nancy/ui/viewport.cpp
@@ -185,6 +185,11 @@ void Viewport::handleInput(NancyInput &input) {
 		}
 	}
 
+	// Nancy 11+ StopPlayerScrolling/StartPlayerScrolling can disable viewport movement entirely
+	if (!NancySceneState.getPlayerScrolling()) {
+		direction = 0;
+	}
+
 	// Perform the movement
 	if (direction) {
 		Time movementDelta = NancySceneState.getMovementTimeDelta(direction & kMoveFast);




More information about the Scummvm-git-logs mailing list