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

fracturehill noreply at scummvm.org
Thu Jul 13 11:33:53 UTC 2023


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

Summary:
9162c5357c NANCY: Add detection entries
eda2ee947c NANCY: Fix use-then-lose items
1bfb6f8d98 NANCY: Ignore invalid hotspots
e9779c0c36 NANCY: Implement SoundEqualizerPuzzle


Commit: 9162c5357c55dad2bf3125c4d1775c137d98a918
    https://github.com/scummvm/scummvm/commit/9162c5357c55dad2bf3125c4d1775c137d98a918
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-07-13T14:32:46+03:00

Commit Message:
NANCY: Add detection entries

Added detection entries for nancy3 and nancy4's Steam
releases, as well as an unknown variant of nancy5.

Changed paths:
    engines/nancy/detection.cpp


diff --git a/engines/nancy/detection.cpp b/engines/nancy/detection.cpp
index f2f9a8e160c..9e366da4129 100644
--- a/engines/nancy/detection.cpp
+++ b/engines/nancy/detection.cpp
@@ -144,7 +144,18 @@ static const Nancy::NancyGameDescription gameDescriptions[] = {
 			AD_ENTRY1s("ciftree.dat", "ee5f8832226567c3610556497c451b09", 16256355),
 			Common::EN_ANY,
 			Common::kPlatformWindows,
-			ADGF_UNSTABLE | ADGF_DROPPLATFORM | ADGF_DROPPLATFORM,
+			ADGF_UNSTABLE | ADGF_DROPPLATFORM,
+			GUIO0()
+		},
+		Nancy::kGameTypeNancy3
+	},
+	{ // Steam version
+		{
+			"nancy3", nullptr,
+			AD_ENTRY1s("ciftree.dat", "6b379f9d8edfb2d439062122e08f785c", 16161115),
+			Common::EN_ANY,
+			Common::kPlatformWindows,
+			ADGF_UNSTABLE | ADGF_DROPPLATFORM,
 			GUIO0()
 		},
 		Nancy::kGameTypeNancy3
@@ -171,7 +182,7 @@ static const Nancy::NancyGameDescription gameDescriptions[] = {
 			AD_ENTRY1s("ciftree.dat", "6b379f9d8edfb2d439062122e08f785c", 16161148),
 			Common::RU_RUS,
 			Common::kPlatformWindows,
-			ADGF_UNSTABLE | ADGF_DROPPLATFORM | ADGF_DROPPLATFORM,
+			ADGF_UNSTABLE | ADGF_DROPPLATFORM,
 			GUIO0()
 		},
 		Nancy::kGameTypeNancy3
@@ -203,6 +214,28 @@ static const Nancy::NancyGameDescription gameDescriptions[] = {
 		},
 		Nancy::kGameTypeNancy4
 	},
