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

fracturehill noreply at scummvm.org
Wed Apr 19 12:05:30 UTC 2023


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

Summary:
01de81a7d7 NANCY: Implement RiddlePuzzle
c8dfd05140 NANCY: Use RandomSource::generateNewSeed()
aeba3f63a1 NANCY: Fix PasswordPuzzle input
2f06dd90c6 NANCY: Clean up puzzle action records
70a916d817 NANCY: Make sure visual ARs stay visible after pause
fe58d58e27 NANCY: Implement OverrideLockPuzzle
bc4f0251f8 NANCY: Improve sound data reading


Commit: 01de81a7d7b2b75330e94c4fa4892f3df8d3efa7
    https://github.com/scummvm/scummvm/commit/01de81a7d7b2b75330e94c4fa4892f3df8d3efa7
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-19T15:02:29+03:00

Commit Message:
NANCY: Implement RiddlePuzzle

Implemented the RiddlePuzzle action record, where
the player has to type in the answers to several riddles.

Changed paths:
  A engines/nancy/action/riddlepuzzle.cpp
  A engines/nancy/action/riddlepuzzle.h
    engines/nancy/action/arfactory.cpp
    engines/nancy/commontypes.cpp
    engines/nancy/commontypes.h
    engines/nancy/module.mk
    engines/nancy/state/scene.cpp
    engines/nancy/state/scene.h
    engines/nancy/ui/textbox.cpp
    engines/nancy/ui/textbox.h


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index ea22ece48f7..b83bd2fbb0f 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -32,6 +32,7 @@
 #include "engines/nancy/action/leverpuzzle.h"
 #include "engines/nancy/action/rippedletterpuzzle.h"
 #include "engines/nancy/action/towerpuzzle.h"
+#include "engines/nancy/action/riddlepuzzle.h"
 
 #include "engines/nancy/state/scene.h"
 
