[Scummvm-git-logs] scummvm master -> 6ba8e586a33bfb03e395d4e86a26d2f95f4d28ce

fracturehill noreply at scummvm.org
Mon Apr 17 17:29:48 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:
197c2bbd26 NANCY: Implement TowerPuzzle
0faeb96c20 NANCY: Disable RippedLetterPuzzle input after completion
5844495076 NANCY: Clock fixes
6ba8e586a3 NANCY: Fix ShowInventoryItem


Commit: 197c2bbd267981ed820e1b30e19a1c80bfdcd5fc
    https://github.com/scummvm/scummvm/commit/197c2bbd267981ed820e1b30e19a1c80bfdcd5fc
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-17T20:27:26+03:00

Commit Message:
NANCY: Implement TowerPuzzle

Implemented the TowerPuzzle action record, which
handles the hanoi tower minigame in nancy2.

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


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 74f8f6a8398..ea22ece48f7 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -31,6 +31,7 @@
 #include "engines/nancy/action/passwordpuzzle.h"
 #include "engines/nancy/action/leverpuzzle.h"
 #include "engines/nancy/action/rippedletterpuzzle.h"
+#include "engines/nancy/action/towerpuzzle.h"
 
 #include "engines/nancy/state/scene.h"
 
@@ -144,6 +145,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type) {
 		return new PlaySoundMultiHS();
 	case 160:
 		return new HintSystem();
+	case 201:
+		return new TowerPuzzle();
 	case 203:
 		return new RippedLetterPuzzle();
 	default:
diff --git a/engines/nancy/action/towerpuzzle.cpp b/engines/nancy/action/towerpuzzle.cpp
new file mode 100644
index 00000000000..06f169b4b69
--- /dev/null
+++ b/engines/nancy/action/towerpuzzle.cpp
@@ -0,0 +1,329 @@
+/* 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/util.h"
+#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/state/scene.h"
+
+#include "engines/nancy/action/towerpuzzle.h"
+
+namespace Nancy {
+namespace Action {
+
+void TowerPuzzle::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());
+}
+
+void TowerPuzzle::registerGraphics() {
+	_heldRing.registerGraphics();
+	RenderObject::registerGraphics();
+}
+
+void TowerPuzzle::readData(Common::SeekableReadStream &stream) {
+	_puzzleState = NancySceneState._towerPuzzleState;
+	assert(_puzzleState);
+
+	readFilename(stream, _imageName);
+
+	_numRingsByDifficulty.resize(3);
+	for (uint i = 0; i < 3; ++i) {
+		_numRingsByDifficulty[i] = stream.readUint16LE();
+	}
+
+	stream.skip(2);
+
+	readRectArray(stream, _droppedRingSrcs, 6);
+	readRectArray(stream, _heldRingSrcs, 6);
+
+	readRectArray(stream, _hotspots, 3);
+
+	_destRects.resize(6);
+	for (uint ringID = 0; ringID < 6; ++ringID) {
+		_destRects[ringID].resize(3);
+		for (uint poleID = 0; poleID < 3; ++poleID) {
+			// Biggest ring can only be in bottom position,
+			// so it only has one rect per pole; second-biggest can
+			// be in bottom-most and one position above it, so it has
+			// two rects per pole, etc. Skipped data is array of 0xFF.
+			readRectArray(stream, _destRects[ringID][poleID], ringID + 1);
+			stream.skip((6 - ringID - 1) * 16);
+		}
+	}
+
+	_takeSound.read(stream, SoundDescription::kNormal);
+	_dropSound.read(stream, SoundDescription::kNormal);
+
+	_solveExitScene.readData(stream);
+	stream.skip(2);
+	_solveSound.read(stream, SoundDescription::kNormal);
+	_flagOnSolve.label = stream.readSint16LE();
+	_flagOnSolve.flag = stream.readByte();
+
+	_exitScene.readData(stream);
+	stream.skip(2);
+	_flagOnExit.label = stream.readSint16LE();
+	_flagOnExit.flag = stream.readByte();
+	readRect(stream, _exitHotspot);
+}
+
+void TowerPuzzle::execute() {
+	switch (_state) {
+	case kBegin:
+		init();
+		registerGraphics();
+		_numRings = _numRingsByDifficulty[NancySceneState.getDifficulty()];
+
+		if (!_puzzleState->playerHasTriedPuzzle) {
+			for (uint i = 0; i < _numRings; ++i) {
+				_puzzleState->order[0][i] = i;
+			}
+			_puzzleState->playerHasTriedPuzzle = true;
+		}
+
+		for (uint poleID = 0; poleID < 3; ++poleID) {
+			for (uint pos = 0; pos < _numRings; ++pos) {
+				if (_puzzleState->order[poleID][pos] == -1) {
+					continue;
+				}
+
+				drawRing(poleID, pos, _puzzleState->order[poleID][pos]);
+			}
+		}
+
+		g_nancy->_sound->loadSound(_takeSound);
+		g_nancy->_sound->loadSound(_dropSound);
+
+		_state = kRun;
+		// fall through
+	case kRun:
+		switch (_solveState) {
+		case kNotSolved :
+			for (uint i = 0; i < _numRings; ++i) {
+				// Win condition is valid for both middle and right pole
+				if (_puzzleState->order[1][i] != (int8)i && _puzzleState->order[2][i] != (int8)i) {
+					return;
+				}
+			}
+
+			g_nancy->_sound->loadSound(_solveSound);
+			g_nancy->_sound->playSound(_solveSound);
+			_solveState = kWaitForSound;
+			break;
+		case kWaitForSound :
+			if (!g_nancy->_sound->isSoundPlaying(_solveSound)) {
+				g_nancy->_sound->stopSound(_solveSound);
+				_state = kActionTrigger;
+			}
+
+			break;
+		}
+
+		break;
+	case kActionTrigger :
+		switch (_solveState) {
+		case kNotSolved:
+			NancySceneState.changeScene(_exitScene);
+			NancySceneState.setEventFlag(_flagOnExit);
+			break;
+		case kWaitForSound:
+			NancySceneState.changeScene(_solveExitScene);
+			NancySceneState.setEventFlag(_flagOnSolve);
+			_puzzleState->playerHasTriedPuzzle = false;
+			break;
+		}
+
+		g_nancy->_sound->stopSound(_takeSound);
+		g_nancy->_sound->stopSound(_dropSound);
+		g_nancy->_sound->stopSound(_solveSound);
+		finishExecution();
+	}
+}
+
+void TowerPuzzle::handleInput(NancyInput &input) {
+	if (_state != kRun && _solveState != kNotSolved) {
+		return;
+	}
+	
+	// Note: this is a click-and-drag puzzle
+
+	// Check if mouse is above a pole hotspot
+	// and change the cursor if needed
+	int hoveredPoleID = -1;
+	for (uint poleID = 0; poleID < 3; ++poleID) {
+		if (NancySceneState.getViewport().convertViewportToScreen(_hotspots[poleID]).contains(input.mousePos)) {
+			g_nancy->_cursorManager->setCursorType(CursorManager::kHotspot);
+			hoveredPoleID = poleID;
+			break;
+		}
+	}
+
+	if (_heldRingID == -1) {
+		// Not holding a ring
+
+		// First, check the exit hotspot
+		if (NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
+			g_nancy->_cursorManager->setCursorType(CursorManager::kExit);
+
+			if (input.input & NancyInput::kLeftMouseButtonUp) {
+				// Player has clicked, exit
+				_state = kActionTrigger;
+			}
+
+			return;
+		}
+
+		// Check if we need to pick up a ring
+		// Behavior is the same as original engine, where clicking outside a hotspot
+		// and dragging the mouse inside while holding the click still triggers
+		if (hoveredPoleID != -1 && (input.input & NancyInput::kLeftMouseButtonHeld)) {
+			// Find the position of the topmost ring
+			int ringPos;
+			for (ringPos = 5; ringPos > -1; --ringPos) {
+				if (_puzzleState->order[hoveredPoleID][ringPos] != -1) {
+					break;
+				}
+			}
+
+			if (ringPos == -1) {
+				// Pole contains no rings, do nothing
+				return;
+			}
+
+			// Redraw so the ring isn't visible anymore
+			drawRing(hoveredPoleID, ringPos, _puzzleState->order[hoveredPoleID][ringPos], true);
+
+			if (ringPos > 0) {
+				drawRing(hoveredPoleID, ringPos - 1, _puzzleState->order[hoveredPoleID][ringPos - 1]);
+			}
+
+			// Change the data
+			SWAP<int8>(_heldRingID, _puzzleState->order[hoveredPoleID][ringPos]);
+			_heldRingPoleID = hoveredPoleID;
+
+			// Show the held ring
+			_heldRing._drawSurface.create(_image, _heldRingSrcs[_heldRingID]);
+			_heldRing.setVisible(true);
+			_heldRing.setTransparent(true);
+
+			g_nancy->_sound->playSound(_takeSound);
+		}
+	}
+
+	if (_heldRingID != -1) {
+		// Holding a ring, check if it has just been dropped
+		if ((input.input & NancyInput::kLeftMouseButtonUp) || !(input.input & NancyInput::kLeftMouseButtonHeld)) {
+			// Check if dropped over a pole hotspot
+			// If not, return to old pole; if yes, move to new one
+			uint returnToPole = hoveredPoleID == -1 ? _heldRingPoleID : hoveredPoleID;
+
+			// Find the new position of the ring
+			uint newPos;
+			for (newPos = 0; newPos < 6; ++newPos) {
+				if (_puzzleState->order[returnToPole][newPos] == -1) {
+					break;
+				}
+			}
+
+			// Make sure the player can't place a larger ring on top of a smaller one
+			if (newPos > 0 && _puzzleState->order[returnToPole][newPos - 1] > _heldRingID) {
+				returnToPole = _heldRingPoleID;
+
+				for (newPos = 0; newPos < 6; ++newPos) {
+					if (_puzzleState->order[returnToPole][newPos] == -1) {
+						break;
+					}
+				}
+			}
+
+			// Draw the new ring in its place
+			drawRing(returnToPole, newPos, _heldRingID);
+
+			// Change the data
+			SWAP<int8>(_heldRingID, _puzzleState->order[returnToPole][newPos]);
+			_heldRingPoleID = -1;
+
+			g_nancy->_sound->playSound(_dropSound);
+
+			// Hide the held ring
+			_heldRing.setVisible(false);
+		} else {
+			// Still holding the ring, move under mouse
+
+			Common::Rect viewport = NancySceneState.getViewport().getScreenPosition();
+
+			// Do not move ring if mouse is outside viewport
+			if (!viewport.contains(input.mousePos)) {
+				return;
+			}
+
+			Common::Rect newScreenPos = _heldRingSrcs[_heldRingID];
+			newScreenPos.moveTo(input.mousePos);
+			newScreenPos.translate(-newScreenPos.width() / 2, -newScreenPos.height() / 2);
+
+			// Center of ring is at top left of cursor
+			const Common::Point &cursorHotspot = g_nancy->_cursorManager->getCurrentCursorHotspot();
+			newScreenPos.translate(-cursorHotspot.x, -cursorHotspot.y);
+
+			// Clip movement so the ring stays entirely inside the viewport
+			if (newScreenPos.left < viewport.left) {
+				newScreenPos.translate(viewport.left - newScreenPos.left, 0);
+			} else if (newScreenPos.right > viewport.right) {
+				newScreenPos.translate(viewport.right - newScreenPos.right, 0);
+			}
+
+			if (newScreenPos.top < viewport.top) {
+				newScreenPos.translate(0, viewport.top - newScreenPos.top);
+			} else if (newScreenPos.bottom > viewport.bottom) {
+				newScreenPos.translate(0, viewport.bottom - newScreenPos.bottom);
+			}
+
+			_heldRing.moveTo(newScreenPos);
+		}
+	}
+}
+
+void TowerPuzzle::drawRing(uint poleID, uint position, uint ringID, bool clear) {
+	_needsRedraw = true;
+
+	if (clear) {
+		// Just clear the ring, leaving a hole in the surface
+		// that needs to be filled by redrawing the ring below
+		_drawSurface.fillRect(_destRects[ringID][poleID][position], _drawSurface.getTransparentColor());
+		return;
+	}
+
+	_drawSurface.blitFrom(_image, _droppedRingSrcs[ringID], _destRects[ringID][poleID][position]);
+}
+
+} // End of namespace Action
+} // End of namespace Nancy
diff --git a/engines/nancy/action/towerpuzzle.h b/engines/nancy/action/towerpuzzle.h
new file mode 100644
index 00000000000..653d0c4a661
--- /dev/null
+++ b/engines/nancy/action/towerpuzzle.h
@@ -0,0 +1,82 @@
+/* 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_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 {
+public:
+	enum SolveState { kNotSolved, kWaitForSound };
+	TowerPuzzle() : RenderObject(7), _heldRing(8) {}
+	virtual ~TowerPuzzle() {}
+
+	void init() override;
+	void registerGraphics() override;
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+	void handleInput(NancyInput &input) override;
+
+protected:
+	Common::String getRecordTypeName() const override { return "TowerPuzzle"; }
+	bool isViewportRelative() const override { return true; }
+
+	void drawRing(uint poleID, uint position, uint ringID, bool clear = false);
+
+	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::Array<Common::Array<Common::Rect>>> _destRects; // [ringID][poleID][position]
+
+	SoundDescription _takeSound;
+	SoundDescription _dropSound;
+
+	SceneChangeDescription _solveExitScene;
+	SoundDescription _solveSound;
+	FlagDescription _flagOnSolve;
+
+	SceneChangeDescription _exitScene;
+	FlagDescription _flagOnExit;
+	Common::Rect _exitHotspot;
+
+	Graphics::ManagedSurface _image;
+	RenderObject _heldRing;
+	int8 _heldRingID = -1;
+	int8 _heldRingPoleID = -1;
+	SolveState _solveState = kNotSolved;
+	TowerPuzzleState *_puzzleState;
+	uint _numRings = 0;
+};
+
+} // End of namespace Action
+} // End of namespace Nancy
+
+#endif // NANCY_ACTION_TOWERIPPEDLETTERPUZZLE_H
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index b8b46865fbe..8254ebc92ff 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -252,6 +252,11 @@ struct RippedLetterPuzzleState {
 	bool playerHasTriedPuzzle;
 };
 
+struct TowerPuzzleState {
+	Common::Array<Common::Array<int8>> order;
+	bool playerHasTriedPuzzle;
+};
+
 } // End of namespace Nancy
 
 #endif // NANCY_COMMONYPES_H
diff --git a/engines/nancy/module.mk b/engines/nancy/module.mk
index fb96c90b751..44c6f1a2f2b 100644
--- a/engines/nancy/module.mk
+++ b/engines/nancy/module.mk
@@ -14,6 +14,7 @@ MODULE_OBJS = \
   action/secondarymovie.o \
   action/secondaryvideo.o \
   action/sliderpuzzle.o \
+  action/towerpuzzle.o \
   action/overlay.o \
   action/telephone.o \
   ui/fullscreenimage.o \
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index 4c2e9fc2069..10ef1e63b06 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -115,7 +115,8 @@ Scene::Scene() :
 		_activeConversation(nullptr),
 		_lightning(nullptr),
 		_sliderPuzzleState(nullptr),
-		_rippedLetterPuzzleState(nullptr) {}
+		_rippedLetterPuzzleState(nullptr),
+		_towerPuzzleState(nullptr) {}
 
 Scene::~Scene()  {
 	delete _helpButton;
@@ -502,7 +503,7 @@ void Scene::synchronize(Common::Serializer &ser) {
 		break;
 	}
 	case kGameTypeNancy2 :
-		if (!_rippedLetterPuzzleState) {
+		if (!_rippedLetterPuzzleState || !_towerPuzzleState) {
 			break;
 		}
 
@@ -516,6 +517,16 @@ void Scene::synchronize(Common::Serializer &ser) {
 		ser.syncArray(_rippedLetterPuzzleState->order.data(), 24, Common::Serializer::Byte);
 		ser.syncArray(_rippedLetterPuzzleState->rotations.data(), 24, Common::Serializer::Byte);
 
+		ser.syncAsByte(_towerPuzzleState->playerHasTriedPuzzle);
+
+		if (ser.isLoading()) {
+			_towerPuzzleState->order.resize(3, Common::Array<int8>(6, -1));
+		}
+
+		for (uint i = 0; i < 3; ++i) {
+			ser.syncArray(_towerPuzzleState->order[i].data(), 6, Common::Serializer::Byte);
+		}
+
 		break;
 	default:
 		break;
@@ -566,6 +577,12 @@ void Scene::init() {
 		_rippedLetterPuzzleState->playerHasTriedPuzzle = false;
 		_rippedLetterPuzzleState->order.resize(24, 0);
 		_rippedLetterPuzzleState->rotations.resize(24, 0);
+
+		delete _towerPuzzleState;
+		_towerPuzzleState = new TowerPuzzleState();
+		_towerPuzzleState->playerHasTriedPuzzle = false;
+		_towerPuzzleState->order.resize(3, Common::Array<int8>(6, -1));
+		break;
 	default:
 		break;
 	}
diff --git a/engines/nancy/state/scene.h b/engines/nancy/state/scene.h
index 0394a63f7f9..9a2a4e3c4d0 100644
--- a/engines/nancy/state/scene.h
+++ b/engines/nancy/state/scene.h
@@ -47,7 +47,6 @@ class NancyConsole;
 struct SceneChangeDescription;
 
 namespace Action {
-class SliderPuzzle;
 class ConversationSound;
 }
 
@@ -189,6 +188,7 @@ public:
 	// Game-specific data that needs to be saved/loaded
 	SliderPuzzleState *_sliderPuzzleState;
 	RippedLetterPuzzleState *_rippedLetterPuzzleState;
+	TowerPuzzleState *_towerPuzzleState;
 
 private:
 	void init();


Commit: 0faeb96c206300d71f1a3649fe8a0ee60a16d421
    https://github.com/scummvm/scummvm/commit/0faeb96c206300d71f1a3649fe8a0ee60a16d421
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-17T20:27:26+03:00

Commit Message:
NANCY: Disable RippedLetterPuzzle input after completion

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


diff --git a/engines/nancy/action/rippedletterpuzzle.cpp b/engines/nancy/action/rippedletterpuzzle.cpp
index bc0f273a84f..efd4ae0f186 100644
--- a/engines/nancy/action/rippedletterpuzzle.cpp
+++ b/engines/nancy/action/rippedletterpuzzle.cpp
@@ -173,6 +173,10 @@ void RippedLetterPuzzle::execute() {
 }
 
 void RippedLetterPuzzle::handleInput(NancyInput &input) {
+	if (_state != kRun && _solveState != kNotSolved) {
+		return;
+	}
+
 	for (uint i = 0; i < 24; ++i) {
 		Common::Rect screenHotspot = NancySceneState.getViewport().convertViewportToScreen(_destRects[i]);
 		if (screenHotspot.contains(input.mousePos)) {


Commit: 5844495076fd967b0d4d78ae526b0a544b8ad671
    https://github.com/scummvm/scummvm/commit/5844495076fd967b0d4d78ae526b0a544b8ad671
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-17T20:27:27+03:00

Commit Message:
NANCY: Clock fixes

Added highlight and fixed input issues.

Changed paths:
    engines/nancy/enginedata.cpp
    engines/nancy/enginedata.h
    engines/nancy/state/scene.cpp
    engines/nancy/ui/animatedbutton.cpp
    engines/nancy/ui/animatedbutton.h
    engines/nancy/ui/clock.cpp


diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index 70000e708e6..7afb3ca34fa 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -51,9 +51,10 @@ BSUM::BSUM(Common::SeekableReadStream *chunkStream) {
 	s.skip(4, kGameTypeNancy3);
 
 	s.skip(8, kGameTypeVampire, kGameTypeVampire);
-	readRect(s, mapButtonHotspot, kGameTypeVampire, kGameTypeVampire);
-	readRect(s, clockHotspot, kGameTypeNancy2);
-	s.skip(0x10);
+	readRect(s, extraButtonHotspot, kGameTypeVampire, kGameTypeVampire);
+	readRect(s, extraButtonHotspot, kGameTypeNancy2);
+	readRect(s, extraButtonHighlightDest, kGameTypeNancy1);
+	s.skip(0x10, kGameTypeVampire, kGameTypeVampire);
 	readRect(s, textboxScreenPosition);
 	readRect(s, inventoryBoxScreenPosition);
 	readRect(s, menuButtonSrc);
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index c1bfb1c4fbc..1394ee1836c 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -39,8 +39,8 @@ struct BSUM {
 	uint16 startTimeMinutes;
 
 	// UI
-	Common::Rect mapButtonHotspot;
-	Common::Rect clockHotspot;
+	Common::Rect extraButtonHotspot;	// Extra button is map in tvd, clock in nancy2 and up
+	Common::Rect extraButtonHighlightDest;
 	Common::Rect textboxScreenPosition;
 	Common::Rect inventoryBoxScreenPosition;
 	Common::Rect menuButtonSrc;
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index 10ef1e63b06..18d09a7729d 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -832,7 +832,7 @@ void Scene::initStaticData() {
 	assert(bsum);
 	
 	if (g_nancy->getGameType() == kGameTypeVampire) {
-		_mapHotspot = bsum->mapButtonHotspot;
+		_mapHotspot = bsum->extraButtonHotspot;
 	} else if (g_nancy->_mapData) {
 		_mapHotspot = g_nancy->_mapData->buttonDest;
 	}
diff --git a/engines/nancy/ui/animatedbutton.cpp b/engines/nancy/ui/animatedbutton.cpp
index b8f1453012e..2b395e14b96 100644
--- a/engines/nancy/ui/animatedbutton.cpp
+++ b/engines/nancy/ui/animatedbutton.cpp
@@ -72,9 +72,14 @@ void AnimatedButton::handleInput(NancyInput &input) {
 			g_nancy->_cursorManager->setCursorType(g_nancy->getGameType() == kGameTypeVampire ? CursorManager::kHotspot : CursorManager::kHotspotArrow);
 		}
 
+		if (isPlaying()) {
+			return;
+		}
+
 		if (!_highlightSrcRect.isEmpty() && !isVisible()) {
 			_drawSurface.create(g_nancy->_graphicsManager->_object0, _highlightSrcRect);
-			moveTo(_hotspot);
+			moveTo(_highlightDestRect);
+			setVisible(true);
 		}
 
 		if (input.input & NancyInput::kLeftMouseButtonUp) {
@@ -87,7 +92,12 @@ void AnimatedButton::handleInput(NancyInput &input) {
 			}
 		}
 
-		input.eatMouseInput();
+		// This breaks TowerPuzzle in nancy2, so we only enable it for TVD
+		if (g_nancy->getGameType() == kGameTypeVampire) {
+			input.eatMouseInput();
+		}
+	} else if (!_highlightSrcRect.isEmpty() && isVisible() && !(isPlaying() || _isOpen)) {
+		setVisible(false);
 	}
 }
 
diff --git a/engines/nancy/ui/animatedbutton.h b/engines/nancy/ui/animatedbutton.h
index b5c7f7eb8a4..21b467072d2 100644
--- a/engines/nancy/ui/animatedbutton.h
+++ b/engines/nancy/ui/animatedbutton.h
@@ -50,6 +50,7 @@ protected:
 	Common::Array<Common::Rect> _srcRects;
 	Common::Array<Common::Rect> _destRects;
 	Common::Rect _highlightSrcRect;
+	Common::Rect _highlightDestRect;
 
 	uint32 _frameTime;
 	bool _alwaysHighlightCursor;
diff --git a/engines/nancy/ui/clock.cpp b/engines/nancy/ui/clock.cpp
index c44c8aee51d..71487abc59a 100644
--- a/engines/nancy/ui/clock.cpp
+++ b/engines/nancy/ui/clock.cpp
@@ -66,6 +66,7 @@ void Clock::init() {
 	_staticImage.setTransparent(g_nancy->getGameType() == kGameTypeVampire);
 
 	_animation.setTransparent(true);
+	_animation.setVisible(false);
 	if (g_nancy->getGameType() == kGameTypeVampire) {
 		GraphicsManager::loadSurfacePalette(_drawSurface, "OBJECT0");
 	}
@@ -98,9 +99,7 @@ void Clock::updateGraphics() {
 }
 
 void Clock::handleInput(NancyInput &input) {
-	if (!_animation.isPlaying()) {
-		_animation.handleInput(input);
-	}
+	_animation.handleInput(input);
 }
 
 void Clock::drawClockHands() {
@@ -125,9 +124,11 @@ void Clock::drawClockHands() {
 void Clock::ClockAnim::init() {
 	_srcRects = _owner->_clockData->animSrcs;
 	_destRects = _owner->_clockData->animDests;
+	_highlightSrcRect = g_nancy->_bootSummary->clockHighlightSrc;
+	_highlightDestRect = g_nancy->_bootSummary->extraButtonHighlightDest;
 	
 	if (_destRects.size()) {
-		moveTo(g_nancy->_bootSummary->clockHotspot);
+		moveTo(g_nancy->_bootSummary->extraButtonHotspot);
 	} else {
 		moveTo(_owner->_clockData->screenPosition);
 	}


Commit: 6ba8e586a33bfb03e395d4e86a26d2f95f4d28ce
    https://github.com/scummvm/scummvm/commit/6ba8e586a33bfb03e395d4e86a26d2f95f4d28ce
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-04-17T20:27:28+03:00

Commit Message:
NANCY: Fix ShowInventoryItem

Fixed a data reading error in ShowInventoryItem that
would crash nancy2.

Changed paths:
    engines/nancy/action/overlay.cpp
    engines/nancy/action/recordtypes.cpp
    engines/nancy/commontypes.cpp
    engines/nancy/commontypes.h


diff --git a/engines/nancy/action/overlay.cpp b/engines/nancy/action/overlay.cpp
index 52d5714a175..64397d52a68 100644
--- a/engines/nancy/action/overlay.cpp
+++ b/engines/nancy/action/overlay.cpp
@@ -96,7 +96,7 @@ void Overlay::readData(Common::SeekableReadStream &stream) {
 
 	_bitmaps.resize(numViewportFrames);
 	for (auto &bm : _bitmaps) {
-		bm.readData(stream);
+		bm.readData(stream, ser.getVersion() >= kGameTypeNancy2);
 	}
 }
 
diff --git a/engines/nancy/action/recordtypes.cpp b/engines/nancy/action/recordtypes.cpp
index 40824c4da96..e62854877e9 100644
--- a/engines/nancy/action/recordtypes.cpp
+++ b/engines/nancy/action/recordtypes.cpp
@@ -496,9 +496,8 @@ void ShowInventoryItem::readData(Common::SeekableReadStream &stream) {
 
 	uint16 numFrames = stream.readUint16LE();
 
-	_bitmaps.reserve(numFrames);
+	_bitmaps.resize(numFrames);
 	for (uint i = 0; i < numFrames; ++i) {
-		_bitmaps.push_back(BitmapDescription());
 		_bitmaps[i].readData(stream);
 	}
 }
diff --git a/engines/nancy/commontypes.cpp b/engines/nancy/commontypes.cpp
index 9d492d2b77d..7893e4e313c 100644
--- a/engines/nancy/commontypes.cpp
+++ b/engines/nancy/commontypes.cpp
@@ -43,8 +43,8 @@ void HotspotDescription::readData(Common::SeekableReadStream &stream) {
 	readRect(stream, coords);
 }
 
-void BitmapDescription::readData(Common::SeekableReadStream &stream) {
-	if (g_nancy->getGameType() <= kGameTypeNancy1) {
+void BitmapDescription::readData(Common::SeekableReadStream &stream, bool frameIsLong) {
+	if (!frameIsLong) {
 		frameID = stream.readUint16LE();
 	} else {
 		frameID = stream.readUint32LE();
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index 8254ebc92ff..5aca4bb77ff 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -142,7 +142,7 @@ struct BitmapDescription {
 	Common::Rect src;
 	Common::Rect dest;
 
-	void readData(Common::SeekableReadStream &stream);
+	void readData(Common::SeekableReadStream &stream, bool frameIsLong = false);
 };
 
 // Describes 10 event flag changes to be executed when an action is triggered




More information about the Scummvm-git-logs mailing list