+	{ // MD5 by fracturehill
+		{
+			"nancy4", nullptr,
+			AD_ENTRY1s("ciftree.dat", "8645fad8c3fb8c0ee13e7a0a75902782", 9714463),
+			Common::RU_RUS,
+			Common::kPlatformWindows,
+			ADGF_UNSTABLE | ADGF_DROPPLATFORM,
+			GUIO0()
+		},
+		Nancy::kGameTypeNancy4
+	},
+	{ // Steam version
+		{
+			"nancy4", nullptr,
+			AD_ENTRY1s("ciftree.dat", "3ad55cd8f9a3b010a19de44ff4ce7edf", 8786300),
+			Common::EN_ANY,
+			Common::kPlatformWindows,
+			ADGF_UNSTABLE | ADGF_DROPPLATFORM,
+			GUIO0()
+		},
+		Nancy::kGameTypeNancy4
+	},
 	{ // MD5 by waltervn
 		{
 			"nancy4", nullptr,
@@ -219,17 +252,6 @@ static const Nancy::NancyGameDescription gameDescriptions[] = {
 		},
 		Nancy::kGameTypeNancy4
 	},
-	{ // MD5 by fracturehill
-		{
-			"nancy4", nullptr,
-			AD_ENTRY1s("ciftree.dat", "8645fad8c3fb8c0ee13e7a0a75902782", 9714463),
-			Common::RU_RUS,
-			Common::kPlatformWindows,
-			ADGF_UNSTABLE | ADGF_DROPPLATFORM,
-			GUIO0()
-		},
-		Nancy::kGameTypeNancy4
-	},
 	{ // MD5 by fracturehill
 		{
 			"nancy4", nullptr,
@@ -290,6 +312,22 @@ static const Nancy::NancyGameDescription gameDescriptions[] = {
 		},
 		Nancy::kGameTypeNancy5
 	},
+	{ // MD5 by fracturehill
+		{
+			"nancy5", nullptr,
+			{
+				{ "data1.hdr", 0, "0db3fb5bc002eb875eebb872969a22ca", 278505 },
+				{ "data1.cab", 0, "b5d2d218ded5683b5ca2eafcdc1ed76e", 1720654 },
+				{ "data2.cab", 0, "d379a879fb23b3013f78537927ac6cfe", 548761463 },
+				AD_LISTEND
+			},
+			Common::EN_ANY,
+			Common::kPlatformWindows,
+			ADGF_UNSTABLE | ADGF_DROPPLATFORM | Nancy::GF_COMPRESSED,
+			GUIO0()
+		},
+		Nancy::kGameTypeNancy5
+	},
 	{ // MD5 by Strangerke
 		{
 			"nancy6", nullptr,


Commit: eda2ee947c167dd3f58944824417992e40440f82
    https://github.com/scummvm/scummvm/commit/eda2ee947c167dd3f58944824417992e40440f82
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-07-13T14:32:46+03:00

Commit Message:
NANCY: Fix use-then-lose items

Items marked as single-use are now correctly removed from
the inventory. Also extended the get_inventory console
command to show if an item is single-use or not.

Changed paths:
    engines/nancy/action/actionmanager.cpp
    engines/nancy/console.cpp


diff --git a/engines/nancy/action/actionmanager.cpp b/engines/nancy/action/actionmanager.cpp
index 4d43bb65310..add96cb7ab6 100644
--- a/engines/nancy/action/actionmanager.cpp
+++ b/engines/nancy/action/actionmanager.cpp
@@ -74,6 +74,8 @@ void ActionManager::handleInput(NancyInput &input) {
 
 							NancySceneState.setHeldItem(-1);
 						}
+
+						rec->_cursorDependency = nullptr;
 					}
 					
 				}
@@ -371,13 +373,8 @@ void ActionManager::processDependency(DependencyRecord &dep, ActionRecord &recor
 					}
 				}
 
-				if (isSatisfied) {
-					dep.satisfied = true;
-					record._cursorDependency = nullptr;
-				} else {
-					dep.satisfied = false;
-					record._cursorDependency = &dep;
-				}
+				dep.satisfied = isSatisfied;
+				record._cursorDependency = &dep;
 			}
 			
 			break;