@@ -149,6 +150,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type) {
 		return new TowerPuzzle();
 	case 203:
 		return new RippedLetterPuzzle();
+	case 205:
+		return new RiddlePuzzle();
 	default:
 		error("Action Record type %i is invalid!", type);
 		return nullptr;
diff --git a/engines/nancy/action/riddlepuzzle.cpp b/engines/nancy/action/riddlepuzzle.cpp
new file mode 100644
index 00000000000..ed3fbb2c92c
--- /dev/null
+++ b/engines/nancy/action/riddlepuzzle.cpp
@@ -0,0 +1,332 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "engines/nancy/nancy.h"
+#include "engines/nancy/sound.h"
+#include "engines/nancy/resource.h"
+#include "engines/nancy/util.h"
+#include "engines/nancy/input.h"
+#include "engines/nancy/graphics.h"
+#include "engines/nancy/state/scene.h"
+
+#include "engines/nancy/action/riddlepuzzle.h"
+
+#include "common/random.h"
+
+namespace Nancy {
+namespace Action {
+
+void RiddlePuzzle::init() {
+	_drawSurface.create(_screenPosition.width(), _screenPosition.height(), g_nancy->_graphicsManager->getInputPixelFormat());
+	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
+
+	setTransparent(true);
+	setVisible(true);
+
+	RenderObject::init();
+}
+
+void RiddlePuzzle::readData(Common::SeekableReadStream &stream) {
+	_puzzleState = NancySceneState._riddlePuzzleState;
+	assert(_puzzleState);
+
+	_viewportTextFontID = stream.readUint16LE();
+	_textboxTextFontID = stream.readUint16LE();
+	_cursorBlinkTime = stream.readUint16LE();
+	readRect(stream, _screenPosition);
+	_typeSound.read(stream, SoundDescription::kNormal);
+	_eraseSound.read(stream, SoundDescription::kNormal);
+	_enterSound.read(stream, SoundDescription::kNormal);
+	_successSceneChange.readData(stream);
+	_successSound.read(stream, SoundDescription::kNormal);
+	_exitSceneChange.readData(stream);
+	_exitSound.read(stream, SoundDescription::kNormal);
+	readRect(stream, _exitHotspot);
+
+	_riddles.resize(stream.readUint16LE()) ;
+	stream.skip(4);
+
+	char buf[128];
+	for (uint i = 0; i < _riddles.size(); ++i) {
+		Riddle &riddle = _riddles[i];
+
+		stream.read(buf, 128);
+		buf[127] = '\0';
+		riddle.text = buf;
+		riddle.sound.read(stream, SoundDescription::kNormal);
+
+		for (uint j = 0; j < 8; ++j) {
+			stream.read(buf, 20);
+			buf[19] = '\0';
+			Common::String answer = buf;
+			if (!answer.empty()) {
+				riddle.answers.push_back(answer);
+			}
+		}
+
+		riddle.sceneIncorrect.readData(stream);
+		riddle.soundIncorrect.read(stream, SoundDescription::kNormal);
+		riddle.sceneCorrect.readData(stream);
+		riddle.soundCorrect.read(stream, SoundDescription::kNormal);
+	}
+}
+
+void RiddlePuzzle::execute() {
+	switch (_state) {
+	case kBegin: {
+		init();
+		registerGraphics();
+		_nextBlinkTime = g_nancy->getTotalPlayTime() + _cursorBlinkTime;
+
+		g_nancy->_sound->loadSound(_typeSound);
+		g_nancy->_sound->loadSound(_eraseSound);
+		g_nancy->_sound->loadSound(_enterSound);
+
+		// Make a list of non-answered riddle IDs
+		Common::Array<byte> availableIDs;
+		for (uint i = 0; i < _riddles.size(); ++i) {
+			bool isAlreadySolved = false;
+			for (auto id : _puzzleState->solvedRiddleIDs) {
+				if (i == id) {
+					isAlreadySolved = true;
+					break;
+				}
+			}
+
+			if (!isAlreadySolved) {
+				availableIDs.push_back(i);
+			}
+		}
+
+		if (availableIDs.size() == 0) {
+			_solveState = kSolvedAll;
+			_state = kRun;
+			break;
+		} else {
+			if (_puzzleState->incorrectRiddleID != -1) {
+				_riddleID = _puzzleState->incorrectRiddleID;
+			} else {
+				_riddleID = availableIDs[g_nancy->_randomSource->getRandomNumber(availableIDs.size() - 1)];
+			}
+		}
+
+		g_nancy->_sound->loadSound(_riddles[_riddleID].sound);
+		g_nancy->_sound->playSound(_riddles[_riddleID].sound);
+		NancySceneState.getTextbox().clear();
+		NancySceneState.getTextbox().overrideFontID(_textboxTextFontID);
+		NancySceneState.getTextbox().addTextLine(_riddles[_riddleID].text);
+		NancySceneState.setShouldClearTextbox(false);
+
+		_state = kRun;
+	}
+		// fall through
+	case kRun:
+		switch (_solveState) {
+		case kWaitForSound: 
+			if (!g_nancy->_sound->isSoundPlaying(_riddles[_riddleID].sound)) {
+				_solveState = kNotSolved;
+				g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+
+			}
+
+			break;
+		case kNotSolved: {
+			Time currentTime = g_nancy->getTotalPlayTime();
+
+			if (_playerHasHitReturn) {
+				_playerHasHitReturn = false;
+
+				if (_playerInput.lastChar() == '-') {
+					_playerInput.deleteLastChar();
+					drawText();
+				}
+
+				if (g_nancy->_sound->isSoundPlaying(_enterSound)) {
+					break;
+				}
+
+				for (Common::String &answer : _riddles[_riddleID].answers) {
+					if (_playerInput.equalsIgnoreCase(answer)) {
+						// Solved a riddle
+						_puzzleState->solvedRiddleIDs.push_back(_riddleID);
+
+						if (_puzzleState->solvedRiddleIDs.size() == _riddles.size()) {
+							// Solved all riddles
+							g_nancy->_sound->loadSound(_successSound);
+							g_nancy->_sound->playSound(_successSound);
+							_solveState = kSolvedAll;
+							_state = kActionTrigger;
+
+							break;
+						} else {
+							// Still have riddles to solve
+							g_nancy->_sound->loadSound(_riddles[_riddleID].soundCorrect);
+							g_nancy->_sound->playSound(_riddles[_riddleID].soundCorrect);
+							_solveState = kSolvedOne;
+							_state = kActionTrigger;
+
+							break;
+						}
+					}
+				}
+
+				if (_solveState == kNotSolved) {
+					// Did not solve a riddle
+					g_nancy->_sound->loadSound(_riddles[_riddleID].soundIncorrect);
+					g_nancy->_sound->playSound(_riddles[_riddleID].soundIncorrect);
+					_solveState = kFailed;
+					_state = kActionTrigger;
+				}
+			} else if (currentTime >= _nextBlinkTime) {
+				_nextBlinkTime = currentTime + _cursorBlinkTime;
+
+				if (_playerInput.size() && _playerInput.lastChar() == '-') {
+					_playerInput.deleteLastChar();
+				} else {
+					_playerInput += '-';
+				}
+
+				drawText();
+			}
+
+			break;
+		}
+		default:
+			break;
+		}
+
+		break;
+	case kActionTrigger: {
+		SoundDescription *sound = nullptr;
+		SceneChangeWithFlag *sceneChange = nullptr;
+		_puzzleState->incorrectRiddleID = -1;
+
+		switch (_solveState) {
+		case kNotSolved:
+			sound = &_exitSound;
+			sceneChange = &_exitSceneChange;
+
+			break;
+		case kFailed:
+			sound = &_riddles[_riddleID].soundIncorrect;
+			sceneChange = &_riddles[_riddleID].sceneIncorrect;
+			_puzzleState->incorrectRiddleID = _riddleID;
+
+			break;
+		case kSolvedOne:
+			sound = &_riddles[_riddleID].soundCorrect;
+			sceneChange = &_riddles[_riddleID].sceneCorrect;
+
+			break;
+		case kSolvedAll:
+			sound = &_successSound;
+			sceneChange = &_successSceneChange;
+
+			break;
+		default:
+			return;	
+		}
+
+		if (g_nancy->_sound->isSoundPlaying(*sound)) {
+			return;
+		}
+
+		g_nancy->_sound->stopSound(*sound);
+		g_nancy->_sound->stopSound(_typeSound);
+		g_nancy->_sound->stopSound(_eraseSound);
+		g_nancy->_sound->stopSound(_enterSound);
+
+		sceneChange->execute();
+		g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+		NancySceneState.setShouldClearTextbox(true);
+		finishExecution();
+	}
+	}
+}
+
+void RiddlePuzzle::handleInput(NancyInput &input) {
+	if (_solveState != kNotSolved) {
+		return;
+	}
+
+	if (NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
+		g_nancy->_cursorManager->setCursorType(CursorManager::kExit);
+
+		if (input.input & NancyInput::kLeftMouseButtonUp) {
+			_state = kActionTrigger;
+		}
+	}
+
+	for (uint i = 0; i < input.otherKbdInput.size(); ++i) {
+		Common::KeyState &key = input.otherKbdInput[i];
+		if (key.keycode == Common::KEYCODE_BACKSPACE) {
+			if (_playerInput.size() && _playerInput.lastChar() == '-' ? _playerInput.size() > 1 : true) {
+				if (_playerInput.lastChar() == '-') {
+					_playerInput.deleteChar(_playerInput.size() - 2);
+				} else {
+					_playerInput.deleteLastChar();
+				}
+
+				g_nancy->_sound->playSound(_eraseSound);
+
+				drawText();
+			}
+		} else if (key.keycode == Common::KEYCODE_RETURN) {
+			if (_playerInput.size() == 0 ||
+				(_playerInput.size() == 1 && _playerInput.lastChar() == '-')) {
+					continue;
+				}
+
+				_playerHasHitReturn = true;
+				g_nancy->_sound->playSound(_enterSound);
+		} else if (Common::isAlnum(key.ascii) || Common::isSpace(key.ascii)) {
+			if (_playerInput.size() && _playerInput.lastChar() == '-') {
+				if (_playerInput.size() <= 16) {
+					_playerInput.deleteLastChar();
+					_playerInput += key.ascii;
+					_playerInput += '-';
+					g_nancy->_sound->playSound(_typeSound);
+					drawText();
+				}
+			} else {
+				if (_playerInput.size() <= 15) {
+					_playerInput += key.ascii;
+					g_nancy->_sound->playSound(_typeSound);
+					drawText();
+				}
+			}
+		}
+	}
+}
+
+void RiddlePuzzle::drawText() {
+	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
+	const Graphics::Font *font = g_nancy->_graphicsManager->getFont(_viewportTextFontID);
+
+	Common::Rect bounds = getBounds();
+	Common::Point destPoint(bounds.left, bounds.bottom - font->getFontHeight());
+	font->drawString(&_drawSurface, _playerInput, destPoint.x, destPoint.y, bounds.width(), 0);
+
+	_needsRedraw = true;
+}
+
+} // End of namespace Action
+} // End of namespace Nancy
diff --git a/engines/nancy/action/riddlepuzzle.h b/engines/nancy/action/riddlepuzzle.h
new file mode 100644
index 00000000000..170da3b15f2
--- /dev/null
+++ b/engines/nancy/action/riddlepuzzle.h
@@ -0,0 +1,83 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef NANCY_ACTION_RIDDLEPUZZLE_H
+#define NANCY_ACTION_RIDDLEPUZZLE_H
+
+#include "engines/nancy/renderobject.h"
+#include "engines/nancy/action/actionrecord.h"
+
+namespace Nancy {
+namespace Action {
+
+class RiddlePuzzle : public ActionRecord, public RenderObject {
+public:
+	enum SolveState { kWaitForSound, kNotSolved, kFailed, kSolvedOne, kSolvedAll };
+	RiddlePuzzle() : RenderObject(7) {}
+	virtual ~RiddlePuzzle() {}
+
+	void init() override;
+
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+	void handleInput(NancyInput &input) override;
+
+protected:
+	struct Riddle {
+		Common::String text;
+		SoundDescription sound;
+		Common::Array<Common::String> answers;
+		SceneChangeWithFlag sceneIncorrect;
+		SoundDescription soundIncorrect;
+		SceneChangeWithFlag sceneCorrect;
+		SoundDescription soundCorrect;
+	};
+
+	Common::String getRecordTypeName() const override { return "RiddlePuzzle"; }
+	bool isViewportRelative() const override { return true; }
+
+	void drawText();
+
+	uint16 _viewportTextFontID;
+	uint16 _textboxTextFontID;
+	Time _cursorBlinkTime;
+	SoundDescription _typeSound;
+	SoundDescription _eraseSound;
+	SoundDescription _enterSound;
+	SceneChangeWithFlag _successSceneChange;
+	SoundDescription _successSound;
+	SceneChangeWithFlag _exitSceneChange;
+	SoundDescription _exitSound;
+	Common::Rect _exitHotspot;
+	Common::Array<Riddle> _riddles;
+
+	Time _nextBlinkTime;
+	SolveState _solveState = kWaitForSound;
+	bool _playerHasHitReturn = false;
+	Common::String _playerInput;
+	uint _riddleID = 0;
+	RiddlePuzzleState *_puzzleState = nullptr;
+};
+
+} // End of namespace Action
+} // End of namespace Nancy
+
+#endif // NANCY_ACTION_RIDDLEPUZZLE_H
diff --git a/engines/nancy/commontypes.cpp b/engines/nancy/commontypes.cpp
index 7893e4e313c..f982e5720e5 100644
--- a/engines/nancy/commontypes.cpp
+++ b/engines/nancy/commontypes.cpp
@@ -38,6 +38,18 @@ void SceneChangeDescription::readData(Common::SeekableReadStream &stream, bool l
 	continueSceneSound = stream.readUint16LE();
 }
 
+void SceneChangeWithFlag::readData(Common::SeekableReadStream &stream) {
+	_sceneChange.readData(stream);
+	stream.skip(2); // shouldStopRendering
+	_flag.label = stream.readSint16LE();
+	_flag.flag = stream.readByte();
+}
+
+void SceneChangeWithFlag::execute() {
+	NancySceneState.changeScene(_sceneChange);
+	NancySceneState.setEventFlag(_flag);
+}
+
 void HotspotDescription::readData(Common::SeekableReadStream &stream) {
 	frameID = stream.readUint16LE();
 	readRect(stream, coords);
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index 5aca4bb77ff..c1b7fb2128d 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -128,6 +128,14 @@ struct FlagDescription {
 	byte flag = 0;
 };
 
+struct SceneChangeWithFlag {
+	SceneChangeDescription _sceneChange;
+	FlagDescription _flag;
+
+	void readData(Common::SeekableReadStream &stream);
+	void execute();
+};
+
 // Describes a hotspot
 struct HotspotDescription {
 	uint16 frameID = 0;
@@ -257,6 +265,11 @@ struct TowerPuzzleState {
 	bool playerHasTriedPuzzle;
 };
 
+struct RiddlePuzzleState {
+	Common::Array<byte> solvedRiddleIDs;
+	int8 incorrectRiddleID;
+};
+
 } // End of namespace Nancy
 
 #endif // NANCY_COMMONYPES_H
diff --git a/engines/nancy/module.mk b/engines/nancy/module.mk
index 44c6f1a2f2b..67b0bebe63b 100644
--- a/engines/nancy/module.mk
+++ b/engines/nancy/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS = \
   action/recordtypes.o \
   action/rippedletterpuzzle.o \
   action/rotatinglockpuzzle.o \
+  action/riddlepuzzle.o \
   action/secondarymovie.o \
   action/secondaryvideo.o \
   action/sliderpuzzle.o \
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index 18d09a7729d..cbdf7f63447 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -116,7 +116,8 @@ Scene::Scene() :
 		_lightning(nullptr),
 		_sliderPuzzleState(nullptr),
 		_rippedLetterPuzzleState(nullptr),
-		_towerPuzzleState(nullptr) {}
+		_towerPuzzleState(nullptr),
+		_riddlePuzzleState(nullptr) {}
 
 Scene::~Scene()  {
 	delete _helpButton;
@@ -128,6 +129,8 @@ Scene::~Scene()  {
 	delete _lightning;
 	delete _sliderPuzzleState;
 	delete _rippedLetterPuzzleState;
+	delete _towerPuzzleState;
+	delete _riddlePuzzleState;
 }
 
 void Scene::process() {
@@ -502,8 +505,8 @@ void Scene::synchronize(Common::Serializer &ser) {
 
 		break;
 	}
-	case kGameTypeNancy2 :
-		if (!_rippedLetterPuzzleState || !_towerPuzzleState) {
+	case kGameTypeNancy2 : {
+		if (!_rippedLetterPuzzleState || !_towerPuzzleState || !_riddlePuzzleState) {
 			break;
 		}
 
@@ -527,7 +530,17 @@ void Scene::synchronize(Common::Serializer &ser) {
 			ser.syncArray(_towerPuzzleState->order[i].data(), 6, Common::Serializer::Byte);
 		}
 
+		byte numRiddles;
+		ser.syncAsByte(numRiddles);
+
+		if (ser.isLoading()) {
+			_riddlePuzzleState->solvedRiddleIDs.resize(numRiddles);
+		}
+
+		ser.syncArray(_riddlePuzzleState->solvedRiddleIDs.data(), numRiddles, Common::Serializer::Byte);
+
 		break;
+	}
 	default:
 		break;
 	}
@@ -570,6 +583,7 @@ void Scene::init() {
 		delete _sliderPuzzleState;
 		_sliderPuzzleState = new SliderPuzzleState();
 		_sliderPuzzleState->playerHasTriedPuzzle = false;
+		
 		break;
 	case kGameTypeNancy2:
 		delete _rippedLetterPuzzleState;
@@ -582,6 +596,11 @@ void Scene::init() {
 		_towerPuzzleState = new TowerPuzzleState();
 		_towerPuzzleState->playerHasTriedPuzzle = false;
 		_towerPuzzleState->order.resize(3, Common::Array<int8>(6, -1));
+
+		delete _riddlePuzzleState;
+		_riddlePuzzleState = new RiddlePuzzleState();
+		_riddlePuzzleState->incorrectRiddleID = -1;
+		
 		break;
 	default:
 		break;
diff --git a/engines/nancy/state/scene.h b/engines/nancy/state/scene.h
index 9a2a4e3c4d0..c0ff18eb5bf 100644
--- a/engines/nancy/state/scene.h
+++ b/engines/nancy/state/scene.h
@@ -189,6 +189,7 @@ public:
 	SliderPuzzleState *_sliderPuzzleState;
 	RippedLetterPuzzleState *_rippedLetterPuzzleState;
 	TowerPuzzleState *_towerPuzzleState;
+	RiddlePuzzleState *_riddlePuzzleState;
 
 private:
 	void init();
diff --git a/engines/nancy/ui/textbox.cpp b/engines/nancy/ui/textbox.cpp
index 478462df023..4c12ad1659a 100644
--- a/engines/nancy/ui/textbox.cpp
+++ b/engines/nancy/ui/textbox.cpp
@@ -49,7 +49,8 @@ Textbox::Textbox() :
 		_scrollbarPos(0),
 		_numLines(0),
 		_lastResponseisMultiline(false),
-		_highlightRObj(7) {}
+		_highlightRObj(7),
+		_fontIDOverride(-1) {}
 
 Textbox::~Textbox() {
 	delete _scrollbar;
@@ -144,7 +145,7 @@ void Textbox::drawTextbox() {
 
 	_numLines = 0;
 
-	const Font *font = g_nancy->_graphicsManager->getFont(tbox->conversationFontID);
+	const Font *font = g_nancy->_graphicsManager->getFont(_fontIDOverride == -1 ? tbox->conversationFontID : _fontIDOverride);
 	const Font *highlightFont = g_nancy->_graphicsManager->getFont(tbox->highlightConversationFontID);
 
 	uint maxWidth = _fullSurface.w - tbox->maxWidthDifference - tbox->borderWidth - 2;
@@ -296,6 +297,7 @@ void Textbox::clear() {
 	_hotspots.clear();
 	_scrollbar->resetPosition();
 	_numLines = 0;
+	_fontIDOverride = -1;
 	onScrollbarMove();
 	_needsRedraw = true;
 }
diff --git a/engines/nancy/ui/textbox.h b/engines/nancy/ui/textbox.h
index bb2bb3f745f..ee9ce9364cb 100644
--- a/engines/nancy/ui/textbox.h
+++ b/engines/nancy/ui/textbox.h
@@ -48,7 +48,7 @@ public:
 	void clear();
 
 	void addTextLine(const Common::String &text);
-	void onScrollbarPositionChanged(float data);
+	void overrideFontID(const uint fontID) { _fontIDOverride = fontID; };
 
 	static void assembleTextLine(char *rawCaption, Common::String &output, uint size);
 
@@ -77,6 +77,8 @@ private:
 	bool _needsTextRedraw;
 	float _scrollbarPos;
 
+	int _fontIDOverride;
+
 	static const char _CCBeginToken[];
 	static const char _CCEndToken[];
 	static const char _colorBeginToken[];


Commit: c8dfd05140bb28319b72b2fbc2a392d86d119a1e
    https://github.com/scummvm/scummvm/commit/c8dfd05140bb28319b72b2fbc2a392d86d119a1e
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-19T15:02:30+03:00

Commit Message:
NANCY: Use RandomSource::generateNewSeed()

Changed paths:
    engines/nancy/nancy.cpp


diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 368d7088f82..b32e64ac3c0 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -59,7 +59,7 @@ NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) :
 	g_nancy = this;
 
 	_randomSource = new Common::RandomSource("Nancy");
-	_randomSource->setSeed(_randomSource->getSeed());
+	_randomSource->setSeed(Common::RandomSource::generateNewSeed());
 
 	_input = new InputManager();
 	_sound = new SoundManager();


Commit: aeba3f63a1d6fe9093eaa670b119558e4ec1f9e0
    https://github.com/scummvm/scummvm/commit/aeba3f63a1d6fe9093eaa670b119558e4ec1f9e0
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-19T15:02:30+03:00

Commit Message:
NANCY: Fix PasswordPuzzle input

Allowed typing when the mouse is hovered over the
exit hotspot inside PasswordPuzzle.

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


diff --git a/engines/nancy/action/passwordpuzzle.cpp b/engines/nancy/action/passwordpuzzle.cpp
index f85faf01257..e93b90db778 100644
--- a/engines/nancy/action/passwordpuzzle.cpp
+++ b/engines/nancy/action/passwordpuzzle.cpp
@@ -175,8 +175,6 @@ void PasswordPuzzle::handleInput(NancyInput &input) {
 		if (input.input & NancyInput::kLeftMouseButtonUp) {
 			_state = kActionTrigger;
 		}
-
-		return;
 	}
 
 	for (uint i = 0; i < input.otherKbdInput.size(); ++i) {


Commit: 2f06dd90c64cbc0e641da7fb81f73a2d1a5d2342
    https://github.com/scummvm/scummvm/commit/2f06dd90c64cbc0e641da7fb81f73a2d1a5d2342
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-19T15:02:32+03:00

Commit Message:
NANCY: Clean up puzzle action records

Removed unnecessary comments and added a
SceneChangeWithFlag struct where applicable.

Changed paths:
    engines/nancy/action/conversation.h
    engines/nancy/action/leverpuzzle.cpp
    engines/nancy/action/leverpuzzle.h
    engines/nancy/action/orderingpuzzle.cpp
    engines/nancy/action/orderingpuzzle.h
    engines/nancy/action/overlay.h
    engines/nancy/action/passwordpuzzle.cpp
    engines/nancy/action/passwordpuzzle.h
    engines/nancy/action/rippedletterpuzzle.cpp
    engines/nancy/action/rippedletterpuzzle.h
    engines/nancy/action/rotatinglockpuzzle.cpp
    engines/nancy/action/rotatinglockpuzzle.h
    engines/nancy/action/secondarymovie.h
    engines/nancy/action/secondaryvideo.h
    engines/nancy/action/sliderpuzzle.cpp
    engines/nancy/action/sliderpuzzle.h
    engines/nancy/action/telephone.cpp
    engines/nancy/action/telephone.h
    engines/nancy/action/towerpuzzle.cpp
    engines/nancy/action/towerpuzzle.h
    engines/nancy/commontypes.cpp
    engines/nancy/commontypes.h


diff --git a/engines/nancy/action/conversation.h b/engines/nancy/action/conversation.h
index cb4588dab4a..3a99bd6ccc6 100644
--- a/engines/nancy/action/conversation.h
+++ b/engines/nancy/action/conversation.h
@@ -60,11 +60,11 @@ protected:
 	};
 
 	struct ResponseStruct {
-		ConversationFlags conditionFlags; // 0x01
-		Common::String text; // 0x06
-		Common::String soundName; // 0x196
-		SceneChangeDescription sceneChange; // 0x1A0
-		FlagDescription flagDesc; // 0x1A8
+		ConversationFlags conditionFlags;
+		Common::String text;
+		Common::String soundName;
+		SceneChangeDescription sceneChange;
+		FlagDescription flagDesc;
 
 		bool isOnScreen = false;
 	};
diff --git a/engines/nancy/action/leverpuzzle.cpp b/engines/nancy/action/leverpuzzle.cpp
index 907223516f9..7324420fba3 100644
--- a/engines/nancy/action/leverpuzzle.cpp
+++ b/engines/nancy/action/leverpuzzle.cpp
@@ -82,15 +82,9 @@ void LeverPuzzle::readData(Common::SeekableReadStream &stream) {
 	_moveSound.read(stream, SoundDescription::kNormal);
 	_noMoveSound.read(stream, SoundDescription::kNormal);
 	_solveExitScene.readData(stream);
-	stream.skip(2);
-	_flagOnSolve.label = stream.readSint16LE();
-	_flagOnSolve.flag = stream.readByte();
 	_solveSoundDelay = stream.readUint16LE();
 	_solveSound.read(stream, SoundDescription::kNormal);
 	_exitScene.readData(stream);
-	stream.skip(2);
-	_flagOnExit.label = stream.readSint16LE();
-	_flagOnExit.flag = stream.readByte();
 	readRect(stream, _exitHotspot);
 }
 
@@ -117,7 +111,7 @@ void LeverPuzzle::execute() {
 				}
 			}
 
-			NancySceneState.setEventFlag(_flagOnSolve);
+			NancySceneState.setEventFlag(_solveExitScene._flag);
 			_solveSoundPlayTime = g_nancy->getTotalPlayTime() + _solveSoundDelay * 1000;
 			_solveState = kPlaySound;
 			break;
@@ -145,10 +139,9 @@ void LeverPuzzle::execute() {
 		g_nancy->_sound->stopSound(_noMoveSound);
 
 		if (_solveState == kNotSolved) {
-			NancySceneState.changeScene(_exitScene);
-			NancySceneState.setEventFlag(_flagOnExit);
+			_exitScene.execute();
 		} else {
-			NancySceneState.changeScene(_solveExitScene);
+			NancySceneState.changeScene(_solveExitScene._sceneChange);
 		}
 
 		finishExecution();
diff --git a/engines/nancy/action/leverpuzzle.h b/engines/nancy/action/leverpuzzle.h
index 5c4875e904e..da9fad9ceb2 100644
--- a/engines/nancy/action/leverpuzzle.h
+++ b/engines/nancy/action/leverpuzzle.h
@@ -42,19 +42,17 @@ public:
 	void handleInput(NancyInput &input) override;
 	void onPause(bool pause) override;
 
-	Common::String _imageName; // 0x0
-	Common::Array<Common::Array<Common::Rect>> _srcRects; // 0xA, 0xC0 bytes
-	Common::Array<Common::Rect> _destRects; // 0xCA, 0x30 bytes
-	Common::Array<byte> _correctSequence; // 0xFA, 3 bytes
-	SoundDescription _moveSound; // 0x100
-	SoundDescription _noMoveSound; // 0x122
-	SceneChangeDescription _solveExitScene; // 0x144
-	FlagDescription _flagOnSolve; // 0x14E
-	uint16 _solveSoundDelay = 0; // 0x151
-	SoundDescription _solveSound; // 0x153
-	SceneChangeDescription _exitScene; // 0x175
-	FlagDescription _flagOnExit; // 0x17F
-	Common::Rect _exitHotspot; // 0x182
+	Common::String _imageName;
+	Common::Array<Common::Array<Common::Rect>> _srcRects;
+	Common::Array<Common::Rect> _destRects;
+	Common::Array<byte> _correctSequence;
+	SoundDescription _moveSound;
+	SoundDescription _noMoveSound;
+	SceneChangeWithFlag _solveExitScene;
+	uint16 _solveSoundDelay = 0;
+	SoundDescription _solveSound;
+	SceneChangeWithFlag _exitScene;
+	Common::Rect _exitHotspot;
 
 	Common::Array<byte> _playerSequence;
 	Common::Array<bool> _leverDirection;
diff --git a/engines/nancy/action/orderingpuzzle.cpp b/engines/nancy/action/orderingpuzzle.cpp
index f5f561c24e1..4e52d4f5021 100644
--- a/engines/nancy/action/orderingpuzzle.cpp
+++ b/engines/nancy/action/orderingpuzzle.cpp
@@ -105,15 +105,9 @@ void OrderingPuzzle::readData(Common::SeekableReadStream &stream) {
 	}
 
 	_solveExitScene.readData(stream, ser.getVersion() == kGameTypeVampire);
-	ser.skip(2); // shouldStopRendering, useless
-	ser.syncAsUint16LE(_flagOnSolve.label);
-	ser.syncAsByte(_flagOnSolve.flag);
 	ser.syncAsUint16LE(_solveSoundDelay);
 	_solveSound.read(stream, SoundDescription::kNormal);
 	_exitScene.readData(stream, ser.getVersion() == kGameTypeVampire);
-	stream.skip(2); // shouldStopRendering, useless
-	_flagOnExit.label = stream.readSint16LE();
-	_flagOnExit.flag = stream.readByte();
 	readRect(stream, _exitHotspot);
 }
 
@@ -146,7 +140,7 @@ void OrderingPuzzle::execute() {
 				}
 			}
 
-			NancySceneState.setEventFlag(_flagOnSolve);
+			NancySceneState.setEventFlag(_solveExitScene._flag);
 			_solveSoundPlayTime = g_nancy->getTotalPlayTime() + _solveSoundDelay * 1000;
 			_solveState = kPlaySound;
 			// fall through
@@ -175,10 +169,9 @@ void OrderingPuzzle::execute() {
 		g_nancy->_sound->stopSound(_solveSound);
 
 		if (_solveState == kNotSolved) {
-			NancySceneState.changeScene(_exitScene);
-			NancySceneState.setEventFlag(_flagOnExit);
+			_exitScene.execute();
 		} else {
-			NancySceneState.changeScene(_solveExitScene);
+			NancySceneState.changeScene(_solveExitScene._sceneChange);
 		}
 
 		finishExecution();
diff --git a/engines/nancy/action/orderingpuzzle.h b/engines/nancy/action/orderingpuzzle.h
index b6ebcf107e6..cdebe918f68 100644
--- a/engines/nancy/action/orderingpuzzle.h
+++ b/engines/nancy/action/orderingpuzzle.h
@@ -42,19 +42,17 @@ public:
 	void handleInput(NancyInput &input) override;
 	void onPause(bool pause) override;
 
-	Common::String _imageName; // 0x00
-	Common::Array<Common::Rect> _srcRects; // 0xC, 15
-	Common::Array<Common::Rect> _destRects; // 0xFC, 15
-	uint16 _sequenceLength = 0; // 0x1EC;
-	Common::Array<byte> _correctSequence; // 0x1EE, 15 bytes
-	Nancy::SoundDescription _clickSound; // 0x1FD, kNormal
-	SceneChangeDescription _solveExitScene; // 0x21F
-	FlagDescription _flagOnSolve; // 0x229
-	uint16 _solveSoundDelay = 0; // 0x22C
-	Nancy::SoundDescription _solveSound; // 0x22E
-	SceneChangeDescription _exitScene; // 0x250
-	FlagDescription _flagOnExit; // 0x25A
-	Common::Rect _exitHotspot; // 0x25D
+	Common::String _imageName;
+	Common::Array<Common::Rect> _srcRects;
+	Common::Array<Common::Rect> _destRects;
+	uint16 _sequenceLength = 0;
+	Common::Array<byte> _correctSequence;
+	Nancy::SoundDescription _clickSound;
+	SceneChangeWithFlag _solveExitScene;
+	uint16 _solveSoundDelay = 0;
+	Nancy::SoundDescription _solveSound;
+	SceneChangeWithFlag _exitScene;
+	Common::Rect _exitHotspot;
 
 	SolveState _solveState = kNotSolved;
 	Graphics::ManagedSurface _image;
diff --git a/engines/nancy/action/overlay.h b/engines/nancy/action/overlay.h
index cb66adad9eb..4452b2b1798 100644
--- a/engines/nancy/action/overlay.h
+++ b/engines/nancy/action/overlay.h
@@ -79,9 +79,9 @@ public:
 	Time _frameTime;
 	FlagDescription _interruptCondition;
 	SceneChangeDescription _sceneChange;
-	MultiEventFlagDescription _flagsOnTrigger; // 0x2A
+	MultiEventFlagDescription _flagsOnTrigger;
 
-	Nancy::SoundDescription _sound; // 0x52
+	Nancy::SoundDescription _sound;
 
 	// Describes a single frame in this animation
 	Common::Array<Common::Rect> _srcRects;
diff --git a/engines/nancy/action/passwordpuzzle.cpp b/engines/nancy/action/passwordpuzzle.cpp
index e93b90db778..7c3f995400e 100644
--- a/engines/nancy/action/passwordpuzzle.cpp
+++ b/engines/nancy/action/passwordpuzzle.cpp
@@ -56,19 +56,10 @@ void PasswordPuzzle::readData(Common::SeekableReadStream &stream) {
 	buf[19] = '\0';
 	_password = buf;
 	_solveExitScene.readData(stream);
-	stream.skip(2);
-	_flagOnSolve.label = stream.readSint16LE();
-	_flagOnSolve.flag = stream.readByte();
 	_solveSound.read(stream, SoundDescription::kNormal);
 	_failExitScene.readData(stream);
-	stream.skip(2);
-	_flagOnFail.label = stream.readSint16LE();
-	_flagOnFail.flag = stream.readByte();
 	_failSound.read(stream, SoundDescription::kNormal);
 	_exitScene.readData(stream);
-	stream.skip(2);
-	_flagOnExit.label = stream.readSint16LE();
-	_flagOnExit.flag = stream.readByte();
 	readRect(stream, _exitHotspot);
 }
 
@@ -145,21 +136,17 @@ void PasswordPuzzle::execute() {
 	case kActionTrigger:
 		switch (_solveState) {
 		case kNotSolved:
-			NancySceneState.changeScene(_exitScene);
-			NancySceneState.setEventFlag(_flagOnExit);
+			_exitScene.execute();
 			break;
 		case kFailed:
-			NancySceneState.changeScene(_failExitScene);
-			NancySceneState.setEventFlag(_flagOnFail.label);
+			_failExitScene.execute();
 			break;
 		case kSolved:
-			NancySceneState.changeScene(_solveExitScene);
-			NancySceneState.setEventFlag(_flagOnSolve.label);
+			_solveExitScene.execute();
 			break;
 		}
 		
 		g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
-
 		finishExecution();
 	}
 }
diff --git a/engines/nancy/action/passwordpuzzle.h b/engines/nancy/action/passwordpuzzle.h
index 951893ad8d8..17a38c243c9 100644
--- a/engines/nancy/action/passwordpuzzle.h
+++ b/engines/nancy/action/passwordpuzzle.h
@@ -42,22 +42,19 @@ public:
 	void handleInput(NancyInput &input) override;
 	void onPause(bool pause) override;
 
-	uint16 _fontID = 0; // 0x00
-	Time _cursorBlinkTime; // 0x2
-	Common::Rect _nameBounds; // 0x4
-	Common::Rect _passwordBounds; // 0x14
+	uint16 _fontID = 0;
+	Time _cursorBlinkTime;
+	Common::Rect _nameBounds;
+	Common::Rect _passwordBounds;
 	// _screenPosition 0x24
-	Common::String _name; // 0x34, 20 bytes long
-	Common::String _password; // 0x48, 20 bytes long
-	SceneChangeDescription _solveExitScene; // 0x5A
-	FlagDescription _flagOnSolve; // 0x66
-	SoundDescription _solveSound; // 0x69
-	SceneChangeDescription _failExitScene; // 0x8B
-	FlagDescription _flagOnFail; // 0x95
-	SoundDescription _failSound; // 0x98
-	SceneChangeDescription _exitScene; // 0xBA
-	FlagDescription _flagOnExit; // 0xC4
-	Common::Rect _exitHotspot; // 0xC7
+	Common::String _name;
+	Common::String _password;
+	SceneChangeWithFlag _solveExitScene;
+	SoundDescription _solveSound;
+	SceneChangeWithFlag _failExitScene;
+	SoundDescription _failSound;
+	SceneChangeWithFlag _exitScene;
+	Common::Rect _exitHotspot;
 
 	Common::String _playerNameInput;
 	Common::String _playerPasswordInput;
diff --git a/engines/nancy/action/rippedletterpuzzle.cpp b/engines/nancy/action/rippedletterpuzzle.cpp
index efd4ae0f186..676ed220ff0 100644
--- a/engines/nancy/action/rippedletterpuzzle.cpp
+++ b/engines/nancy/action/rippedletterpuzzle.cpp
@@ -92,19 +92,9 @@ void RippedLetterPuzzle::readData(Common::SeekableReadStream &stream) {
 	_rotateSound.read(stream, SoundDescription::kNormal);
 
 	_solveExitScene.readData(stream);
-	stream.skip(2); // shouldStopRendering, useless
-
-	_flagOnSolve.label = stream.readSint16LE();
-	_flagOnSolve.flag = stream.readByte();
-
 	_solveSound.read(stream, SoundDescription::kNormal);
 
 	_exitScene.readData(stream);
-
-	stream.skip(2); // shouldStopRendering, useless
-	_flagOnExit.label = stream.readSint16LE();
-	_flagOnExit.flag = stream.readByte();
-
 	readRect(stream, _exitHotspot);
 }
 
@@ -155,12 +145,10 @@ void RippedLetterPuzzle::execute() {
 	case kActionTrigger :
 		switch (_solveState) {
 		case kNotSolved:
-			NancySceneState.changeScene(_exitScene);
-			NancySceneState.setEventFlag(_flagOnExit);
+			_exitScene.execute();
 			break;
 		case kWaitForSound:
-			NancySceneState.changeScene(_solveExitScene);
-			NancySceneState.setEventFlag(_flagOnSolve);
+			_solveExitScene.execute();
 			_puzzleState->playerHasTriedPuzzle = false;
 			break;
 		}
diff --git a/engines/nancy/action/rippedletterpuzzle.h b/engines/nancy/action/rippedletterpuzzle.h
index 6d4f57a25cf..1293710c1b5 100644
--- a/engines/nancy/action/rippedletterpuzzle.h
+++ b/engines/nancy/action/rippedletterpuzzle.h
@@ -53,11 +53,9 @@ public:
 	SoundDescription _takeSound;
 	SoundDescription _dropSound;
 	SoundDescription _rotateSound;
-	SceneChangeDescription _solveExitScene;
+	SceneChangeWithFlag _solveExitScene;
 	SoundDescription _solveSound;
-	FlagDescription _flagOnSolve;
-	SceneChangeDescription _exitScene;
-	FlagDescription _flagOnExit;
+	SceneChangeWithFlag _exitScene;
 	Common::Rect _exitHotspot;
 
 	RenderObject _pickedUpPiece;
diff --git a/engines/nancy/action/rotatinglockpuzzle.cpp b/engines/nancy/action/rotatinglockpuzzle.cpp
index ecf53176f81..8a1dbf28881 100644
--- a/engines/nancy/action/rotatinglockpuzzle.cpp
+++ b/engines/nancy/action/rotatinglockpuzzle.cpp
@@ -94,15 +94,10 @@ void RotatingLockPuzzle::readData(Common::SeekableReadStream &stream) {
 
 	_clickSound.read(stream, SoundDescription::kNormal);
 	_solveExitScene.readData(stream);
-	stream.skip(2); // shouldStopRendering, useless
-	_flagOnSolve.label = stream.readSint16LE();
-	_flagOnSolve.flag = stream.readByte();
 	_solveSoundDelay = stream.readUint16LE();
 	_solveSound.read(stream, SoundDescription::kNormal);
+
 	_exitScene.readData(stream);
-	stream.skip(2); // shouldStopRendering, useless
-	_flagOnExit.label = stream.readSint16LE();
-	_flagOnExit.flag = stream.readByte();
 	readRect(stream, _exitHotspot);
 }
 
@@ -130,7 +125,7 @@ void RotatingLockPuzzle::execute() {
 				}
 			}
 
-			NancySceneState.setEventFlag(_flagOnSolve);
+			NancySceneState.setEventFlag(_solveExitScene._flag);
 			_solveSoundPlayTime = g_nancy->getTotalPlayTime() + _solveSoundDelay * 1000;
 			_solveState = kPlaySound;
 			// fall through
@@ -155,10 +150,9 @@ void RotatingLockPuzzle::execute() {
 		g_nancy->_sound->stopSound(_solveSound);
 
 		if (_solveState == kNotSolved) {
-			NancySceneState.changeScene(_exitScene);
-			NancySceneState.setEventFlag(_flagOnExit);
+			_exitScene.execute();
 		} else {
-			NancySceneState.changeScene(_solveExitScene);
+			NancySceneState.changeScene(_solveExitScene._sceneChange);
 		}
 
 		finishExecution();
diff --git a/engines/nancy/action/rotatinglockpuzzle.h b/engines/nancy/action/rotatinglockpuzzle.h
index a9841130e51..cf0b5a1e231 100644
--- a/engines/nancy/action/rotatinglockpuzzle.h
+++ b/engines/nancy/action/rotatinglockpuzzle.h
@@ -42,21 +42,18 @@ public:
 	void handleInput(NancyInput &input) override;
 	void onPause(bool pause) override;
 
-	Common::String _imageName; // 0x00
-	// 0xA numDials
-	Common::Array<Common::Rect> _srcRects; // 0xC, 10
-	Common::Array<Common::Rect> _destRects; // 0xAC, 8
-	Common::Array<Common::Rect> _upHotspots; // 0x12C, 8
-	Common::Array<Common::Rect> _downHotspots; // 0x1AC, 8
-	Common::Array<byte> _correctSequence; // 0x22C
-	Nancy::SoundDescription _clickSound; // 0x234, kNormal
-	SceneChangeDescription _solveExitScene; // 0x256
-	FlagDescription _flagOnSolve; // 0x260
-	uint16 _solveSoundDelay = 0; // 0x263
-	Nancy::SoundDescription _solveSound; // 0x265
-	SceneChangeDescription _exitScene; // 0x287
-	FlagDescription _flagOnExit; // 0x291
-	Common::Rect _exitHotspot; // 0x294
+	Common::String _imageName;
+	Common::Array<Common::Rect> _srcRects;
+	Common::Array<Common::Rect> _destRects;
+	Common::Array<Common::Rect> _upHotspots;
+	Common::Array<Common::Rect> _downHotspots;
+	Common::Array<byte> _correctSequence;
+	Nancy::SoundDescription _clickSound;
+	SceneChangeWithFlag _solveExitScene;
+	uint16 _solveSoundDelay = 0;
+	Nancy::SoundDescription _solveSound;
+	SceneChangeWithFlag _exitScene;
+	Common::Rect _exitHotspot;
 
 	SolveState _solveState = kNotSolved;
 	Graphics::ManagedSurface _image;
diff --git a/engines/nancy/action/secondarymovie.h b/engines/nancy/action/secondarymovie.h
index 79e15f5d40a..01756e4c742 100644
--- a/engines/nancy/action/secondarymovie.h
+++ b/engines/nancy/action/secondarymovie.h
@@ -56,21 +56,21 @@ public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
 
-	Common::String _videoName; // 0x00
+	Common::String _videoName;
 	Common::String _paletteName;
 
-	uint16 _videoSceneChange = kMovieNoSceneChange; // 0x1C
-	byte _playerCursorAllowed = kPlayerCursorAllowed; // 0x1E
-	byte _playDirection = kPlayMovieForward; // 0x20, 2E
-	uint16 _firstFrame = 0; // 0x22, 30
-	uint16 _lastFrame = 0; // 0x24, 32
-	Common::Array<FlagAtFrame> _frameFlags; // 0x26
-	MultiEventFlagDescription _triggerFlags; // 0x80
+	uint16 _videoSceneChange = kMovieNoSceneChange;
+	byte _playerCursorAllowed = kPlayerCursorAllowed;
+	byte _playDirection = kPlayMovieForward;
+	uint16 _firstFrame = 0;
+	uint16 _lastFrame = 0;
+	Common::Array<FlagAtFrame> _frameFlags;
+	MultiEventFlagDescription _triggerFlags;
 
-	SoundDescription _sound; // 0xA8
+	SoundDescription _sound;
 
-	SceneChangeDescription _sceneChange; // 0xCA
-	Common::Array<SecondaryVideoDescription> _videoDescs; // 0xD4
+	SceneChangeDescription _sceneChange;
+	Common::Array<SecondaryVideoDescription> _videoDescs;
 
 protected:
 	Common::String getRecordTypeName() const override { return "PlaySecondaryMovie"; }
diff --git a/engines/nancy/action/secondaryvideo.h b/engines/nancy/action/secondaryvideo.h
index 7bf8279c463..927e650cfc1 100644
--- a/engines/nancy/action/secondaryvideo.h
+++ b/engines/nancy/action/secondaryvideo.h
@@ -58,15 +58,15 @@ public:
 	uint16 _videoFormat = kLargeVideoFormat;
 	uint16 _videoHotspots = kVideoHotspots;
 
-	uint16 _loopFirstFrame = 0; // 0x1E
-	uint16 _loopLastFrame = 0; // 0x20
-	uint16 _onHoverFirstFrame = 0; // 0x22
-	uint16 _onHoverLastFrame = 0; // 0x24
-	uint16 _onHoverEndFirstFrame = 0; // 0x26
-	uint16 _onHoverEndLastFrame = 0; // 0x28
-	SceneChangeDescription _sceneChange; // 0x2A
-	// unknown byte
-	Common::Array<SecondaryVideoDescription> _videoDescs; // 0x35
+	uint16 _loopFirstFrame = 0;
+	uint16 _loopLastFrame = 0;
+	uint16 _onHoverFirstFrame = 0;
+	uint16 _onHoverLastFrame = 0;
+	uint16 _onHoverEndFirstFrame = 0;
+	uint16 _onHoverEndLastFrame = 0;
+	SceneChangeDescription _sceneChange;
+
+	Common::Array<SecondaryVideoDescription> _videoDescs;
 
 protected:
 	Common::String getRecordTypeName() const override { return Common::String::format("PlaySecondaryVideoChan%i", channel); }
diff --git a/engines/nancy/action/sliderpuzzle.cpp b/engines/nancy/action/sliderpuzzle.cpp
index 3f4b5ce55cf..69b437b7aba 100644
--- a/engines/nancy/action/sliderpuzzle.cpp
+++ b/engines/nancy/action/sliderpuzzle.cpp
@@ -105,14 +105,8 @@ void SliderPuzzle::readData(Common::SeekableReadStream &stream) {
 
 	_clickSound.read(stream, SoundDescription::kNormal);
 	_solveExitScene.readData(stream);
-	stream.skip(2);
-	_flagOnSolve.label = stream.readSint16LE();
-	_flagOnSolve.flag = stream.readByte();
 	_solveSound.read(stream, SoundDescription::kNormal);
 	_exitScene.readData(stream);
-	stream.skip(2);
-	_flagOnExit.label = stream.readSint16LE();
-	_flagOnExit.flag = stream.readByte();
 	readRect(stream, _exitHotspot);
 }
 
@@ -171,12 +165,10 @@ void SliderPuzzle::execute() {
 	case kActionTrigger:
 		switch (_solveState) {
 		case kNotSolved:
-			NancySceneState.changeScene(_exitScene);
-			NancySceneState.setEventFlag(_flagOnExit);
+			_exitScene.execute();
 			break;
 		case kWaitForSound:
-			NancySceneState.changeScene(_solveExitScene);
-			NancySceneState.setEventFlag(_flagOnSolve);
+			_solveExitScene.execute();
 			_puzzleState->playerHasTriedPuzzle = false;
 			break;
 		}
diff --git a/engines/nancy/action/sliderpuzzle.h b/engines/nancy/action/sliderpuzzle.h
index b38bc1900c1..8ae4b35aec8 100644
--- a/engines/nancy/action/sliderpuzzle.h
+++ b/engines/nancy/action/sliderpuzzle.h
@@ -51,19 +51,17 @@ public:
 	SPUZ *_spuzData = nullptr;
 	SliderPuzzleState *_puzzleState = nullptr;
 
-	Common::String _imageName; // 0x00
-	uint16 _width = 0; // 0xA
-	uint16 _height = 0; // 0xC
-	Common::Array<Common::Array<Common::Rect>> _srcRects; // 0x0E, size 0x240
-	Common::Array<Common::Array<Common::Rect>> _destRects; // 0x24E, size 0x240
-	Common::Array<Common::Array<int16>> _correctTileOrder; // 0x48E, size 0x48
-	SoundDescription _clickSound; // 0x4D6
-	SceneChangeDescription _solveExitScene; // 0x4F8
-	FlagDescription _flagOnSolve; // 0x502
-	SoundDescription _solveSound; // 0x505
-	SceneChangeDescription _exitScene; // 0x527
-	FlagDescription _flagOnExit; // 0x531
-	Common::Rect _exitHotspot; // 0x534
+	Common::String _imageName;
+	uint16 _width = 0;
+	uint16 _height = 0;
+	Common::Array<Common::Array<Common::Rect>> _srcRects;
+	Common::Array<Common::Array<Common::Rect>> _destRects;
+	Common::Array<Common::Array<int16>> _correctTileOrder;
+	SoundDescription _clickSound;
+	SceneChangeWithFlag _solveExitScene;
+	SoundDescription _solveSound;
+	SceneChangeWithFlag _exitScene;
+	Common::Rect _exitHotspot;
 
 	SolveState _solveState = kNotSolved;
 	Graphics::ManagedSurface _image;
diff --git a/engines/nancy/action/telephone.cpp b/engines/nancy/action/telephone.cpp
index bae9184d7df..fe15a099208 100644
--- a/engines/nancy/action/telephone.cpp
+++ b/engines/nancy/action/telephone.cpp
@@ -87,13 +87,7 @@ void Telephone::readData(Common::SeekableReadStream &stream) {
 	textBuf[199] = '\0';
 	_dialAgainString = textBuf;
 	_reloadScene.readData(stream);
-	stream.skip(2);
-	_flagOnReload.label = stream.readSint16LE();
-	_flagOnReload.flag = stream.readUint16LE();
 	_exitScene.readData(stream);
-	stream.skip(2);
-	_flagOnExit.label = stream.readSint16LE();
-	_flagOnExit.flag = stream.readUint16LE();
 	readRect(stream, _exitHotspot);
 
 	uint numCalls = stream.readUint16LE();
@@ -113,9 +107,6 @@ void Telephone::readData(Common::SeekableReadStream &stream) {
 		textBuf[199] = '\0';
 		call.text = textBuf;
 		call.sceneChange.readData(stream);
-		stream.skip(2);
-		call.flag.label = stream.readSint16LE();
-		call.flag.flag = stream.readUint16LE();
 	}
 }
 
@@ -223,23 +214,20 @@ void Telephone::execute() {
 	case kActionTrigger:
 		switch (_callState) {
 		case kBadNumber:
-			NancySceneState.changeScene(_reloadScene);
+			_reloadScene.execute();
 			_calledNumber.clear();
-			NancySceneState.setEventFlag(_flagOnReload);
 			_state = kRun;
 			_callState = kWaiting;
 
 			break;
 		case kCall: {
 			PhoneCall &call = _calls[_selected];
-			NancySceneState.changeScene(call.sceneChange);
-			NancySceneState.setEventFlag(call.flag);
+			call.sceneChange.execute();
 
 			break;
 		}
 		case kHangUp:
-			NancySceneState.changeScene(_exitScene);
-			NancySceneState.setEventFlag(_flagOnExit);
+			_exitScene.execute();
 
 			break;
 		default:
diff --git a/engines/nancy/action/telephone.h b/engines/nancy/action/telephone.h
index c5979e32bf7..8273ae674a8 100644
--- a/engines/nancy/action/telephone.h
+++ b/engines/nancy/action/telephone.h
@@ -32,12 +32,10 @@ namespace Action {
 class Telephone : public ActionRecord, public RenderObject {
 public:
 	struct PhoneCall {
-		Common::Array<byte> phoneNumber; // 0x0, 11 bytes
-		Common::String soundName; // 0xB
-		Common::String text; // 0x15, 0xC8 bytes
-		SceneChangeDescription sceneChange; // 0xDD
-		// shouldStopRendering
-		FlagDescription flag; // 0xE7
+		Common::Array<byte> phoneNumber;
+		Common::String soundName;
+		Common::String text;
+		SceneChangeWithFlag sceneChange;
 	};
 
 	enum CallState { kWaiting, kButtonPress, kRinging, kBadNumber, kCall, kHangUp };
@@ -54,25 +52,22 @@ public:
 	void execute() override;
 	void handleInput(NancyInput &input) override;
 
-	Common::String _imageName; // 0x00
-	Common::Array<Common::Rect> _srcRects; // 0xA, 12
-	Common::Array<Common::Rect> _destRects; // 0xCA, 12
-	SoundDescription _genericDialogueSound; // 0x18A
-	SoundDescription _genericButtonSound; // 0x1AC
-	SoundDescription _ringSound; // 0x1CE
-	SoundDescription _dialToneSound; // 0x1F0
-	SoundDescription _dialAgainSound; // 0x212
-	SoundDescription _hangUpSound; // 0x234
-	Common::Array<Common::String> _buttonSoundNames; // 0x256, 12 * 0xA
-	Common::String _addressBookString; // 0x2CE, 0xC8 long
-	Common::String _dialAgainString; // 0x396
-	SceneChangeDescription _reloadScene; // 0x45E
-	FlagDescription _flagOnReload; // 0x468 ??
-	SceneChangeDescription _exitScene; // 0x46C
-	FlagDescription _flagOnExit; // 0x476
-	Common::Rect _exitHotspot; // 0x47A
-	// 0x48A numConvos
-	Common::Array<PhoneCall> _calls; // 0x48C
+	Common::String _imageName;
+	Common::Array<Common::Rect> _srcRects;
+	Common::Array<Common::Rect> _destRects;
+	SoundDescription _genericDialogueSound;
+	SoundDescription _genericButtonSound;
+	SoundDescription _ringSound;
+	SoundDescription _dialToneSound;
+	SoundDescription _dialAgainSound;
+	SoundDescription _hangUpSound;
+	Common::Array<Common::String> _buttonSoundNames;
+	Common::String _addressBookString;
+	Common::String _dialAgainString;
+	SceneChangeWithFlag _reloadScene;
+	SceneChangeWithFlag _exitScene;
+	Common::Rect _exitHotspot;
+	Common::Array<PhoneCall> _calls;
 
 	Common::Array<byte> _calledNumber;
 	Graphics::ManagedSurface _image;
diff --git a/engines/nancy/action/towerpuzzle.cpp b/engines/nancy/action/towerpuzzle.cpp
index 06f169b4b69..2f8710dd9c8 100644
--- a/engines/nancy/action/towerpuzzle.cpp
+++ b/engines/nancy/action/towerpuzzle.cpp
@@ -83,16 +83,13 @@ void TowerPuzzle::readData(Common::SeekableReadStream &stream) {
 	_takeSound.read(stream, SoundDescription::kNormal);
 	_dropSound.read(stream, SoundDescription::kNormal);
 
-	_solveExitScene.readData(stream);
+	_solveExitScene._sceneChange.readData(stream);
 	stream.skip(2);
 	_solveSound.read(stream, SoundDescription::kNormal);
-	_flagOnSolve.label = stream.readSint16LE();
-	_flagOnSolve.flag = stream.readByte();
+	_solveExitScene._flag.label = stream.readSint16LE();
+	_solveExitScene._flag.flag = stream.readByte();
 
 	_exitScene.readData(stream);
-	stream.skip(2);
-	_flagOnExit.label = stream.readSint16LE();
-	_flagOnExit.flag = stream.readByte();
 	readRect(stream, _exitHotspot);
 }
 
@@ -152,12 +149,10 @@ void TowerPuzzle::execute() {
 	case kActionTrigger :
 		switch (_solveState) {
 		case kNotSolved:
-			NancySceneState.changeScene(_exitScene);
-			NancySceneState.setEventFlag(_flagOnExit);
+			_exitScene.execute();
 			break;
 		case kWaitForSound:
-			NancySceneState.changeScene(_solveExitScene);
-			NancySceneState.setEventFlag(_flagOnSolve);
+			_solveExitScene.execute();
 			_puzzleState->playerHasTriedPuzzle = false;
 			break;
 		}
diff --git a/engines/nancy/action/towerpuzzle.h b/engines/nancy/action/towerpuzzle.h
index 653d0c4a661..3e97d438463 100644
--- a/engines/nancy/action/towerpuzzle.h
+++ b/engines/nancy/action/towerpuzzle.h
@@ -48,23 +48,20 @@ protected:
 
 	Common::String _imageName;
 	Common::Array<uint16> _numRingsByDifficulty;
-	// 2 unknown
-	Common::Array<Common::Rect> _droppedRingSrcs; // 6
-	Common::Array<Common::Rect> _heldRingSrcs; // 6
 
-	Common::Array<Common::Rect> _hotspots; // 3
+	Common::Array<Common::Rect> _droppedRingSrcs;
+	Common::Array<Common::Rect> _heldRingSrcs;
 
+	Common::Array<Common::Rect> _hotspots;
 	Common::Array<Common::Array<Common::Array<Common::Rect>>> _destRects; // [ringID][poleID][position]
 
 	SoundDescription _takeSound;
 	SoundDescription _dropSound;
 
-	SceneChangeDescription _solveExitScene;
+	SceneChangeWithFlag _solveExitScene;
 	SoundDescription _solveSound;
-	FlagDescription _flagOnSolve;
 
-	SceneChangeDescription _exitScene;
-	FlagDescription _flagOnExit;
+	SceneChangeWithFlag _exitScene;
 	Common::Rect _exitHotspot;
 
 	Graphics::ManagedSurface _image;
diff --git a/engines/nancy/commontypes.cpp b/engines/nancy/commontypes.cpp
index f982e5720e5..d223d9383b2 100644
--- a/engines/nancy/commontypes.cpp
+++ b/engines/nancy/commontypes.cpp
@@ -38,8 +38,8 @@ void SceneChangeDescription::readData(Common::SeekableReadStream &stream, bool l
 	continueSceneSound = stream.readUint16LE();
 }
 
-void SceneChangeWithFlag::readData(Common::SeekableReadStream &stream) {
-	_sceneChange.readData(stream);
+void SceneChangeWithFlag::readData(Common::SeekableReadStream &stream, bool longFormat) {
+	_sceneChange.readData(stream, longFormat);
 	stream.skip(2); // shouldStopRendering
 	_flag.label = stream.readSint16LE();
 	_flag.flag = stream.readByte();
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index c1b7fb2128d..43f1e65ec09 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -132,7 +132,7 @@ struct SceneChangeWithFlag {
 	SceneChangeDescription _sceneChange;
 	FlagDescription _flag;
 
-	void readData(Common::SeekableReadStream &stream);
+	void readData(Common::SeekableReadStream &stream, bool longFormat = false);
 	void execute();
 };
 


Commit: 70a916d817686260d12ec1f2afda160bb01e0c42
    https://github.com/scummvm/scummvm/commit/70a916d817686260d12ec1f2afda160bb01e0c42
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-19T15:02:32+03:00

Commit Message:
NANCY: Make sure visual ARs stay visible after pause

Added a RenderActionRecord class that automatically
handles re-adding ActionRecords with visuals to the
rendering system, and subclassed relevant ARs from it.

Changed paths:
    engines/nancy/action/actionrecord.h
    engines/nancy/action/conversation.cpp
    engines/nancy/action/conversation.h
    engines/nancy/action/leverpuzzle.cpp
    engines/nancy/action/leverpuzzle.h
    engines/nancy/action/orderingpuzzle.cpp
    engines/nancy/action/orderingpuzzle.h
    engines/nancy/action/overlay.cpp
    engines/nancy/action/overlay.h
    engines/nancy/action/passwordpuzzle.cpp
    engines/nancy/action/passwordpuzzle.h
    engines/nancy/action/recordtypes.cpp
    engines/nancy/action/recordtypes.h
    engines/nancy/action/riddlepuzzle.h
    engines/nancy/action/rippedletterpuzzle.h
    engines/nancy/action/rotatinglockpuzzle.cpp
    engines/nancy/action/rotatinglockpuzzle.h
    engines/nancy/action/secondarymovie.cpp
    engines/nancy/action/secondarymovie.h
    engines/nancy/action/secondaryvideo.cpp
    engines/nancy/action/secondaryvideo.h
    engines/nancy/action/sliderpuzzle.cpp
    engines/nancy/action/sliderpuzzle.h
    engines/nancy/action/telephone.h
    engines/nancy/action/towerpuzzle.h


diff --git a/engines/nancy/action/actionrecord.h b/engines/nancy/action/actionrecord.h
index 327eff5153a..2029a777a20 100644
--- a/engines/nancy/action/actionrecord.h
+++ b/engines/nancy/action/actionrecord.h
@@ -25,6 +25,7 @@
 #include "engines/nancy/time.h"
 #include "engines/nancy/cursor.h"
 #include "engines/nancy/commontypes.h"
+#include "engines/nancy/renderobject.h"
 
 namespace Common {
 class SeekableReadStream;
@@ -81,7 +82,7 @@ struct DependencyRecord {
 // Supports conditional execution (via dependencies) and can have
 // clickable hotspots on screen.
 // Does _not_ support drawing to screen, records that need this functionality
-// will have to also subclass RenderObject.
+// will have to subclass RenderActionRecord.
 class ActionRecord {
 	friend class ActionManager;
 	friend class Nancy::NancyConsole;
@@ -132,6 +133,17 @@ public:
 	int8 _itemRequired;								// 0x97
 };
 
+// Base class for visual ActionRecords
+class RenderActionRecord : public ActionRecord, public RenderObject {
+public:
+	RenderActionRecord(uint zOrder) : RenderObject(zOrder) {}
+	virtual ~RenderActionRecord() {}
+
+	// This makes sure the AR is re-added to the render system
+	// when returning from a different state (e.g. the Help screen)
+	void onPause(bool pause) override { if (!pause) registerGraphics(); }
+};
+
 } // End of namespace Action
 } // End of namespace Nancy
 
diff --git a/engines/nancy/action/conversation.cpp b/engines/nancy/action/conversation.cpp
index 5f6fbc5ab69..ce5305f92b3 100644
--- a/engines/nancy/action/conversation.cpp
+++ b/engines/nancy/action/conversation.cpp
@@ -496,6 +496,7 @@ void ConversationVideo::updateGraphics() {
 
 void ConversationVideo::onPause(bool pause) {
 	_decoder.pauseVideo(pause);
+	RenderActionRecord::onPause(pause);
 }
 
 bool ConversationVideo::isVideoDonePlaying() {
diff --git a/engines/nancy/action/conversation.h b/engines/nancy/action/conversation.h
index 3a99bd6ccc6..52d406d53a1 100644
--- a/engines/nancy/action/conversation.h
+++ b/engines/nancy/action/conversation.h
@@ -23,16 +23,15 @@
 #define NANCY_ACTION_CONVERSATION_H
 
 #include "engines/nancy/action/actionrecord.h"
-#include "engines/nancy/renderobject.h"
 #include "engines/nancy/video.h"
 
 namespace Nancy {
 namespace Action {
 
 // The base class for conversations, with no video data
-class ConversationSound : public ActionRecord, public RenderObject {
+class ConversationSound : public RenderActionRecord {
 public:
-	ConversationSound() : RenderObject(8) {}
+	ConversationSound() : RenderActionRecord(8) {}
 	virtual ~ConversationSound();
 
 	void init() override;
diff --git a/engines/nancy/action/leverpuzzle.cpp b/engines/nancy/action/leverpuzzle.cpp
index 7324420fba3..6641c228a6c 100644
--- a/engines/nancy/action/leverpuzzle.cpp
+++ b/engines/nancy/action/leverpuzzle.cpp
@@ -218,12 +218,6 @@ void LeverPuzzle::handleInput(NancyInput &input) {
 	}
 }
 
-void LeverPuzzle::onPause(bool pause) {
-	if (!pause) {
-		registerGraphics();
-	}
-}
-
 void LeverPuzzle::drawLever(uint id) {
 	Common::Point destPoint(_destRects[id].left - _screenPosition.left, _destRects[id].top - _screenPosition.top);
 	_drawSurface.blitFrom(_image, _srcRects[id][_playerSequence[id]], destPoint);
diff --git a/engines/nancy/action/leverpuzzle.h b/engines/nancy/action/leverpuzzle.h
index da9fad9ceb2..5fd4c20f510 100644
--- a/engines/nancy/action/leverpuzzle.h
+++ b/engines/nancy/action/leverpuzzle.h
@@ -22,17 +22,15 @@
 #ifndef NANCY_ACTION_LEVERPUZZLE_H
 #define NANCY_ACTION_LEVERPUZZLE_H
 
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class LeverPuzzle : public ActionRecord, public RenderObject {
+class LeverPuzzle : public RenderActionRecord {
 public:
 	enum SolveState { kNotSolved, kPlaySound, kWaitForSound };
-	LeverPuzzle() : RenderObject(7) {}
+	LeverPuzzle() : RenderActionRecord(7) {}
 	virtual ~LeverPuzzle() {}
 
 	void init() override;
@@ -40,7 +38,6 @@ public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
 	void handleInput(NancyInput &input) override;
-	void onPause(bool pause) override;
 
 	Common::String _imageName;
 	Common::Array<Common::Array<Common::Rect>> _srcRects;
diff --git a/engines/nancy/action/orderingpuzzle.cpp b/engines/nancy/action/orderingpuzzle.cpp
index 4e52d4f5021..4639106c12a 100644
--- a/engines/nancy/action/orderingpuzzle.cpp
+++ b/engines/nancy/action/orderingpuzzle.cpp
@@ -223,12 +223,6 @@ void OrderingPuzzle::handleInput(NancyInput &input) {
 	}
 }
 
-void OrderingPuzzle::onPause(bool pause) {
-	if (!pause) {
-		registerGraphics();
-	}
-}
-
 void OrderingPuzzle::drawElement(uint id) {
 	_drawnElements[id] = true;
 	Common::Point destPoint(_destRects[id].left - _screenPosition.left, _destRects[id].top - _screenPosition.top);
diff --git a/engines/nancy/action/orderingpuzzle.h b/engines/nancy/action/orderingpuzzle.h
index cdebe918f68..9c9a6034c02 100644
--- a/engines/nancy/action/orderingpuzzle.h
+++ b/engines/nancy/action/orderingpuzzle.h
@@ -22,17 +22,15 @@
 #ifndef NANCY_ACTION_ORDERINGPUZZLE_H
 #define NANCY_ACTION_ORDERINGPUZZLE_H
 
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class OrderingPuzzle : public ActionRecord, public RenderObject {
+class OrderingPuzzle : public RenderActionRecord {
 public:
 	enum SolveState { kNotSolved, kPlaySound, kWaitForSound };
-	OrderingPuzzle() : RenderObject(7) {}
+	OrderingPuzzle() : RenderActionRecord(7) {}
 	virtual ~OrderingPuzzle() {}
 
 	void init() override;
@@ -40,7 +38,6 @@ public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
 	void handleInput(NancyInput &input) override;
-	void onPause(bool pause) override;
 
 	Common::String _imageName;
 	Common::Array<Common::Rect> _srcRects;
diff --git a/engines/nancy/action/overlay.cpp b/engines/nancy/action/overlay.cpp
index 64397d52a68..b5e6ec45dcc 100644
--- a/engines/nancy/action/overlay.cpp
+++ b/engines/nancy/action/overlay.cpp
@@ -206,12 +206,6 @@ void Overlay::execute() {
 	}
 }
 
-void Overlay::onPause(bool pause) {
-	if (!pause) {
-		registerGraphics();
-	}
-}
-
 Common::String Overlay::getRecordTypeName() const {
 	if (g_nancy->getGameType() <= kGameTypeNancy1) {
 		if (_isInterruptible) {
diff --git a/engines/nancy/action/overlay.h b/engines/nancy/action/overlay.h
index 4452b2b1798..2f2af35e2f3 100644
--- a/engines/nancy/action/overlay.h
+++ b/engines/nancy/action/overlay.h
@@ -22,8 +22,6 @@
 #ifndef NANCY_ACTION_OVERLAY_H
 #define NANCY_ACTION_OVERLAY_H
 
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
@@ -36,7 +34,7 @@ namespace Action {
 // - PlayStaticBitmapAnimation: nancy1 only, does not support static mode
 // - PlayIntStaticBitmapAnimation: nancy1 only, same as above but supports being interrupted by an event flag
 // - Overlay: nancy2 and above, supports static mode
-class Overlay : public ActionRecord, public RenderObject {
+class Overlay : public RenderActionRecord {
 public:
 	static const byte kPlayOverlayPlain				= 1;
 	static const byte kPlayOverlayTransparent		= 2;
@@ -56,14 +54,13 @@ public:
 	static const byte kPlayOverlayWithHotspot		= 1;
 	static const byte kPlayOverlayNoHotspot			= 2;
 
-	Overlay(bool interruptible) : RenderObject(7), _isInterruptible(interruptible) {}
+	Overlay(bool interruptible) : RenderActionRecord(7), _isInterruptible(interruptible) {}
 	virtual ~Overlay() { _fullSurface.free(); }
 
 	void init() override;
 
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
-	void onPause(bool pause) override;
 
 	Common::String _imageName;
 
diff --git a/engines/nancy/action/passwordpuzzle.cpp b/engines/nancy/action/passwordpuzzle.cpp
index 7c3f995400e..2a2eb999f50 100644
--- a/engines/nancy/action/passwordpuzzle.cpp
+++ b/engines/nancy/action/passwordpuzzle.cpp
@@ -198,12 +198,6 @@ void PasswordPuzzle::handleInput(NancyInput &input) {
 	}
 }
 
-void PasswordPuzzle::onPause(bool pause) {
-	if (!pause) {
-		registerGraphics();
-	}
-}
-
 void PasswordPuzzle::drawText() {
 	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
 	const Graphics::Font *font = g_nancy->_graphicsManager->getFont(_fontID);
diff --git a/engines/nancy/action/passwordpuzzle.h b/engines/nancy/action/passwordpuzzle.h
index 17a38c243c9..8f785070551 100644
--- a/engines/nancy/action/passwordpuzzle.h
+++ b/engines/nancy/action/passwordpuzzle.h
@@ -22,17 +22,15 @@
 #ifndef NANCY_ACTION_PASSWORDPUZZLE_H
 #define NANCY_ACTION_PASSWORDPUZZLE_H
 
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class PasswordPuzzle : public ActionRecord, public RenderObject {
+class PasswordPuzzle : public RenderActionRecord {
 public:
 	enum SolveState { kNotSolved, kFailed, kSolved };
-	PasswordPuzzle() : RenderObject(7) {}
+	PasswordPuzzle() : RenderActionRecord(7) {}
 	virtual ~PasswordPuzzle() {}
 
 	void init() override;
@@ -40,7 +38,6 @@ public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
 	void handleInput(NancyInput &input) override;
-	void onPause(bool pause) override;
 
 	uint16 _fontID = 0;
 	Time _cursorBlinkTime;
diff --git a/engines/nancy/action/recordtypes.cpp b/engines/nancy/action/recordtypes.cpp
index e62854877e9..eddb7627c39 100644
--- a/engines/nancy/action/recordtypes.cpp
+++ b/engines/nancy/action/recordtypes.cpp
@@ -546,12 +546,6 @@ void ShowInventoryItem::execute() {
 	}
 }
 
-void ShowInventoryItem::onPause(bool pause) {
-	if (!pause) {
-		registerGraphics();
-	}
-}
-
 void PlayDigiSoundAndDie::readData(Common::SeekableReadStream &stream) {
 	_sound.read(stream, SoundDescription::kDIGI);
 	_sceneChange.readData(stream, g_nancy->getGameType() == kGameTypeVampire);
diff --git a/engines/nancy/action/recordtypes.h b/engines/nancy/action/recordtypes.h
index 9a217a848fe..db659fc37e8 100644
--- a/engines/nancy/action/recordtypes.h
+++ b/engines/nancy/action/recordtypes.h
@@ -22,8 +22,6 @@
 #ifndef NANCY_ACTION_RECORDTYPES_H
 #define NANCY_ACTION_RECORDTYPES_H
 
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
@@ -340,16 +338,15 @@ protected:
 	Common::String getRecordTypeName() const override { return "DifficultyLevel"; }
 };
 
-class ShowInventoryItem : public ActionRecord, public RenderObject {
+class ShowInventoryItem : public RenderActionRecord {
 public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
 
-	ShowInventoryItem() : RenderObject(9) {}
+	ShowInventoryItem() : RenderActionRecord(9) {}
 	virtual ~ShowInventoryItem() { _fullSurface.free(); }
 
 	void init() override;
-	void onPause(bool pause) override;
 
 	uint16 _objectID = 0;
 	Common::String _imageName;
diff --git a/engines/nancy/action/riddlepuzzle.h b/engines/nancy/action/riddlepuzzle.h
index 170da3b15f2..88b92a5c1f5 100644
--- a/engines/nancy/action/riddlepuzzle.h
+++ b/engines/nancy/action/riddlepuzzle.h
@@ -22,16 +22,15 @@
 #ifndef NANCY_ACTION_RIDDLEPUZZLE_H
 #define NANCY_ACTION_RIDDLEPUZZLE_H
 
-#include "engines/nancy/renderobject.h"
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class RiddlePuzzle : public ActionRecord, public RenderObject {
+class RiddlePuzzle : public RenderActionRecord {
 public:
 	enum SolveState { kWaitForSound, kNotSolved, kFailed, kSolvedOne, kSolvedAll };
-	RiddlePuzzle() : RenderObject(7) {}
+	RiddlePuzzle() : RenderActionRecord(7) {}
 	virtual ~RiddlePuzzle() {}
 
 	void init() override;
diff --git a/engines/nancy/action/rippedletterpuzzle.h b/engines/nancy/action/rippedletterpuzzle.h
index 1293710c1b5..3b6152019c6 100644
--- a/engines/nancy/action/rippedletterpuzzle.h
+++ b/engines/nancy/action/rippedletterpuzzle.h
@@ -22,16 +22,15 @@
 #ifndef NANCY_ACTION_RIPPEDLETTERPUZZLE_H
 #define NANCY_ACTION_RIPPEDLETTERPUZZLE_H
 
-#include "engines/nancy/renderobject.h"
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class RippedLetterPuzzle : public ActionRecord, public RenderObject {
+class RippedLetterPuzzle : public RenderActionRecord {
 public:
 	enum SolveState { kNotSolved, kWaitForSound };
-	RippedLetterPuzzle() : RenderObject(7), _pickedUpPiece(8) {}
+	RippedLetterPuzzle() : RenderActionRecord(7), _pickedUpPiece(8) {}
 	virtual ~RippedLetterPuzzle() {}
 
 	void init() override;
diff --git a/engines/nancy/action/rotatinglockpuzzle.cpp b/engines/nancy/action/rotatinglockpuzzle.cpp
index 8a1dbf28881..cdef29a69d3 100644
--- a/engines/nancy/action/rotatinglockpuzzle.cpp
+++ b/engines/nancy/action/rotatinglockpuzzle.cpp
@@ -206,13 +206,6 @@ void RotatingLockPuzzle::handleInput(NancyInput &input) {
 		}
 	}
 }
-
-void RotatingLockPuzzle::onPause(bool pause) {
-	if (!pause) {
-		registerGraphics();
-	}
-}
-
 void RotatingLockPuzzle::drawDial(uint id) {
 	Common::Point destPoint(_destRects[id].left - _screenPosition.left, _destRects[id].top - _screenPosition.top);
 	_drawSurface.blitFrom(_image, _srcRects[_currentSequence[id]], destPoint);
diff --git a/engines/nancy/action/rotatinglockpuzzle.h b/engines/nancy/action/rotatinglockpuzzle.h
index cf0b5a1e231..f5210d23c5e 100644
--- a/engines/nancy/action/rotatinglockpuzzle.h
+++ b/engines/nancy/action/rotatinglockpuzzle.h
@@ -22,17 +22,15 @@
 #ifndef NANCY_ACTION_ROTATINGLOCKPUZZLE_H
 #define NANCY_ACTION_ROTATINGLOCKPUZZLE_H
 
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class RotatingLockPuzzle : public ActionRecord, public RenderObject {
+class RotatingLockPuzzle : public RenderActionRecord {
 public:
 	enum SolveState { kNotSolved, kPlaySound, kWaitForSound };
-	RotatingLockPuzzle() : RenderObject(7) {}
+	RotatingLockPuzzle() : RenderActionRecord(7) {}
 	virtual ~RotatingLockPuzzle() {}
 
 	void init() override;
@@ -40,7 +38,6 @@ public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
 	void handleInput(NancyInput &input) override;
-	void onPause(bool pause) override;
 
 	Common::String _imageName;
 	Common::Array<Common::Rect> _srcRects;
diff --git a/engines/nancy/action/secondarymovie.cpp b/engines/nancy/action/secondarymovie.cpp
index c459d6d88cb..493dc735a88 100644
--- a/engines/nancy/action/secondarymovie.cpp
+++ b/engines/nancy/action/secondarymovie.cpp
@@ -173,6 +173,7 @@ void PlaySecondaryMovie::updateGraphics() {
 
 void PlaySecondaryMovie::onPause(bool pause) {
 	_decoder.pauseVideo(pause);
+	RenderActionRecord::onPause(pause);
 }
 
 void PlaySecondaryMovie::execute() {
diff --git a/engines/nancy/action/secondarymovie.h b/engines/nancy/action/secondarymovie.h
index 01756e4c742..e3011d6ee01 100644
--- a/engines/nancy/action/secondarymovie.h
+++ b/engines/nancy/action/secondarymovie.h
@@ -23,14 +23,12 @@
 #define NANCY_ACTION_SECONDARYMOVIE_H
 
 #include "engines/nancy/video.h"
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class PlaySecondaryMovie : public ActionRecord, public RenderObject {
+class PlaySecondaryMovie : public RenderActionRecord {
 public:
 	static const byte kMovieSceneChange			= 5;
 	static const byte kMovieNoSceneChange		= 6;
@@ -46,7 +44,7 @@ public:
 		FlagDescription flagDesc;
 	};
 
-	PlaySecondaryMovie() : RenderObject(8) {}
+	PlaySecondaryMovie() : RenderActionRecord(8) {}
 	virtual ~PlaySecondaryMovie();
 
 	void init() override;
diff --git a/engines/nancy/action/secondaryvideo.cpp b/engines/nancy/action/secondaryvideo.cpp
index 615bf2393f9..953bc3ceadc 100644
--- a/engines/nancy/action/secondaryvideo.cpp
+++ b/engines/nancy/action/secondaryvideo.cpp
@@ -143,6 +143,7 @@ void PlaySecondaryVideo::updateGraphics() {
 
 void PlaySecondaryVideo::onPause(bool pause) {
 	_decoder.pauseVideo(pause);
+	RenderActionRecord::onPause(pause);
 }
 
 void PlaySecondaryVideo::handleInput(NancyInput &input) {
diff --git a/engines/nancy/action/secondaryvideo.h b/engines/nancy/action/secondaryvideo.h
index 927e650cfc1..adfa6fb628e 100644
--- a/engines/nancy/action/secondaryvideo.h
+++ b/engines/nancy/action/secondaryvideo.h
@@ -23,8 +23,6 @@
 #define NANCY_ACTION_SECONDARYVIDEO_H
 
 #include "engines/nancy/video.h"
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
@@ -32,14 +30,14 @@ namespace Action {
 
 // ActionRecord that shows NPC animations outside of dialogue. Supports
 // different animations depending on whether the NPC is hovered by the mouse
-class PlaySecondaryVideo : public ActionRecord, public RenderObject {
+class PlaySecondaryVideo : public RenderActionRecord {
 public:
 	static const byte kNoVideoHotspots	= 1;
 	static const byte kVideoHotspots	= 2;
 
 	enum HoverState { kNoHover, kHover, kEndHover };
 
-	PlaySecondaryVideo(uint chan) : RenderObject(8), channel(chan) {}
+	PlaySecondaryVideo(uint chan) : RenderActionRecord(8), channel(chan) {}
 	virtual ~PlaySecondaryVideo() { _decoder.close(); }
 
 	void init() override;
diff --git a/engines/nancy/action/sliderpuzzle.cpp b/engines/nancy/action/sliderpuzzle.cpp
index 69b437b7aba..793b9d26af2 100644
--- a/engines/nancy/action/sliderpuzzle.cpp
+++ b/engines/nancy/action/sliderpuzzle.cpp
@@ -282,12 +282,6 @@ void SliderPuzzle::handleInput(NancyInput &input) {
 	}
 }
 
-void SliderPuzzle::onPause(bool pause) {
-	if (!pause) {
-		registerGraphics();
-	}
-}
-
 void SliderPuzzle::drawTile(int tileID, uint posX, uint posY) {
 	if (tileID < 0) {
 		undrawTile(posX, posY);
diff --git a/engines/nancy/action/sliderpuzzle.h b/engines/nancy/action/sliderpuzzle.h
index 8ae4b35aec8..58115413c9f 100644
--- a/engines/nancy/action/sliderpuzzle.h
+++ b/engines/nancy/action/sliderpuzzle.h
@@ -22,8 +22,6 @@
 #ifndef NANCY_ACTION_SLIDERPUZZLE_H
 #define NANCY_ACTION_SLIDERPUZZLE_H
 
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Common {
@@ -33,12 +31,13 @@ class Serializer;
 namespace Nancy {
 
 struct SPUZ;
+
 namespace Action {
 
-class SliderPuzzle: public ActionRecord, public RenderObject {
+class SliderPuzzle: public RenderActionRecord {
 public:
 	enum SolveState { kNotSolved, kWaitForSound };
-	SliderPuzzle() : RenderObject(7) {}
+	SliderPuzzle() : RenderActionRecord(7) {}
 	virtual ~SliderPuzzle() {}
 
 	void init() override;
@@ -46,7 +45,6 @@ public:
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;
 	void handleInput(NancyInput &input) override;
-	void onPause(bool pause) override;
 
 	SPUZ *_spuzData = nullptr;
 	SliderPuzzleState *_puzzleState = nullptr;
diff --git a/engines/nancy/action/telephone.h b/engines/nancy/action/telephone.h
index 8273ae674a8..74bff2bec2a 100644
--- a/engines/nancy/action/telephone.h
+++ b/engines/nancy/action/telephone.h
@@ -22,14 +22,12 @@
 #ifndef NANCY_ACTION_TELEPHONE_H
 #define NANCY_ACTION_TELEPHONE_H
 
-#include "engines/nancy/renderobject.h"
-
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class Telephone : public ActionRecord, public RenderObject {
+class Telephone : public RenderActionRecord {
 public:
 	struct PhoneCall {
 		Common::Array<byte> phoneNumber;
@@ -41,7 +39,7 @@ public:
 	enum CallState { kWaiting, kButtonPress, kRinging, kBadNumber, kCall, kHangUp };
 
 	Telephone() :
-		RenderObject(7),
+		RenderActionRecord(7),
 		_callState(kWaiting),
 		_selected(0) {}
 	virtual ~Telephone() {}
diff --git a/engines/nancy/action/towerpuzzle.h b/engines/nancy/action/towerpuzzle.h
index 3e97d438463..b698b4f00c8 100644
--- a/engines/nancy/action/towerpuzzle.h
+++ b/engines/nancy/action/towerpuzzle.h
@@ -22,16 +22,15 @@
 #ifndef NANCY_ACTION_TOWERIPPEDLETTERPUZZLE_H
 #define NANCY_ACTION_TOWERIPPEDLETTERPUZZLE_H
 
-#include "engines/nancy/renderobject.h"
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
 namespace Action {
 
-class TowerPuzzle : public ActionRecord, public RenderObject {
+class TowerPuzzle : public RenderActionRecord {
 public:
 	enum SolveState { kNotSolved, kWaitForSound };
-	TowerPuzzle() : RenderObject(7), _heldRing(8) {}
+	TowerPuzzle() : RenderActionRecord(7), _heldRing(8) {}
 	virtual ~TowerPuzzle() {}
 
 	void init() override;


Commit: fe58d58e27d3fc22ed27ccd26bdd871b51b0bb93
    https://github.com/scummvm/scummvm/commit/fe58d58e27d3fc22ed27ccd26bdd871b51b0bb93
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-19T15:02:32+03:00

Commit Message:
NANCY: Implement OverrideLockPuzzle

Implemented the OverrideLockPuzzle, which appears at the
very end of nancy2 and has the player remember a
sequence of button presses.

Changed paths:
  A engines/nancy/action/overridelockpuzzle.cpp
  A engines/nancy/action/overridelockpuzzle.h
    engines/nancy/action/arfactory.cpp
    engines/nancy/module.mk


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index b83bd2fbb0f..da76380e44d 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -33,6 +33,7 @@
 #include "engines/nancy/action/rippedletterpuzzle.h"
 #include "engines/nancy/action/towerpuzzle.h"
 #include "engines/nancy/action/riddlepuzzle.h"
+#include "engines/nancy/action/overridelockpuzzle.h"
 
 #include "engines/nancy/state/scene.h"
 
@@ -150,6 +151,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type) {
 		return new TowerPuzzle();
 	case 203:
 		return new RippedLetterPuzzle();
+	case 204:
+		return new OverrideLockPuzzle();
 	case 205:
 		return new RiddlePuzzle();
 	default:
diff --git a/engines/nancy/action/overridelockpuzzle.cpp b/engines/nancy/action/overridelockpuzzle.cpp
new file mode 100644
index 00000000000..8094121229d
--- /dev/null
+++ b/engines/nancy/action/overridelockpuzzle.cpp
@@ -0,0 +1,236 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "engines/nancy/nancy.h"
+#include "engines/nancy/graphics.h"
+#include "engines/nancy/resource.h"
+#include "engines/nancy/sound.h"
+#include "engines/nancy/input.h"
+#include "engines/nancy/util.h"
+#include "engines/nancy/state/scene.h"
+#include "engines/nancy/ui/viewport.h"
+
+#include "engines/nancy/action/overridelockpuzzle.h"
+
+#include "common/random.h"
+
+namespace Nancy {
+namespace Action {
+
+void OverrideLockPuzzle::init() {
+	Common::Rect bounds = NancySceneState.getViewport().getBounds();
+
+	_drawSurface.create(bounds.width(), bounds.height(), g_nancy->_graphicsManager->getInputPixelFormat());
+	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
+
+	setTransparent(true);
+	setVisible(true);
+	moveTo(bounds);
+
+	g_nancy->_resource->loadImage(_imageName, _image);
+	_image.setTransparentColor(_drawSurface.getTransparentColor());
+}
+
+void OverrideLockPuzzle::readData(Common::SeekableReadStream &stream) {
+	readFilename(stream, _imageName);
+
+	byte num = stream.readByte();
+	_popButtons = stream.readByte();
+	_randomizeLights = stream.readByte();
+
+	readRectArray(stream, _buttonSrcs, num);
+	stream.skip((10 - num) * 16);
+	readRectArray(stream, _buttonDests, num);
+	stream.skip((10 - num) * 16);
+	readRectArray(stream, _hotspots, num);
+	stream.skip((10 - num) * 16);
+	readRectArray(stream, _lightSrcs, num);
+	stream.skip((10 - num) * 16);
+	readRectArray(stream, _lightDests, num);
+	stream.skip((10 - num) * 16);
+
+	_buttonSound.read(stream, SoundDescription::kNormal);
+	_wrongSound.read(stream, SoundDescription::kNormal);
+
+	_buttonPopTime = stream.readUint16LE();
+
+	_solveExitScene.readData(stream);
+	_solveSound.read(stream, SoundDescription::kNormal);
+
+	_exitScene.readData(stream);
+	readRect(stream, _exitHotspot);
+}
+
+void OverrideLockPuzzle::execute() {
+	switch (_state) {
+	case kBegin: {
+		init();
+		registerGraphics();
+		
+		// Set the order of the button presses (always random)
+		// and of the lights (only random on expert difficulty)
+		uint numButtons = _buttonSrcs.size();
+		_buttonOrder.resize(numButtons);
+		_lightsOrder.resize(numButtons);
+		Common::Array<byte> buttonIDs(numButtons);
+		Common::Array<byte> lightIDs(numButtons);
+		for (uint i = 0; i < numButtons; ++i) {
+			buttonIDs[i] = i;
+			lightIDs[i] = i;
+		}
+
+		for (uint i = 0; i < numButtons; ++i) {
+			_buttonOrder[i] = buttonIDs.remove_at(g_nancy->_randomSource->getRandomNumber(buttonIDs.size() - 1));
+
+			if (_randomizeLights == kLightsRandom) {
+				_lightsOrder[i] = lightIDs.remove_at(g_nancy->_randomSource->getRandomNumber(lightIDs.size() - 1));
+			} else {
+				_lightsOrder[i] = i;
+			}
+		}
+
+		g_nancy->_sound->loadSound(_buttonSound);
+		g_nancy->_sound->loadSound(_wrongSound);
+		_state = kRun;
+	}
+		// fall through
+	case kRun:
+		if (_timeToPop != 0 && g_nancy->getTotalPlayTime() > _timeToPop) {
+			if (_popButtons == kButtonsPopUp) {
+				drawButton(_lastPushedButton, true);
+			}
+			
+			drawLights();
+
+			_lastPushedButton = -1;
+			_timeToPop = 0;
+			
+			for (uint i = 0; i < _playerOrder.size(); ++i) {
+				if (_playerOrder[i] != _buttonOrder[i]) {
+					// Wrong order, reset
+					_drawSurface.clear(_drawSurface.getTransparentColor());
+					_playerOrder.clear();
+					_needsRedraw = true;
+					g_nancy->_sound->playSound(_wrongSound);
+					return;
+				}
+			}
+
+			if (_playerOrder.size() == _buttonOrder.size()) {
+				// Solved the puzzle
+				g_nancy->_sound->loadSound(_solveSound);
+				g_nancy->_sound->playSound(_solveSound);
+				_state = kActionTrigger;
+				_solveState = kSolved;
+			}
+		}
+
+		break;
+	case kActionTrigger:
+		switch (_solveState) {
+		case kNotSolved:
+			_exitScene.execute();
+			break;
+		case kSolved:
+			if (g_nancy->_sound->isSoundPlaying(_solveSound)) {
+				return;
+			}
+
+			_solveExitScene.execute();
+			g_nancy->_sound->stopSound(_solveSound);
+		}
+
+		g_nancy->_sound->stopSound(_buttonSound);
+		g_nancy->_sound->stopSound(_wrongSound);
+		finishExecution();
+	}
+}
+
+void OverrideLockPuzzle::handleInput(NancyInput &input) {
+	if ((_state != kRun && _solveState != kNotSolved) || _timeToPop != 0) {
+		return;
+	}
+
+	// Check the exit hotspot
+	if (NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
+		g_nancy->_cursorManager->setCursorType(CursorManager::kExit);
+
+		if (input.input & NancyInput::kLeftMouseButtonUp) {
+			_state = kActionTrigger;
+		}
+
+		return;
+	}
+
+	for (uint i = 0; i < _buttonOrder.size(); ++i) {
+		bool hotspotIsInactive = false;
+		for (uint j = 0; j < _playerOrder.size(); ++j) {
+			if (_playerOrder[j] == i) {
+				hotspotIsInactive = true;
+				break;
+			}
+		}
+
+		if (hotspotIsInactive) {
+			continue;
+		}
+
+		if (NancySceneState.getViewport().convertViewportToScreen(_hotspots[i]).contains(input.mousePos)) {
+			g_nancy->_cursorManager->setCursorType(CursorManager::kHotspot);
+			
+			if (input.input & NancyInput::kLeftMouseButtonUp) {
+				drawButton(i, false);
+				_lastPushedButton = i;
+				_timeToPop = g_nancy->getTotalPlayTime() + _buttonPopTime;
+				_playerOrder.push_back(i);
+				g_nancy->_sound->playSound(_buttonSound);
+			}
+
+			break;
+		}
+	}
+}
+
+void OverrideLockPuzzle::drawButton(uint buttonID, bool clear) {
+	if (clear) {
+		_drawSurface.fillRect(_buttonDests[buttonID], _drawSurface.getTransparentColor());
+		return;
+	} else {
+		_drawSurface.blitFrom(_image, _buttonSrcs[buttonID], _buttonDests[buttonID]);
+	}
+
+	_needsRedraw = true;
+}
+
+void OverrideLockPuzzle::drawLights() {
+	for (uint i = 0; i < _playerOrder.size(); ++i) {
+		if (_randomizeLights == kLightsCircular) {
+			_drawSurface.blitFrom(_image, _lightSrcs[i], _lightDests[i]);
+		} else {
+			_drawSurface.blitFrom(_image, _lightSrcs[_lightsOrder[i]], _lightDests[_lightsOrder[i]]);
+		}
+	}
+
+	_needsRedraw = true;
+}
+
+} // End of namespace Action
+} // End of namespace Nancy
diff --git a/engines/nancy/action/overridelockpuzzle.h b/engines/nancy/action/overridelockpuzzle.h
new file mode 100644
index 00000000000..c06db0f9674
--- /dev/null
+++ b/engines/nancy/action/overridelockpuzzle.h
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef NANCY_ACTION_OVERRIDELOCKPUZZLE_H
+#define NANCY_ACTION_OVERRIDELOCKPUZZLE_H
+
+#include "engines/nancy/action/actionrecord.h"
+
+namespace Nancy {
+namespace Action {
+
+class OverrideLockPuzzle : public RenderActionRecord {
+public:
+	static const byte kButtonsStayDown 	= 1;
+	static const byte kButtonsPopUp 	= 2;
+
+	static const byte kLightsCircular 	= 3;
+	static const byte kLightsRandom 	= 4;
+
+	OverrideLockPuzzle() : RenderActionRecord(7) {}
+	virtual ~OverrideLockPuzzle() {}
+
+	void init() override;
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+	void handleInput(NancyInput &input) override;
+
+protected:
+	Common::String getRecordTypeName() const override { return "OverrideLockPuzzle"; }
+	bool isViewportRelative() const override { return true; }
+
+	void drawButton(uint buttonID, bool clear);
+	void drawLights();
+
+	enum SolveState { kNotSolved, kSolved };
+
+	Common::String _imageName;
+
+	byte _popButtons = kButtonsStayDown;
+	byte _randomizeLights = kLightsCircular;
+
+	Common::Array<Common::Rect> _buttonSrcs;
+	Common::Array<Common::Rect> _buttonDests;
+	Common::Array<Common::Rect> _hotspots;
+	Common::Array<Common::Rect> _lightSrcs;
+	Common::Array<Common::Rect> _lightDests;
+
+	SoundDescription _buttonSound;
+	SoundDescription _wrongSound;
+
+	Time _buttonPopTime;
+
+	SceneChangeWithFlag _solveExitScene;
+	SoundDescription _solveSound;
+
+	SceneChangeWithFlag _exitScene;
+	Common::Rect _exitHotspot;
+
+	Graphics::ManagedSurface _image;
+
+	Common::Array<byte> _buttonOrder;
+	Common::Array<byte> _lightsOrder;
+	Common::Array<byte> _playerOrder;
+
+	Time _timeToPop;
+	SolveState _solveState = kNotSolved;
+	int8 _lastPushedButton = -1;
+};
+
+} // End of namespace Action
+} // End of namespace Nancy
+
+#endif // NANCY_ACTION_OVERRIDELOCKPUZZLE_H
diff --git a/engines/nancy/module.mk b/engines/nancy/module.mk
index 67b0bebe63b..90f7a8dbad8 100644
--- a/engines/nancy/module.mk
+++ b/engines/nancy/module.mk
@@ -4,10 +4,12 @@ MODULE_OBJS = \
   action/actionmanager.o \
   action/actionrecord.o \
   action/arfactory.o \
+  action/conversation.o \
   action/leverpuzzle.o \
   action/orderingpuzzle.o \
+  action/overlay.o \
+  action/overridelockpuzzle.o \
   action/passwordpuzzle.o \
-  action/conversation.o \
   action/recordtypes.o \
   action/rippedletterpuzzle.o \
   action/rotatinglockpuzzle.o \
@@ -16,7 +18,6 @@ MODULE_OBJS = \
   action/secondaryvideo.o \
   action/sliderpuzzle.o \
   action/towerpuzzle.o \
-  action/overlay.o \
   action/telephone.o \
   ui/fullscreenimage.o \
   ui/animatedbutton.o \


Commit: bc4f0251f8eff4983288f9a7b7d13858d1bff18d
    https://github.com/scummvm/scummvm/commit/bc4f0251f8eff4983288f9a7b7d13858d1bff18d
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-19T15:02:33+03:00

Commit Message:
NANCY: Improve sound data reading

The samplesPerSec property found in some SoundDescriptions
is no longer ignored. This results in the correct playback of
certain sounds (e.g. the button press sounds in nancy2's
OverrideLockPuzzle).

Changed paths:
    engines/nancy/action/conversation.cpp
    engines/nancy/action/leverpuzzle.cpp
    engines/nancy/action/orderingpuzzle.cpp
    engines/nancy/action/overlay.cpp
    engines/nancy/action/overridelockpuzzle.cpp
    engines/nancy/action/passwordpuzzle.cpp
    engines/nancy/action/recordtypes.cpp
    engines/nancy/action/riddlepuzzle.cpp
    engines/nancy/action/rippedletterpuzzle.cpp
    engines/nancy/action/rotatinglockpuzzle.cpp
    engines/nancy/action/secondarymovie.cpp
    engines/nancy/action/sliderpuzzle.cpp
    engines/nancy/action/telephone.cpp
    engines/nancy/action/towerpuzzle.cpp
    engines/nancy/commontypes.cpp
    engines/nancy/commontypes.h
    engines/nancy/enginedata.cpp
    engines/nancy/sound.cpp
    engines/nancy/sound.h
    engines/nancy/state/scene.cpp


diff --git a/engines/nancy/action/conversation.cpp b/engines/nancy/action/conversation.cpp
index ce5305f92b3..9ba1b7376c0 100644
--- a/engines/nancy/action/conversation.cpp
+++ b/engines/nancy/action/conversation.cpp
@@ -58,7 +58,7 @@ void ConversationSound::readData(Common::SeekableReadStream &stream) {
 	ser.setVersion(g_nancy->getGameType());
 
 	if (ser.getVersion() >= kGameTypeNancy2) {
-		_sound.read(stream, SoundDescription::kNormal);
+		_sound.readData(stream, SoundDescription::kNormal);
 	}
 
 	char *rawText = new char[1500];
@@ -67,10 +67,10 @@ void ConversationSound::readData(Common::SeekableReadStream &stream) {
 	delete[] rawText;
 
 	if (ser.getVersion() <= kGameTypeNancy1) {
-		_sound.read(stream, SoundDescription::kNormal);
+		_sound.readData(stream, SoundDescription::kNormal);
 	}
 
-	_responseGenericSound.read(stream, SoundDescription::kNormal);
+	_responseGenericSound.readData(stream, SoundDescription::kNormal);
 	ser.skip(1);
 	ser.syncAsByte(_conditionalResponseCharacterID);
 	ser.syncAsByte(_goodbyeResponseCharacterID);
diff --git a/engines/nancy/action/leverpuzzle.cpp b/engines/nancy/action/leverpuzzle.cpp
index 6641c228a6c..31248c34271 100644
--- a/engines/nancy/action/leverpuzzle.cpp
+++ b/engines/nancy/action/leverpuzzle.cpp
@@ -79,11 +79,11 @@ void LeverPuzzle::readData(Common::SeekableReadStream &stream) {
 		_correctSequence.push_back(stream.readByte());
 	}
 
-	_moveSound.read(stream, SoundDescription::kNormal);
-	_noMoveSound.read(stream, SoundDescription::kNormal);
+	_moveSound.readData(stream, SoundDescription::kNormal);
+	_noMoveSound.readData(stream, SoundDescription::kNormal);
 	_solveExitScene.readData(stream);
 	_solveSoundDelay = stream.readUint16LE();
-	_solveSound.read(stream, SoundDescription::kNormal);
+	_solveSound.readData(stream, SoundDescription::kNormal);
 	_exitScene.readData(stream);
 	readRect(stream, _exitHotspot);
 }
diff --git a/engines/nancy/action/orderingpuzzle.cpp b/engines/nancy/action/orderingpuzzle.cpp
index 4639106c12a..7e0ae7b8f8e 100644
--- a/engines/nancy/action/orderingpuzzle.cpp
+++ b/engines/nancy/action/orderingpuzzle.cpp
@@ -101,12 +101,12 @@ void OrderingPuzzle::readData(Common::SeekableReadStream &stream) {
 	ser.skip(15 - _sequenceLength, kGameTypeNancy1);
 
 	if (ser.getVersion() != kGameTypeVampire) {
-		_clickSound.read(stream, SoundDescription::kNormal);
+		_clickSound.readData(stream, SoundDescription::kNormal);
 	}
 
 	_solveExitScene.readData(stream, ser.getVersion() == kGameTypeVampire);
 	ser.syncAsUint16LE(_solveSoundDelay);
-	_solveSound.read(stream, SoundDescription::kNormal);
+	_solveSound.readData(stream, SoundDescription::kNormal);
 	_exitScene.readData(stream, ser.getVersion() == kGameTypeVampire);
 	readRect(stream, _exitHotspot);
 }
diff --git a/engines/nancy/action/overlay.cpp b/engines/nancy/action/overlay.cpp
index b5e6ec45dcc..36d02074002 100644
--- a/engines/nancy/action/overlay.cpp
+++ b/engines/nancy/action/overlay.cpp
@@ -85,7 +85,7 @@ void Overlay::readData(Common::SeekableReadStream &stream) {
 
 	_sceneChange.readData(stream);
 	_flagsOnTrigger.readData(stream);
-	_sound.read(stream, SoundDescription::kNormal);
+	_sound.readData(stream, SoundDescription::kNormal);
 	uint numViewportFrames = stream.readUint16LE();
 
 	if (_overlayType == kPlayOverlayAnimated) {
diff --git a/engines/nancy/action/overridelockpuzzle.cpp b/engines/nancy/action/overridelockpuzzle.cpp
index 8094121229d..f3fccc02227 100644
--- a/engines/nancy/action/overridelockpuzzle.cpp
+++ b/engines/nancy/action/overridelockpuzzle.cpp
@@ -67,13 +67,13 @@ void OverrideLockPuzzle::readData(Common::SeekableReadStream &stream) {
 	readRectArray(stream, _lightDests, num);
 	stream.skip((10 - num) * 16);
 
-	_buttonSound.read(stream, SoundDescription::kNormal);
-	_wrongSound.read(stream, SoundDescription::kNormal);
+	_buttonSound.readData(stream, SoundDescription::kNormal);
+	_wrongSound.readData(stream, SoundDescription::kNormal);
 
 	_buttonPopTime = stream.readUint16LE();
 
 	_solveExitScene.readData(stream);
-	_solveSound.read(stream, SoundDescription::kNormal);
+	_solveSound.readData(stream, SoundDescription::kNormal);
 
 	_exitScene.readData(stream);
 	readRect(stream, _exitHotspot);
diff --git a/engines/nancy/action/passwordpuzzle.cpp b/engines/nancy/action/passwordpuzzle.cpp
index 2a2eb999f50..bf877a92046 100644
--- a/engines/nancy/action/passwordpuzzle.cpp
+++ b/engines/nancy/action/passwordpuzzle.cpp
@@ -56,9 +56,9 @@ void PasswordPuzzle::readData(Common::SeekableReadStream &stream) {
 	buf[19] = '\0';
 	_password = buf;
 	_solveExitScene.readData(stream);
-	_solveSound.read(stream, SoundDescription::kNormal);
+	_solveSound.readData(stream, SoundDescription::kNormal);
 	_failExitScene.readData(stream);
-	_failSound.read(stream, SoundDescription::kNormal);
+	_failSound.readData(stream, SoundDescription::kNormal);
 	_exitScene.readData(stream);
 	readRect(stream, _exitHotspot);
 }
diff --git a/engines/nancy/action/recordtypes.cpp b/engines/nancy/action/recordtypes.cpp
index eddb7627c39..ed31513e4a4 100644
--- a/engines/nancy/action/recordtypes.cpp
+++ b/engines/nancy/action/recordtypes.cpp
@@ -547,7 +547,7 @@ void ShowInventoryItem::execute() {
 }
 
 void PlayDigiSoundAndDie::readData(Common::SeekableReadStream &stream) {
-	_sound.read(stream, SoundDescription::kDIGI);
+	_sound.readData(stream, SoundDescription::kDIGI);
 	_sceneChange.readData(stream, g_nancy->getGameType() == kGameTypeVampire);
 
 	_flagOnTrigger.label = stream.readSint16LE();
@@ -582,7 +582,7 @@ void PlayDigiSoundAndDie::execute() {
 }
 
 void PlaySoundPanFrameAnchorAndDie::readData(Common::SeekableReadStream &stream) {
-	_sound.read(stream, SoundDescription::kDIGI);
+	_sound.readData(stream, SoundDescription::kDIGI);
 	stream.skip(2);
 }
 
@@ -593,7 +593,7 @@ void PlaySoundPanFrameAnchorAndDie::execute() {
 }
 
 void PlaySoundMultiHS::readData(Common::SeekableReadStream &stream) {
-	_sound.read(stream, SoundDescription::kNormal);
+	_sound.readData(stream, SoundDescription::kNormal);
 
 	if (g_nancy->getGameType() != kGameTypeVampire) {
 		_sceneChange.readData(stream);
@@ -646,7 +646,7 @@ void PlaySoundMultiHS::execute() {
 
 void HintSystem::readData(Common::SeekableReadStream &stream) {
 	_characterID = stream.readByte();
-	_genericSound.read(stream, SoundDescription::kNormal);
+	_genericSound.readData(stream, SoundDescription::kNormal);
 }
 
 void HintSystem::execute() {
diff --git a/engines/nancy/action/riddlepuzzle.cpp b/engines/nancy/action/riddlepuzzle.cpp
index ed3fbb2c92c..0c291facf6e 100644
--- a/engines/nancy/action/riddlepuzzle.cpp
+++ b/engines/nancy/action/riddlepuzzle.cpp
@@ -52,13 +52,13 @@ void RiddlePuzzle::readData(Common::SeekableReadStream &stream) {
 	_textboxTextFontID = stream.readUint16LE();
 	_cursorBlinkTime = stream.readUint16LE();
 	readRect(stream, _screenPosition);
-	_typeSound.read(stream, SoundDescription::kNormal);
-	_eraseSound.read(stream, SoundDescription::kNormal);
-	_enterSound.read(stream, SoundDescription::kNormal);
+	_typeSound.readData(stream, SoundDescription::kNormal);
+	_eraseSound.readData(stream, SoundDescription::kNormal);
+	_enterSound.readData(stream, SoundDescription::kNormal);
 	_successSceneChange.readData(stream);
-	_successSound.read(stream, SoundDescription::kNormal);
+	_successSound.readData(stream, SoundDescription::kNormal);
 	_exitSceneChange.readData(stream);
-	_exitSound.read(stream, SoundDescription::kNormal);
+	_exitSound.readData(stream, SoundDescription::kNormal);
 	readRect(stream, _exitHotspot);
 
 	_riddles.resize(stream.readUint16LE()) ;
@@ -71,7 +71,7 @@ void RiddlePuzzle::readData(Common::SeekableReadStream &stream) {
 		stream.read(buf, 128);
 		buf[127] = '\0';
 		riddle.text = buf;
-		riddle.sound.read(stream, SoundDescription::kNormal);
+		riddle.sound.readData(stream, SoundDescription::kNormal);
 
 		for (uint j = 0; j < 8; ++j) {
 			stream.read(buf, 20);
@@ -83,9 +83,9 @@ void RiddlePuzzle::readData(Common::SeekableReadStream &stream) {
 		}
 
 		riddle.sceneIncorrect.readData(stream);
-		riddle.soundIncorrect.read(stream, SoundDescription::kNormal);
+		riddle.soundIncorrect.readData(stream, SoundDescription::kNormal);
 		riddle.sceneCorrect.readData(stream);
-		riddle.soundCorrect.read(stream, SoundDescription::kNormal);
+		riddle.soundCorrect.readData(stream, SoundDescription::kNormal);
 	}
 }
 
diff --git a/engines/nancy/action/rippedletterpuzzle.cpp b/engines/nancy/action/rippedletterpuzzle.cpp
index 676ed220ff0..655951bacca 100644
--- a/engines/nancy/action/rippedletterpuzzle.cpp
+++ b/engines/nancy/action/rippedletterpuzzle.cpp
@@ -87,12 +87,12 @@ void RippedLetterPuzzle::readData(Common::SeekableReadStream &stream) {
 		_solveRotations[i] = stream.readByte();
 	}
 
-	_takeSound.read(stream, SoundDescription::kNormal);
-	_dropSound.read(stream, SoundDescription::kNormal);
-	_rotateSound.read(stream, SoundDescription::kNormal);
+	_takeSound.readData(stream, SoundDescription::kNormal);
+	_dropSound.readData(stream, SoundDescription::kNormal);
+	_rotateSound.readData(stream, SoundDescription::kNormal);
 
 	_solveExitScene.readData(stream);
-	_solveSound.read(stream, SoundDescription::kNormal);
+	_solveSound.readData(stream, SoundDescription::kNormal);
 
 	_exitScene.readData(stream);
 	readRect(stream, _exitHotspot);
diff --git a/engines/nancy/action/rotatinglockpuzzle.cpp b/engines/nancy/action/rotatinglockpuzzle.cpp
index cdef29a69d3..6b897884f8d 100644
--- a/engines/nancy/action/rotatinglockpuzzle.cpp
+++ b/engines/nancy/action/rotatinglockpuzzle.cpp
@@ -92,10 +92,10 @@ void RotatingLockPuzzle::readData(Common::SeekableReadStream &stream) {
 
 	stream.skip(8 - numDials);
 
-	_clickSound.read(stream, SoundDescription::kNormal);
+	_clickSound.readData(stream, SoundDescription::kNormal);
 	_solveExitScene.readData(stream);
 	_solveSoundDelay = stream.readUint16LE();
-	_solveSound.read(stream, SoundDescription::kNormal);
+	_solveSound.readData(stream, SoundDescription::kNormal);
 
 	_exitScene.readData(stream);
 	readRect(stream, _exitHotspot);
diff --git a/engines/nancy/action/secondarymovie.cpp b/engines/nancy/action/secondarymovie.cpp
index 493dc735a88..22de5a70c5c 100644
--- a/engines/nancy/action/secondarymovie.cpp
+++ b/engines/nancy/action/secondarymovie.cpp
@@ -74,7 +74,7 @@ void PlaySecondaryMovie::readData(Common::SeekableReadStream &stream) {
 	}
 
 	_triggerFlags.readData(stream);
-	_sound.read(stream, SoundDescription::kNormal);
+	_sound.readData(stream, SoundDescription::kNormal);
 	_sceneChange.readData(stream, ser.getVersion() == kGameTypeVampire);
 
 	uint16 numVideoDescs;
diff --git a/engines/nancy/action/sliderpuzzle.cpp b/engines/nancy/action/sliderpuzzle.cpp
index 793b9d26af2..6f84b14ad27 100644
--- a/engines/nancy/action/sliderpuzzle.cpp
+++ b/engines/nancy/action/sliderpuzzle.cpp
@@ -103,9 +103,9 @@ void SliderPuzzle::readData(Common::SeekableReadStream &stream) {
 
 	stream.skip((6 - _height) * 6 * 2);
 
-	_clickSound.read(stream, SoundDescription::kNormal);
+	_clickSound.readData(stream, SoundDescription::kNormal);
 	_solveExitScene.readData(stream);
-	_solveSound.read(stream, SoundDescription::kNormal);
+	_solveSound.readData(stream, SoundDescription::kNormal);
 	_exitScene.readData(stream);
 	readRect(stream, _exitHotspot);
 }
diff --git a/engines/nancy/action/telephone.cpp b/engines/nancy/action/telephone.cpp
index fe15a099208..0e0e75fa13a 100644
--- a/engines/nancy/action/telephone.cpp
+++ b/engines/nancy/action/telephone.cpp
@@ -65,12 +65,12 @@ void Telephone::readData(Common::SeekableReadStream &stream) {
 		}
 	}
 
-	_genericDialogueSound.read(stream, SoundDescription::kNormal);
-	_genericButtonSound.read(stream, SoundDescription::kNormal);
-	_ringSound.read(stream, SoundDescription::kNormal);
-	_dialToneSound.read(stream, SoundDescription::kNormal);
-	_dialAgainSound.read(stream, SoundDescription::kNormal);
-	_hangUpSound.read(stream, SoundDescription::kNormal);
+	_genericDialogueSound.readData(stream, SoundDescription::kNormal);
+	_genericButtonSound.readData(stream, SoundDescription::kNormal);
+	_ringSound.readData(stream, SoundDescription::kNormal);
+	_dialToneSound.readData(stream, SoundDescription::kNormal);
+	_dialAgainSound.readData(stream, SoundDescription::kNormal);
+	_hangUpSound.readData(stream, SoundDescription::kNormal);
 
 	_buttonSoundNames.reserve(12);
 	for (uint i = 0; i < 12; ++i) {
diff --git a/engines/nancy/action/towerpuzzle.cpp b/engines/nancy/action/towerpuzzle.cpp
index 2f8710dd9c8..03d21a6757b 100644
--- a/engines/nancy/action/towerpuzzle.cpp
+++ b/engines/nancy/action/towerpuzzle.cpp
@@ -80,12 +80,12 @@ void TowerPuzzle::readData(Common::SeekableReadStream &stream) {
 		}
 	}
 
-	_takeSound.read(stream, SoundDescription::kNormal);
-	_dropSound.read(stream, SoundDescription::kNormal);
+	_takeSound.readData(stream, SoundDescription::kNormal);
+	_dropSound.readData(stream, SoundDescription::kNormal);
 
 	_solveExitScene._sceneChange.readData(stream);
 	stream.skip(2);
-	_solveSound.read(stream, SoundDescription::kNormal);
+	_solveSound.readData(stream, SoundDescription::kNormal);
 	_solveExitScene._flag.label = stream.readSint16LE();
 	_solveExitScene._flag.flag = stream.readByte();
 
diff --git a/engines/nancy/commontypes.cpp b/engines/nancy/commontypes.cpp
index d223d9383b2..fad15b0ac2a 100644
--- a/engines/nancy/commontypes.cpp
+++ b/engines/nancy/commontypes.cpp
@@ -86,41 +86,35 @@ void SecondaryVideoDescription::readData(Common::SeekableReadStream &stream) {
 	stream.skip(0x20);
 }
 
-void SoundDescription::read(Common::SeekableReadStream &stream, Type type) {
-	readFilename(stream, name);
+void SoundDescription::readData(Common::SeekableReadStream &stream, Type type) {
+	Common::Serializer s(&stream, nullptr);
+	s.setVersion(type);
 
-	if (type == SoundDescription::kScene) {
-		stream.skip(4);
-	}
-	channelID = stream.readUint16LE();
-
-	// 0xE is soundPlayFormat, but I have no idea what that does yet
-
-	// The difference between these is a couple members found at the same position
-	// whose purpose I don't understand, so for now just skip them
-	switch (type) {
-	case kNormal:
-		stream.skip(8);
-		break;
-	case kMenu:
-		stream.skip(6);
-		break;
-	case kScene:
-		// fall through
-	case kDIGI:
-		stream.skip(4);
-		break;
-	}
+	readFilename(s, name);
+
+	s.skip(4, kScene, kScene);
+	s.syncAsUint16LE(channelID);
 
-	numLoops = stream.readUint16LE();
-	if (stream.readUint16LE() != 0) { // loop indefinitely
+	s.skip(2); // PLAY_SOUND_FROM_HD = 1, PLAY_SOUND_FROM_CDROM = 2
+	s.skip(2); // PLAY_SOUND_AS_DIGI = 1, PLAY_SOUND_AS_STREAM = 2
+	s.skip(4, kNormal, kNormal);
+	s.skip(2, kMenu, kMenu);
+
+	s.syncAsUint16LE(numLoops);
+	uint16 loopType;
+	s.syncAsUint16LE(loopType);
+	if (loopType != 0) { // LOOP_ONCE = 1, LOOP_INFINITE = 0
 		numLoops = 0;
 	}
-	stream.skip(2);
-	volume = stream.readUint16LE();
-	stream.skip(2);
-	panAnchorFrame = stream.readUint16LE();
-	stream.skip(2);
+	
+	s.skip(2);
+	s.syncAsUint16LE(volume);
+	s.skip(2); // Second volume, always (?) same as the first
+	
+	s.syncAsUint32LE(samplesPerSec, kNormal, kNormal);
+	s.syncAsUint16LE(panAnchorFrame, kDIGI, kDIGI);
+	s.skip(2, kDIGI, kDIGI);
+	s.skip(4, kMenu, kScene);
 }
 
 void ConditionalDialogue::readData(Common::SeekableReadStream &stream) {
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index 43f1e65ec09..78710d725cd 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -172,15 +172,16 @@ struct SecondaryVideoDescription {
 
 // Descrbes a single sound. Combines four different structs found in the data in one
 struct SoundDescription {
-	enum Type { kNormal, kMenu, kDIGI, kScene };
+	enum Type { kNormal = 0, kDIGI = 1, kMenu = 2, kScene = 3 };
 
 	Common::String name;
 	uint16 channelID = 0;
 	uint16 numLoops = 0;
 	uint16 volume = 0;
 	uint16 panAnchorFrame = 0;
+	uint32 samplesPerSec = 0;
 
-	void read(Common::SeekableReadStream &stream, Type type);
+	void readData(Common::SeekableReadStream &stream, Type type);
 };
 
 // Structs inside nancy.dat, which contains all the data that was
diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index 7afb3ca34fa..f5c4f3880b2 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -124,7 +124,7 @@ INV::INV(Common::SeekableReadStream *chunkStream) {
 	byte textBuf[60];
 
 	if (s.getVersion() >= kGameTypeNancy2) {
-		cantSound.read(*chunkStream, SoundDescription::kNormal);
+		cantSound.readData(*chunkStream, SoundDescription::kNormal);
 		s.syncBytes(textBuf, 60);
 		textBuf[59] = '\0';
 		cantText = (char *)textBuf;
@@ -167,14 +167,14 @@ INV::INV(Common::SeekableReadStream *chunkStream) {
 			textBuf[59] = '\0';
 			item.generalCantText = (char *)textBuf;
 
-			item.specificCantSound.read(*chunkStream, SoundDescription::kNormal);
-			item.generalCantSound.read(*chunkStream, SoundDescription::kNormal);
+			item.specificCantSound.readData(*chunkStream, SoundDescription::kNormal);
+			item.generalCantSound.readData(*chunkStream, SoundDescription::kNormal);
 		} else if (s.getVersion() >= kGameTypeNancy3) {
 			s.syncBytes(textBuf, 60);
 			textBuf[59] = '\0';
 			item.specificCantText = (char *)textBuf;
 
-			item.specificCantSound.read(*chunkStream, SoundDescription::kNormal);
+			item.specificCantSound.readData(*chunkStream, SoundDescription::kNormal);
 		}
 	}
 
@@ -246,7 +246,7 @@ MAP::MAP(Common::SeekableReadStream *chunkStream) {
 
 	sounds.resize(numMaps);
 	for (uint i = 0; i < numMaps; ++i) {
-		sounds[i].read(*chunkStream, SoundDescription::kMenu);
+		sounds[i].readData(*chunkStream, SoundDescription::kMenu);
 	}
 
 	s.skip(0x20);
@@ -345,7 +345,7 @@ CRED::CRED(Common::SeekableReadStream *chunkStream) {
 
 	updateTime = chunkStream->readUint16LE();
 	pixelsToScroll = chunkStream->readUint16LE();
-	sound.read(*chunkStream, SoundDescription::kMenu);
+	sound.readData(*chunkStream, SoundDescription::kMenu);
 
 	delete chunkStream;
 }
diff --git a/engines/nancy/sound.cpp b/engines/nancy/sound.cpp
index 7cbdc794dc0..f155f58a07f 100644
--- a/engines/nancy/sound.cpp
+++ b/engines/nancy/sound.cpp
@@ -189,7 +189,7 @@ bool readHISHeader(Common::SeekableReadStream *stream, SoundType &type, uint16 &
 	return true;
 }
 
-Audio::SeekableAudioStream *SoundManager::makeHISStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
+Audio::SeekableAudioStream *SoundManager::makeHISStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint overrideSamplesPerSec) {
 	char buf[22];
 
 	stream->read(buf, 22);
@@ -242,7 +242,7 @@ Audio::SeekableAudioStream *SoundManager::makeHISStream(Common::SeekableReadStre
 	Common::SeekableSubReadStream *subStream = new Common::SeekableSubReadStream(stream, stream->pos(), stream->pos() + size, disposeAfterUse);
 
 	if (type == kSoundTypeRaw || type == kSoundTypeDiamondware)
-		return Audio::makeRawStream(subStream, samplesPerSec, flags, DisposeAfterUse::YES);
+		return Audio::makeRawStream(subStream, overrideSamplesPerSec == 0 ? samplesPerSec : overrideSamplesPerSec, flags, DisposeAfterUse::YES);
 	else
 		return Audio::makeVorbisStream(subStream, DisposeAfterUse::YES);
 }
@@ -264,7 +264,7 @@ void SoundManager::loadCommonSounds(IFF *boot) {
 		chunk = boot->getChunkStream(s);
 		if (chunk) {
 			SoundDescription &desc = _commonSounds.getOrCreateVal(s);
-			desc.read(*chunk, SoundDescription::kNormal);
+			desc.readData(*chunk, SoundDescription::kNormal);
 			g_nancy->_sound->loadSound(desc);
 			_channels[desc.channelID].isPersistent = true;
 
@@ -276,7 +276,7 @@ void SoundManager::loadCommonSounds(IFF *boot) {
 	chunk = boot->getChunkStream("MSND"); // channel 28
 	if (chunk) {
 		SoundDescription &desc = _commonSounds.getOrCreateVal("MSND");
-		desc.read(*chunk, SoundDescription::kMenu);
+		desc.readData(*chunk, SoundDescription::kMenu);
 		g_nancy->_sound->loadSound(desc);
 		_channels[desc.channelID].isPersistent = true;
 
@@ -310,7 +310,7 @@ void SoundManager::loadSound(const SoundDescription &description, bool panning)
 
 	Common::SeekableReadStream *file = SearchMan.createReadStreamForMember(description.name + (g_nancy->getGameType() == kGameTypeVampire ? ".dwd" : ".his"));
 	if (file) {
-		_channels[description.channelID].stream = makeHISStream(file, DisposeAfterUse::YES);
+		_channels[description.channelID].stream = makeHISStream(file, DisposeAfterUse::YES, description.samplesPerSec);
 	}
 }
 
diff --git a/engines/nancy/sound.h b/engines/nancy/sound.h
index 3e491f56443..6277217c468 100644
--- a/engines/nancy/sound.h
+++ b/engines/nancy/sound.h
@@ -74,7 +74,7 @@ public:
 	// Used when changing scenes
 	void stopAndUnloadSpecificSounds();
 
-	static Audio::SeekableAudioStream *makeHISStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
+	static Audio::SeekableAudioStream *makeHISStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 overrideSamplesPerSec = 0);
 
 protected:
 	struct Channel {
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index cbdf7f63447..a7484339cc4 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -73,7 +73,7 @@ void Scene::SceneSummary::read(Common::SeekableReadStream &stream) {
 		readFilename(stream, palettes[2]);
 	}
 
-	sound.read(stream, SoundDescription::kScene);
+	sound.readData(stream, SoundDescription::kScene);
 
 	ser.skip(6);
 	ser.syncAsUint16LE(panningType);




More information about the Scummvm-git-logs mailing list