diff --git a/engines/nancy/console.cpp b/engines/nancy/console.cpp
index 7fdd00fddfe..5e846292a45 100644
--- a/engines/nancy/console.cpp
+++ b/engines/nancy/console.cpp
@@ -669,9 +669,10 @@ bool NancyConsole::Cmd_getInventory(int argc, const char **argv) {
 
 	if (argc == 1) {
 		for (uint i = 0; i < numItems; ++i) {
-			debugPrintf("\nItem %u, %s, %s",
+			debugPrintf("\nItem %u, %s, %s, %s",
 				i,
 				g_nancy->_inventoryData->itemDescriptions[i].name.c_str(),
+				g_nancy->_inventoryData->itemDescriptions[i].keepItem == 0 ? "UseThenLose" : "KeepAlways",
 				NancySceneState.hasItem(i) == g_nancy->_true ? "true" : "false");
 		}
 	} else {
@@ -681,9 +682,10 @@ bool NancyConsole::Cmd_getInventory(int argc, const char **argv) {
 				debugPrintf("\nInvalid flag %s", argv[i]);
 				continue;
 			}
-			debugPrintf("\nItem %u, %s, %s",
+			debugPrintf("\nItem %u, %s, %s, %s",
 				flagID,
 				g_nancy->_inventoryData->itemDescriptions[flagID].name.c_str(),
+				g_nancy->_inventoryData->itemDescriptions[i].keepItem == 0 ? "UseThenLose" : "KeepAlways",
 				NancySceneState.hasItem(i) == g_nancy->_true ? "true" : "false");
 
 		}


Commit: 1bfb6f8d98f02d9250c398d47f84ee1eb3c8168e
    https://github.com/scummvm/scummvm/commit/1bfb6f8d98f02d9250c398d47f84ee1eb3c8168e
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-07-13T14:32:46+03:00

Commit Message:
NANCY: Ignore invalid hotspots

Added a check for action record hotspot validity. This
fixes a broken frame in nancy2 scene 1600.

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


diff --git a/engines/nancy/action/actionmanager.cpp b/engines/nancy/action/actionmanager.cpp
index add96cb7ab6..da78c3f6198 100644
--- a/engines/nancy/action/actionmanager.cpp
+++ b/engines/nancy/action/actionmanager.cpp
@@ -41,7 +41,10 @@ void ActionManager::handleInput(NancyInput &input) {
 			rec->handleInput(input);
 		}
 
-		if (rec->_isActive && rec->_hasHotspot && NancySceneState.getViewport().convertViewportToScreen(rec->_hotspot).contains(input.mousePos)) {
+		if (	rec->_isActive &&
+				rec->_hasHotspot &&
+				rec->_hotspot.isValidRect() && // Needed for nancy2 scene 1600
+				NancySceneState.getViewport().convertViewportToScreen(rec->_hotspot).contains(input.mousePos)) {
 			g_nancy->_cursorManager->setCursorType(rec->getHoverCursor());
 
 			if (input.input & NancyInput::kLeftMouseButtonUp) {


Commit: e9779c0c367c9be415520b2c1e022ec265bd1ff6
    https://github.com/scummvm/scummvm/commit/e9779c0c367c9be415520b2c1e022ec265bd1ff6
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-07-13T14:32:46+03:00

Commit Message:
NANCY: Implement SoundEqualizerPuzzle

Implemented the SoundEqualizerPuzzle, used for nancy2's
mixing console sequence. Also extended the SoundManager
to accommodate the need to change volume and playback
rate while a sound is playing.

Changed paths:
  A engines/nancy/action/soundequalizerpuzzle.cpp
  A engines/nancy/action/soundequalizerpuzzle.h
    engines/nancy/action/arfactory.cpp
    engines/nancy/module.mk
    engines/nancy/puzzledata.cpp
    engines/nancy/puzzledata.h
    engines/nancy/sound.cpp
    engines/nancy/sound.h
    engines/nancy/ui/scrollbar.cpp
    engines/nancy/ui/scrollbar.h


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 50a726d6ef3..d94d809c34f 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -35,6 +35,7 @@
 #include "engines/nancy/action/riddlepuzzle.h"
 #include "engines/nancy/action/overridelockpuzzle.h"
 #include "engines/nancy/action/bombpuzzle.h"
+#include "engines/nancy/action/soundequalizerpuzzle.h"
 
 #include "engines/nancy/state/scene.h"
 
@@ -152,6 +153,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type) {
 		return new StopSound(); // StopAndUnloadSound, but we always unload
 	case 160:
 		return new HintSystem();
+	case 200:
+		return new SoundEqualizerPuzzle();
 	case 201:
 		return new TowerPuzzle();
 	case 202:
diff --git a/engines/nancy/action/soundequalizerpuzzle.cpp b/engines/nancy/action/soundequalizerpuzzle.cpp
new file mode 100644
index 00000000000..0dbf8ba918d
--- /dev/null
+++ b/engines/nancy/action/soundequalizerpuzzle.cpp
@@ -0,0 +1,304 @@
+/* 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/action/soundequalizerpuzzle.h"
+#include "engines/nancy/state/scene.h"
+#include "engines/nancy/ui/scrollbar.h"
+
+#include "engines/nancy/util.h"
+#include "engines/nancy/nancy.h"
+#include "engines/nancy/graphics.h"
+#include "engines/nancy/resource.h"
+#include "engines/nancy/input.h"
+#include "engines/nancy/sound.h"
+#include "engines/nancy/puzzledata.h"
+
+namespace Nancy {
+namespace Action {
+
+class ViewportScrollbar : public UI::Scrollbar {
+public:
+	ViewportScrollbar(uint16 zOrder, const Common::Rect &srcBounds, Graphics::ManagedSurface &srcSurf, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical = true) :
+		Scrollbar(zOrder, srcBounds, srcSurf, topPosition, scrollDistance, isVertical) {}
+	virtual ~ViewportScrollbar() = default;
+
+    bool handleInput(NancyInput &input) {
+        if (_screenPosition.contains(input.mousePos)) {
+        	input.input &= (~NancyInput::kRightMouseButtonUp);
+
+        	Scrollbar::handleInput(input);
+
+		    g_nancy->_cursorManager->setCursorType(CursorManager::kHotspot);
+			return true;
+        }
+
+		return false;
+    }
+};
+
+SoundEqualizerPuzzle::~SoundEqualizerPuzzle() {
+	for (auto *scrollbar : _sliders) {
+		delete scrollbar;
+	}
+}
+
+void SoundEqualizerPuzzle::init() {
+	Common::Rect screenBounds = NancySceneState.getViewport().getBounds();
+	_drawSurface.create(screenBounds.width(), screenBounds.height(), g_nancy->_graphicsManager->getInputPixelFormat());
+	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
+	setTransparent(true);
+	setVisible(true);
+	moveTo(screenBounds);
+
+	g_nancy->_resource->loadImage(_imageName, _image);
+	_image.setTransparentColor(_drawSurface.getTransparentColor());
+
+	Common::Rect vpPos = g_nancy->_viewportData->screenPosition;
+
+	if (_puzzleState->sliderValues[0] == 255) {
+		for (uint i = 0; i < 6; ++i) {
+			_puzzleState->sliderValues[i] = _sliderInitialPositions[i];
+		}
+	}
+
+	_sliders.resize(6);
+	for (uint i = 0; i < 6; ++i) {
+		Common::Point screenDest(_sliderX[i], _sliderYMax[i] - (_sliderSrc.height() / 2));
+		screenDest.x += vpPos.left;
+		screenDest.y += vpPos.top;
+		_sliders[i] = new ViewportScrollbar(	8,
+												_sliderSrc,
+												_image,
+												screenDest,
+												_sliderYMin[i] - _sliderYMax[i]);
+		_sliders[i]->init();
+		_sliders[i]->setPosition((float)(100 - _puzzleState->sliderValues[i]) / 100);
+	}
+}
+
+void SoundEqualizerPuzzle::registerGraphics() {
+	for (auto *scrollbar : _sliders) {
+		scrollbar->registerGraphics();
+	}
+
+	RenderActionRecord::registerGraphics();
+}
+
+void SoundEqualizerPuzzle::readData(Common::SeekableReadStream &stream) {
+	_puzzleState = (SoundEqualizerPuzzleData *)NancySceneState.getPuzzleData(SoundEqualizerPuzzleData::getTag());
+	assert(_puzzleState);
+
+	uint16 difficulty = NancySceneState.getDifficulty();
+	readFilename(stream, _imageName);
+
+	readRect(stream, _buttonSrc);
+	readRect(stream, _buttonDest);
+	readRect(stream, _sliderSrc);
+
+	_sliderX.resize(6);
+	_sliderYMin.resize(6);
+	_sliderYMax.resize(6);
+	for (uint i = 0; i < 6; ++i) {
+		_sliderX[i] = stream.readUint16LE();
+		_sliderYMin[i] = stream.readUint16LE();
+		_sliderYMax[i] = stream.readUint16LE();
+	}
+
+	readRect(stream, _lightSrc);
+
+	_lightDests.resize(6);
+	for (uint i = 0; i < 6; ++i) {
+		readRectArray(stream, _lightDests[i], 10);
+	}
+
+	_sliderInitialPositions.resize(6);
+	for (uint i = 0; i < 3; ++i) {
+		// Only read the data for the current difficulty and skip over the rest
+		if (i == difficulty) {
+			for (uint j = 0; j < 6; ++j) {
+				_sliderInitialPositions[j] = stream.readUint16LE();
+			}
+		} else {
+			stream.skip(12);
+		}
+	}
+
+	_sounds.resize(3);
+	for (uint i = 0; i < 3; ++i) {
+		_sounds[i].readNormal(stream);
+	}
+
+	_minVolume.resize(3);
+	_maxVolume.resize(3);
+	_minRate.resize(3);
+	_maxRate.resize(3);
+
+	for (uint i = 0; i < 3; ++i) {
+		// Only read the data for the current difficulty and skip over the rest
+		if (i == difficulty) {
+			for (uint j = 0; j < 3; ++j) {
+				_minVolume[j] = stream.readUint16LE();
+				_maxVolume[j] = stream.readUint16LE();
+				_minRate[j] = stream.readUint32LE();
+				_maxRate[j] = stream.readUint32LE();
+			}
+		} else {
+			stream.skip(12 * 3);
+		}
+	}
+
+	_solveChannelID = stream.readUint16LE();
+
+	for (uint i = 0; i < 3; ++i) {
+		// Only read the data for the current difficulty and skip over the rest
+		if (i == difficulty) {
+			_solveMinVolume = stream.readUint16LE();
+			_solveMaxVolume = stream.readUint16LE();
+			_solveMinRate = stream.readUint32LE();
+			_solveMaxRate = stream.readUint32LE();
+		} else {
+			stream.skip(12);
+		}
+	}
+
+	_exitScene.readData(stream);
+	stream.skip(2);
+	_exitSound.readNormal(stream);
+
+	_solveFlag.label = stream.readSint16LE();
+	_solveFlag.flag = stream.readByte();
+}
+
+void SoundEqualizerPuzzle::execute() {
+	switch(_state) {
+	case kBegin:
+		init();
+		registerGraphics();
+
+		for (uint i = 0; i < 3; ++i) {
+			g_nancy->_sound->loadSound(_sounds[i]);
+			g_nancy->_sound->playSound(_sounds[i]);
+		}
+
+		for (uint i = 0; i < 6; ++i) {
+			updateSlider(i);
+		}
+
+		_state = kRun;
+		break;
+	case kRun:
+		break;
+	case kActionTrigger:
+		if (g_nancy->_sound->isSoundPlaying(_exitSound)) {
+			return;
+		}
+
+		for (uint i = 0; i < 3; ++i) {
+			g_nancy->_sound->stopSound(_sounds[i]);
+		}
+
+		NancySceneState.changeScene(_exitScene);
+		finishExecution();
+	}
+}
+
+void SoundEqualizerPuzzle::handleInput(NancyInput &input) {
+	if (_state == kActionTrigger) {
+		g_nancy->_cursorManager->setCursorType(CursorManager::kHotspot);
+		return;
+	} else if (_state == kBegin) {
+		return;
+	}
+
+	if (NancySceneState.getViewport().convertViewportToScreen(_buttonDest).contains(input.mousePos)) {
+		g_nancy->_cursorManager->setCursorType(CursorManager::kHotspot);
+
+		if (input.input & NancyInput::kLeftMouseButtonUp) {
+			// Exit button pressed
+			_drawSurface.blitFrom(_image, _buttonSrc, _buttonDest);
+			_needsRedraw = true;
+
+			g_nancy->_sound->loadSound(_exitSound);
+			g_nancy->_sound->playSound(_exitSound);
+			
+			_state = kActionTrigger;
+			return;
+		}
+	} else {
+		for (uint i = 0; i < 6; ++i) {
+			if (_sliders[i]->handleInput(input)) {
+				updateSlider(i);
+				break;
+			}
+		}
+	}
+}
+
+void SoundEqualizerPuzzle::updateSlider(uint sliderID) {
+	float sliderVal = 1 - _sliders[sliderID]->getPos();
+	_puzzleState->sliderValues[sliderID] = sliderVal * 100;
+	
+	if (sliderID < 3) {
+		// First three sliders change pitch, except when the slider
+		// controls the "solve" sound; in that case it does nothing
+		if (sliderID != _solveChannelID) {
+			g_nancy->_sound->setRate(_sounds[sliderID],
+				_minRate[sliderID] + (_maxRate[sliderID] - _minRate[sliderID]) * sliderVal);
+		}
+	} else {
+		// Other three sliders change volume; 
+		// "solve" sound slider behaves as an on/off switch
+		if (sliderID - 3 != _solveChannelID) {
+			g_nancy->_sound->setVolume(_sounds[sliderID - 3],
+				_minVolume[sliderID - 3] + (_maxVolume[sliderID - 3] - _minVolume[sliderID - 3]) * sliderVal);
+		} else {
+			if (sliderVal * 100 >= _solveMinVolume && sliderVal * 100 <= _solveMaxVolume) {
+				g_nancy->_sound->setVolume(_sounds[sliderID - 3], _maxVolume[sliderID - 3]);
+
+				// Since the rate for the "solve" sound never actualy changes,
+				// we only need the volume to be correct.
+				NancySceneState.setEventFlag(_solveFlag);
+			} else {
+				g_nancy->_sound->setVolume(_sounds[sliderID - 3], _minVolume[sliderID - 3]);
+			}
+		}
+	}
+
+	uint numLights = sliderVal * 10;
+
+	if (numLights < 10) {
+		Common::Rect clear = _lightDests[sliderID][numLights];
+		clear.extend(_lightDests[sliderID][9]);
+
+		_drawSurface.fillRect(clear, _drawSurface.getTransparentColor());
+
+		_needsRedraw = true;
+	}
+
+	for (uint i = 0; i < numLights; ++i) {
+		_drawSurface.blitFrom(_image, _lightSrc, _lightDests[sliderID][i]);
+
+		_needsRedraw = true;
+	}
+}
+
+} // End of namespace Action
+} // End of namespace Nancy
diff --git a/engines/nancy/action/soundequalizerpuzzle.h b/engines/nancy/action/soundequalizerpuzzle.h
new file mode 100644
index 00000000000..bff08a2254f
--- /dev/null
+++ b/engines/nancy/action/soundequalizerpuzzle.h
@@ -0,0 +1,99 @@
+/* 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_SOUNDEQUALIZERPUZZLE_H
+#define NANCY_ACTION_SOUNDEQUALIZERPUZZLE_H
+
+#include "engines/nancy/action/actionrecord.h"
+
+namespace UI {
+class Scrollbar;
+}
+
+namespace Nancy {
+
+struct SoundEqualizerPuzzleData;
+
+namespace Action {
+
+class ViewportScrollbar;
+
+class SoundEqualizerPuzzle: public RenderActionRecord {
+public:
+	SoundEqualizerPuzzle() : RenderActionRecord(7) {}
+	virtual ~SoundEqualizerPuzzle();
+
+	void init() override;
+	void registerGraphics() override;
+
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+	void handleInput(NancyInput &input) override;
+
+	Common::String _imageName;
+	
+	Common::Rect _buttonSrc;
+	Common::Rect _buttonDest;
+	Common::Rect _sliderSrc;
+
+	Common::Array<uint16> _sliderX;
+	Common::Array<uint16> _sliderYMin;
+	Common::Array<uint16> _sliderYMax;
+
+	Common::Rect _lightSrc;
+	Common::Array<Common::Array<Common::Rect>> _lightDests;
+
+	Common::Array<uint16> _sliderInitialPositions;
+
+	Common::Array<SoundDescription> _sounds;
+
+	Common::Array<uint16> _minVolume;
+	Common::Array<uint16> _maxVolume;
+	Common::Array<uint16> _minRate;
+	Common::Array<uint16> _maxRate;
+
+	uint16 _solveChannelID;
+	uint16 _solveMinVolume;
+	uint16 _solveMaxVolume;
+	uint16 _solveMinRate;
+	uint16 _solveMaxRate;
+
+	SceneChangeDescription _exitScene;
+	SoundDescription _exitSound;
+
+	FlagDescription _solveFlag;
+
+	Graphics::ManagedSurface _image;
+	Common::Array<ViewportScrollbar *> _sliders;
+
+	SoundEqualizerPuzzleData *_puzzleState = nullptr;
+
+protected:
+	Common::String getRecordTypeName() const override { return "SoundEqualizerPuzzle"; }
+	bool isViewportRelative() const override { return true; }
+
+	void updateSlider(uint sliderID);
+};
+
+} // End of namespace Action
+} // End of namespace Nancy
+
+#endif // NANCY_ACTION_SOUNDEQUALIZERPUZZLE_H
diff --git a/engines/nancy/module.mk b/engines/nancy/module.mk
index 075bfd37c4b..d06009945d4 100644
--- a/engines/nancy/module.mk
+++ b/engines/nancy/module.mk
@@ -18,6 +18,7 @@ MODULE_OBJS = \
   action/secondarymovie.o \
   action/secondaryvideo.o \
   action/sliderpuzzle.o \
+  action/soundequalizerpuzzle.o \
   action/towerpuzzle.o \
   action/telephone.o \
   ui/fullscreenimage.o \
diff --git a/engines/nancy/puzzledata.cpp b/engines/nancy/puzzledata.cpp
index 5515e88f5da..9b0baa117e7 100644
--- a/engines/nancy/puzzledata.cpp
+++ b/engines/nancy/puzzledata.cpp
@@ -96,6 +96,14 @@ void RiddlePuzzleData::synchronize(Common::Serializer &ser) {
 	ser.syncArray(solvedRiddleIDs.data(), numRiddles, Common::Serializer::Byte);
 }
 
+SoundEqualizerPuzzleData::SoundEqualizerPuzzleData() {
+	sliderValues.resize(6, 255);
+}
+
+void SoundEqualizerPuzzleData::synchronize(Common::Serializer &ser) {
+	ser.syncArray(sliderValues.data(), 6, Common::Serializer::Byte);
+}
+
 PuzzleData *makePuzzleData(const uint32 tag) {
 	switch(tag) {
 	case SliderPuzzleData::getTag():
@@ -106,6 +114,8 @@ PuzzleData *makePuzzleData(const uint32 tag) {
 		return new TowerPuzzleData();
 	case RiddlePuzzleData::getTag():
 		return new RiddlePuzzleData();
+	case SoundEqualizerPuzzleData::getTag():
+		return new SoundEqualizerPuzzleData();
 	default:
 		return nullptr;
 	}
diff --git a/engines/nancy/puzzledata.h b/engines/nancy/puzzledata.h
index bf9c90f4a07..abed79cf1d3 100644
--- a/engines/nancy/puzzledata.h
+++ b/engines/nancy/puzzledata.h
@@ -78,6 +78,15 @@ struct RiddlePuzzleData : public PuzzleData {
 	int8 incorrectRiddleID;
 };
 
+struct SoundEqualizerPuzzleData : public PuzzleData {
+	SoundEqualizerPuzzleData();
+
+	static constexpr uint32 getTag() { return MKTAG('S', 'E', 'Q', 'L'); }
+	virtual void synchronize(Common::Serializer &ser);
+
+	Common::Array<byte> sliderValues;
+};
+
 PuzzleData *makePuzzleData(const uint32 tag);
 
 } // End of namespace Nancy
diff --git a/engines/nancy/sound.cpp b/engines/nancy/sound.cpp
index 6dd1b011fa0..65cdc5199f6 100644
--- a/engines/nancy/sound.cpp
+++ b/engines/nancy/sound.cpp
@@ -486,6 +486,30 @@ void SoundManager::calculatePanForAllSounds() {
 	}
 }
 
+void SoundManager::setVolume(uint16 channelID, uint16 volume) {
+	_mixer->setChannelVolume(_channels[channelID].handle, volume);
+}
+
+void SoundManager::setVolume(const SoundDescription &description, uint16 volume) {
+	setVolume(description.channelID, volume);
+}
+
+void SoundManager::setVolume(const Common::String &chunkName, uint16 volume) {
+	setVolume(_commonSounds[chunkName], volume);
+}
+
+void SoundManager::setRate(uint16 channelID, uint32 rate) {
+	_mixer->setChannelRate(_channels[channelID].handle, rate);
+}
+
+void SoundManager::setRate(const SoundDescription &description, uint32 rate) {
+	setRate(description.channelID, rate);
+}
+
+void SoundManager::setRate(const Common::String &chunkName, uint32 rate) {
+	setRate(_commonSounds[chunkName], rate);
+}
+
 void SoundManager::stopAndUnloadSpecificSounds() {
 	if (g_nancy->getGameType() == kGameTypeVampire && Nancy::State::Map::hasInstance()) {
 		// Don't stop the map sound in certain scenes
diff --git a/engines/nancy/sound.h b/engines/nancy/sound.h
index 6277217c468..d5da394260c 100644
--- a/engines/nancy/sound.h
+++ b/engines/nancy/sound.h
@@ -71,6 +71,14 @@ public:
 	void calculatePan(const SoundDescription &description);
 	void calculatePanForAllSounds();
 
+	void setVolume(uint16 channelID, uint16 volume);
+	void setVolume(const SoundDescription &description, uint16 volume);
+	void setVolume(const Common::String &chunkName, uint16 volume);
+
+	void setRate(uint16 channelID, uint32 rate);
+	void setRate(const SoundDescription &description, uint32 rate);
+	void setRate(const Common::String &chunkName, uint32 rate);
+
 	// Used when changing scenes
 	void stopAndUnloadSpecificSounds();
 
diff --git a/engines/nancy/ui/scrollbar.cpp b/engines/nancy/ui/scrollbar.cpp
index b12b6e3ceab..0a79e0d7c1e 100644
--- a/engines/nancy/ui/scrollbar.cpp
+++ b/engines/nancy/ui/scrollbar.cpp
@@ -30,12 +30,15 @@ namespace Nancy {
 namespace UI {
 
 Scrollbar::Scrollbar(uint16 zOrder, const Common::Rect &srcBounds, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical) :
+    Scrollbar(zOrder, srcBounds, g_nancy->_graphicsManager->_object0, topPosition, scrollDistance, isVertical) {}
+
+Scrollbar::Scrollbar(uint16 zOrder, const Common::Rect &srcBounds, Graphics::ManagedSurface &srcSurf, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical) :
 		RenderObject(zOrder),
 		_isVertical(isVertical),
 		_isClicked(false),
 		_currentPosition(0),
 		_maxDist(scrollDistance) {
-	_drawSurface.create(g_nancy->_graphicsManager->_object0, srcBounds);
+	_drawSurface.create(srcSurf, srcBounds);
 
 	_startPosition = topPosition;
 	_startPosition.x -= srcBounds.width() / 2;
@@ -92,6 +95,11 @@ void Scrollbar::handleInput(NancyInput &input) {
 	}
 }
 
+void Scrollbar::setPosition(float pos) {
+    _currentPosition = pos;
+    moveTo(Common::Point(_screenPosition.left, _startPosition.y + (_maxDist * pos)));
+}
+
 void Scrollbar::calculatePosition() {
 	uint16 scroll = _isVertical ? _screenPosition.top - _startPosition.y : _screenPosition.left - _startPosition.x;
 
diff --git a/engines/nancy/ui/scrollbar.h b/engines/nancy/ui/scrollbar.h
index 9129c6d38f6..b85f6938aac 100644
--- a/engines/nancy/ui/scrollbar.h
+++ b/engines/nancy/ui/scrollbar.h
@@ -33,6 +33,7 @@ namespace UI {
 class Scrollbar : public RenderObject {
 public:
 	Scrollbar(uint16 zOrder, const Common::Rect &srcBounds, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical = true);
+	Scrollbar(uint16 zOrder, const Common::Rect &srcBounds, Graphics::ManagedSurface &srcSurf, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical = true);
 	virtual ~Scrollbar() = default;
 
 	void init() override;
@@ -42,6 +43,7 @@ public:
 	void resetPosition();
 	float getPos() const { return _currentPosition; }
 
+    void setPosition(float pos);
 	void calculatePosition();
 
 	Common::Point _startPosition;




More information about the Scummvm-git-logs mailing list