[Scummvm-git-logs] scummvm master -> 4b274641fb88d0873ef36a3dcc844461c68f5d46

fracturehill noreply at scummvm.org
Sun Feb 18 21:32:16 UTC 2024


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

Summary:
18eea6d464 NANCY: Add support for nancy9 RippedLetterPuzzle
f89967c979 NANCY: Implement NewPhone
4b274641fb DEVTOOLS: Fix typos in nancy.dat


Commit: 18eea6d464708fbe25ab7e62059c4ddae83a62c9
    https://github.com/scummvm/scummvm/commit/18eea6d464708fbe25ab7e62059c4ddae83a62c9
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-18T22:31:13+01:00

Commit Message:
NANCY: Add support for nancy9 RippedLetterPuzzle

In nancy9 this record got an upgrade allowing for an
extra solution, as well as duplicated elements.

Changed paths:
    engines/nancy/action/puzzle/rippedletterpuzzle.cpp
    engines/nancy/action/puzzle/rippedletterpuzzle.h
    engines/nancy/util.cpp


diff --git a/engines/nancy/action/puzzle/rippedletterpuzzle.cpp b/engines/nancy/action/puzzle/rippedletterpuzzle.cpp
index 1560ed31318..709079357a3 100644
--- a/engines/nancy/action/puzzle/rippedletterpuzzle.cpp
+++ b/engines/nancy/action/puzzle/rippedletterpuzzle.cpp
@@ -76,15 +76,18 @@ void RippedLetterPuzzle::readData(Common::SeekableReadStream &stream) {
 		height = stream.readByte();
 	}
 
+	// All the checks for whether width is greater than maxWidth are
+	// to account for nancy9 scene 2428, where the dimensions are 15x1
+
 	for (uint i = 0; i < height; ++i) {
 		readRectArray(stream, _srcRects, width, maxWidth);
 	}
-	stream.skip((maxHeight - height) * maxWidth * 16);
+	stream.skip((maxWidth >= width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * 16);
 
 	for (uint i = 0; i < height; ++i) {
 		readRectArray(stream, _destRects, width, maxWidth);
 	}
-	stream.skip((maxHeight - height) * maxWidth * 16);
+	stream.skip((maxWidth >= width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * 16);
 
 	readRect(stream, _rotateHotspot);
 	readRect(stream, _takeHotspot);
@@ -94,41 +97,79 @@ void RippedLetterPuzzle::readData(Common::SeekableReadStream &stream) {
 		_rotationType = (RotationType)stream.readUint16LE();
 	}
 
+	uint elemSize = g_nancy->getGameType() <= kGameTypeNancy8 ? 1 : 2;
+
 	_initOrder.resize(width * height);
 	for (uint i = 0; i < height; ++i) {
 		for (uint j = 0; j < width; ++j) {
-			_initOrder[i * width + j] = stream.readByte();
+			_initOrder[i * width + j] = (elemSize == 1 ? stream.readByte() : stream.readSint16LE());
 		}
-		stream.skip((maxWidth - width));
+		stream.skip(maxWidth > width ? (maxWidth - width) * elemSize : 0);
 	}
-	stream.skip((maxHeight - height) * maxWidth);
+	stream.skip((maxWidth > width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * elemSize);
 
 	_initRotations.resize(width * height);
 	for (uint i = 0; i < height; ++i) {
 		for (uint j = 0; j < width; ++j) {
-			_initRotations[i * width + j] = stream.readByte();
+			_initRotations[i * width + j] = (elemSize == 1 ? stream.readByte() : stream.readSint16LE());
+		}
+		stream.skip(maxWidth > width ? (maxWidth - width) * elemSize : 0);
+	}
+	stream.skip((maxWidth > width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * elemSize);
+
+	if (g_nancy->getGameType() >= kGameTypeNancy9) {
+		uint16 numDoubledElements = stream.readUint16LE();
+		_doubles.resize(numDoubledElements);
+		uint i = 0;
+		for (uint j = 0; j < 20; ++j) {
+			int16 id = stream.readSint16LE();
+			if (id == -1) {
+				++i;
+			} else {
+				_doubles[i].push_back(id);
+			}
 		}
-		stream.skip((maxWidth - width));
 	}
-	stream.skip((maxHeight - height) * maxWidth);
 
 	_solveOrder.resize(width * height);
 	for (uint i = 0; i < height; ++i) {
 		for (uint j = 0; j < width; ++j) {
-			_solveOrder[i * width + j] = stream.readByte();
+			_solveOrder[i * width + j] = (elemSize == 1 ? stream.readByte() : stream.readSint16LE());
 		}
-		stream.skip((maxWidth - width));
+		stream.skip(maxWidth > width ? (maxWidth - width) * elemSize : 0);
 	}
-	stream.skip((maxHeight - height) * maxWidth);
+	stream.skip((maxWidth > width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * elemSize);
 
 	_solveRotations.resize(width * height);
 	for (uint i = 0; i < height; ++i) {
 		for (uint j = 0; j < width; ++j) {
-			_solveRotations[i * width + j] = stream.readByte();
+			_solveRotations[i * width + j] = (elemSize == 1 ? stream.readByte() : stream.readSint16LE());
+		}
+		stream.skip(maxWidth > width ? (maxWidth - width) * elemSize : 0);
+	}
+	stream.skip((maxWidth > width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * elemSize);
+
+	if (g_nancy->getGameType() >= kGameTypeNancy9) {
+		_useAltSolution = stream.readByte();
+
+		_solveOrderAlt.resize(width * height);
+		for (uint i = 0; i < height; ++i) {
+			for (uint j = 0; j < width; ++j) {
+				_solveOrderAlt[i * width + j] = (elemSize == 1 ? stream.readByte() : stream.readSint16LE());
+			}
+			stream.skip(maxWidth > width ? (maxWidth - width) * elemSize : 0);
 		}
-		stream.skip((maxWidth - width));
+		stream.skip((maxWidth > width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * elemSize);
+
+		_solveRotationsAlt.resize(width * height);
+		for (uint i = 0; i < height; ++i) {
+			for (uint j = 0; j < width; ++j) {
+				_solveRotationsAlt[i * width + j] = (elemSize == 1 ? stream.readByte() : stream.readSint16LE());
+			}
+			stream.skip(maxWidth > width ? (maxWidth - width) * elemSize : 0);
+		}
+		stream.skip((maxWidth > width ? (maxHeight - height) * maxWidth : maxWidth * maxHeight - width * height) * elemSize);
 	}
-	stream.skip((maxHeight - height) * maxWidth);
 
 	if (g_nancy->getGameType() >= kGameTypeNancy7) {
 		_useCustomPickUpTile = stream.readByte();
@@ -144,6 +185,10 @@ void RippedLetterPuzzle::readData(Common::SeekableReadStream &stream) {
 
 	_exitScene.readData(stream);
 	readRect(stream, _exitHotspot);
+
+	if (g_nancy->getGameType() >= kGameTypeNancy9) {
+		_customCursorID = stream.readSint16LE();
+	}
 }
 
 void RippedLetterPuzzle::execute() {
@@ -174,8 +219,14 @@ void RippedLetterPuzzle::execute() {
 		switch (_solveState) {
 		case kNotSolved :
 			for (uint i = 0; i < _puzzleState->order.size(); ++i) {
-				if (_puzzleState->order[i] != _solveOrder[i] || _puzzleState->rotations[i] != _solveRotations[i]) {
-					return;
+				if (_puzzleState->rotations[i] != _solveRotations[i] || !checkOrder(false)) {
+					if (_useAltSolution) {
+						if (!checkOrder(true)) {
+							return;
+						}
+					} else {
+						return;
+					}
 				}
 			}
 
@@ -199,6 +250,10 @@ void RippedLetterPuzzle::execute() {
 			_exitScene.execute();
 			break;
 		case kWaitForSound:
+			if (_solveExitScene._sceneChange.sceneID == NancySceneState.getSceneInfo().sceneID) {
+				// nancy9 scene 2484 is auto-solved for you, but has a valid scene change back to itself
+				return;
+			}
 			_solveExitScene.execute();
 			_puzzleState->playerHasTriedPuzzle = false;
 			break;
@@ -212,7 +267,7 @@ void RippedLetterPuzzle::execute() {
 }
 
 void RippedLetterPuzzle::handleInput(NancyInput &input) {
-	if (_state != kRun && _solveState != kNotSolved) {
+	if (_state == kBegin) {
 		return;
 	}
 
@@ -325,7 +380,7 @@ void RippedLetterPuzzle::handleInput(NancyInput &input) {
 	if (_pickedUpPieceID == -1) {
 		// No piece picked up, check the exit hotspot
 		if (NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
-			g_nancy->_cursor->setCursorType(g_nancy->_cursor->_puzzleExitCursor);
+			g_nancy->_cursor->setCursorType(_customCursorID != -1 ? (CursorManager::CursorType)_customCursorID : g_nancy->_cursor->_puzzleExitCursor);
 
 			if (input.input & NancyInput::kLeftMouseButtonUp) {
 				// Player has clicked, exit
@@ -351,5 +406,50 @@ void RippedLetterPuzzle::drawPiece(const uint pos, const byte rotation, const in
 	GraphicsManager::rotateBlit(srcSurf, destSurf, rotation);
 }
 
+bool RippedLetterPuzzle::checkOrder(bool useAlt) {
+	auto &current = _puzzleState->order;
+	auto &correct = useAlt ? _solveOrderAlt : _solveOrder;
+
+	if (!_doubles.size()) {
+		return current == correct;
+	}
+
+	for (uint i = 0; i < current.size(); ++i) {
+		bool foundCorrect = false;
+		bool isDoubled = false;
+		for (auto &d : _doubles) {
+			for (byte e : d) {
+				if (current[i] == e) {
+					isDoubled = true;
+					break;
+				}
+			}
+
+			if (isDoubled) {
+				for (byte e : d) {
+					if (correct[i] == e) {
+						foundCorrect = true;
+						break;
+					}
+				}
+
+				if (!foundCorrect) {
+					return false;
+				}
+
+				break;
+			}
+		}
+
+		if (!isDoubled) {
+			if (current[i] != correct[i]) {
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
 } // End of namespace Action
 } // End of namespace Nancy
diff --git a/engines/nancy/action/puzzle/rippedletterpuzzle.h b/engines/nancy/action/puzzle/rippedletterpuzzle.h
index 09fe7c942a5..4ea8223d8da 100644
--- a/engines/nancy/action/puzzle/rippedletterpuzzle.h
+++ b/engines/nancy/action/puzzle/rippedletterpuzzle.h
@@ -59,6 +59,10 @@ public:
 	Common::Array<byte> _initRotations;
 	Common::Array<int8> _solveOrder;
 	Common::Array<byte> _solveRotations;
+	Common::Array<int8> _solveOrderAlt;
+	Common::Array<byte> _solveRotationsAlt;
+	Common::Array<Common::Array<byte>> _doubles;
+	bool _useAltSolution = false;
 
 	bool _useCustomPickUpTile = false;
 	Common::Rect _customPickUpTileSrc;
@@ -73,6 +77,8 @@ public:
 	SceneChangeWithFlag _exitScene;
 	Common::Rect _exitHotspot;
 
+	int16 _customCursorID = -1;
+
 	Misc::MouseFollowObject _pickedUpPiece;
 	int8 _pickedUpPieceID = -1;
 	byte _pickedUpPieceRot = 0;
@@ -86,6 +92,7 @@ protected:
 	bool isViewportRelative() const override { return true; }
 
 	void drawPiece(const uint pos, const byte rotation, const int pieceID = -1);
+	bool checkOrder(bool useAlt);
 };
 
 } // End of namespace Action
diff --git a/engines/nancy/util.cpp b/engines/nancy/util.cpp
index 819f41d3ab4..78d22d2b8ef 100644
--- a/engines/nancy/util.cpp
+++ b/engines/nancy/util.cpp
@@ -65,7 +65,7 @@ void readRectArray(Common::SeekableReadStream &stream, Common::Array<Common::Rec
 		totalNum = num;
 	}
 
-	stream.skip((totalNum - num) * 16);
+	stream.skip(totalNum > num ? (totalNum - num) * 16 : 0);
 }
 
 void readRectArray(Common::Serializer &stream, Common::Array<Common::Rect> &inArray, uint num, uint totalNum, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
@@ -91,7 +91,7 @@ void readRectArray(Common::Serializer &stream, Common::Array<Common::Rect> &inAr
 			totalNum = num;
 		}
 
-		stream.skip((totalNum - num) * 16);
+		stream.skip(totalNum > num ? (totalNum - num) * 16 : 0);
 	}
 }
 
@@ -136,7 +136,7 @@ void readRectArray16(Common::SeekableReadStream &stream, Common::Array<Common::R
 		totalNum = num;
 	}
 
-	stream.skip((totalNum - num) * 8);
+	stream.skip(totalNum > num ? (totalNum - num) * 8 : 0);
 }
 
 void readRectArray16(Common::Serializer &stream, Common::Array<Common::Rect> &inArray, uint num, uint totalNum, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
@@ -162,7 +162,7 @@ void readRectArray16(Common::Serializer &stream, Common::Array<Common::Rect> &in
 			totalNum = num;
 		}
 
-		stream.skip((totalNum - num) * 8);
+		stream.skip(totalNum > num ? (totalNum - num) * 8 : 0);
 	}
 }
 


Commit: f89967c979ec5d977a45926f01fa5267d06c3bdb
    https://github.com/scummvm/scummvm/commit/f89967c979ec5d977a45926f01fa5267d06c3bdb
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-18T22:31:13+01:00

Commit Message:
NANCY: Implement NewPhone

Added support for the new Telephone AR type, which
adds a cellphone display with a phone number directory,
a dial button, and conditional phone numbers.

Changed paths:
    engines/nancy/action/arfactory.cpp
    engines/nancy/action/puzzle/telephone.cpp
    engines/nancy/action/puzzle/telephone.h
    engines/nancy/resource.cpp


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 6be4f83cd8f..600a419e30f 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -253,7 +253,7 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 	case 115:
 		return new LeverPuzzle();
 	case 116:
-		return new Telephone();
+		return new Telephone(false);
 	case 117:
 		return new SliderPuzzle();
 	case 118:
@@ -360,6 +360,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 		return new OrderingPuzzle(OrderingPuzzle::kKeypadTerse);
 	case 225:
 		return new SpigotPuzzle();
+	case 230:
+		return new Telephone(true);
 	default:
 		return nullptr;
 	}
diff --git a/engines/nancy/action/puzzle/telephone.cpp b/engines/nancy/action/puzzle/telephone.cpp
index 0e4d05c9660..57e1a7bbd94 100644
--- a/engines/nancy/action/puzzle/telephone.cpp
+++ b/engines/nancy/action/puzzle/telephone.cpp
@@ -25,6 +25,7 @@
 #include "engines/nancy/sound.h"
 #include "engines/nancy/input.h"
 #include "engines/nancy/util.h"
+#include "engines/nancy/font.h"
 
 #include "engines/nancy/action/puzzle/telephone.h"
 
@@ -34,41 +35,86 @@ namespace Nancy {
 namespace Action {
 
 void Telephone::init() {
-	_drawSurface.create(_screenPosition.width(), _screenPosition.height(), g_nancy->_graphics->getInputPixelFormat());
+	Common::Rect screenBounds = NancySceneState.getViewport().getBounds();
+	_drawSurface.create(screenBounds.width(), screenBounds.height(), g_nancy->_graphics->getInputPixelFormat());
 	_drawSurface.clear(g_nancy->_graphics->getTransColor());
-
 	setTransparent(true);
+	setVisible(true);
+	moveTo(screenBounds);
 
 	g_nancy->_resource->loadImage(_imageName, _image);
+	g_nancy->_resource->loadImage(_displayAnimName, _animImage);
+
+	if (_isNewPhone) {
+		_font = g_nancy->_graphics->getFont(_displayFont);
+	}
 }
 
 void Telephone::readData(Common::SeekableReadStream &stream) {
 	readFilename(stream, _imageName);
 
-	readRectArray(stream, _srcRects, 12);
-	readRectArray(stream, _destRects, 12);
+	uint16 numButtons = 12;
+	uint16 maxNumButtons = _isNewPhone ? 20 : 12;
+
+	if (_isNewPhone) {
+		_hasDisplay = stream.readByte();
+		_displayFont = stream.readUint16LE();
+		readFilename(stream, _displayAnimName);
+		_displayAnimFrameTime = stream.readUint32LE();
+		uint16 numFrames = stream.readUint16LE();
+		readRectArray(stream, _displaySrcs, numFrames, 10);
+		readRect(stream, _displayDest);
+		_dialAutomatically = stream.readByte();
+
+		numButtons = stream.readUint16LE();
+	}
+
+	readRectArray(stream, _srcRects, numButtons, maxNumButtons);
+	readRectArray(stream, _destRects, numButtons, maxNumButtons);
 
-	_screenPosition = _destRects[0];
-	for (uint i = 0; i < 12; ++i) {
-		_screenPosition.extend(_destRects[i]);
+	if (_isNewPhone) {
+		readRect(stream, _dirHighlightSrc);
+		readRect(stream, _dialHighlightSrc);
+		
+		_upDirButtonID = stream.readUint16LE();
+		_downDirButtonID = stream.readUint16LE();
+		_dialButtonID = stream.readUint16LE();
+		_dirButtonID = stream.readUint16LE();
+
+		readRect(stream, _displayDialingSrc);
 	}
 
-	_genericDialogueSound.readNormal(stream);
-	_genericButtonSound.readNormal(stream);
-	_ringSound.readNormal(stream);
-	_dialToneSound.readNormal(stream);
-	_dialAgainSound.readNormal(stream);
-	_hangUpSound.readNormal(stream);
+	if (!_isNewPhone) {
+		_genericDialogueSound.readNormal(stream);
+		_genericButtonSound.readNormal(stream);
+		_ringSound.readNormal(stream);
+		_dialToneSound.readNormal(stream);
+		_dialAgainSound.readNormal(stream);
+		_hangUpSound.readNormal(stream);
+	} else {
+		_ringSound.readNormal(stream);
+		_dialToneSound.readNormal(stream);
+		_preCallSound.readNormal(stream);
+		_hangUpSound.readNormal(stream);
+		_genericButtonSound.readNormal(stream);
+	}
 
-	readFilenameArray(stream, _buttonSoundNames, 12);
+	readFilenameArray(stream, _buttonSoundNames, numButtons);
+	stream.skip(33 * (maxNumButtons - numButtons));
 
 	char textBuf[200];
-	stream.read(textBuf, 200);
-	textBuf[199] = '\0';
-	_addressBookString = textBuf;
+	if (!_isNewPhone) {
+		stream.read(textBuf, 200);
+		textBuf[199] = '\0';
+		_addressBookString = textBuf;
+	} else {
+		_dialAgainSound.readNormal(stream);
+	}
+	
 	stream.read(textBuf, 200);
 	textBuf[199] = '\0';
 	_dialAgainString = textBuf;
+	
 	_reloadScene.readData(stream);
 	stream.skip(1);
 	_exitScene.readData(stream);
@@ -81,15 +127,24 @@ void Telephone::readData(Common::SeekableReadStream &stream) {
 	for (uint i = 0; i < numCalls; ++i) {
 		PhoneCall &call = _calls[i];
 
+		if (_isNewPhone) {
+			call.eventFlagCondition = stream.readSint16LE();
+		}
+
 		call.phoneNumber.resize(11);
 		for (uint j = 0; j < 11; ++j) {
 			call.phoneNumber[j] = stream.readByte();
 		}
 
-		readFilename(stream, call.soundName);
-		stream.read(textBuf, 200);
-		textBuf[199] = '\0';
-		call.text = textBuf;
+		if (!_isNewPhone) {
+			readFilename(stream, call.soundName);
+			stream.read(textBuf, 200);
+			textBuf[199] = '\0';
+			call.text = textBuf;
+		} else {
+			readRect(stream, call.displaySrc);
+		}
+		
 		call.sceneChange.readData(stream);
 		stream.skip(1);
 	}
@@ -109,11 +164,36 @@ void Telephone::execute() {
 	case kRun:
 		switch (_callState) {
 		case kWaiting:
+			if (_isNewPhone && !_animIsStopped) {
+				if (g_nancy->getTotalPlayTime() > _displayAnimEnd) {
+					if (_displayAnimEnd == 0) {
+						_displayAnimEnd = g_nancy->getTotalPlayTime() + _displayAnimFrameTime;
+					} else {
+						_displayAnimEnd += _displayAnimFrameTime;
+					}
+
+					_drawSurface.blitFrom(_animImage, _displaySrcs[_displayAnimFrame], _displayDest);
+					_needsRedraw = true;
+					++_displayAnimFrame;
+
+					if (_displayAnimFrame >= _displaySrcs.size()) {
+						_displayAnimFrame = 0;
+					}
+				}
+			}
+
 			if (_checkNumbers) {
 				// Pressed a new button, check all numbers for match
 				// We do this before going to the ringing state to support nancy4's voice mail system,
 				// where call numbers can be 1 digit long
 				for (uint i = 0; i < _calls.size(); ++i) {
+					// Do not evaluate phone calls whose condition isn't met
+					if (_calls[i].eventFlagCondition != kEvNoEvent) {
+						if (NancySceneState.getEventFlag(_calls[i].eventFlagCondition, g_nancy->_false)) {
+							continue;
+						}
+					}
+
 					bool invalid = false;
 
 					for (uint j = 0; j < _calledNumber.size(); ++j) {
@@ -157,16 +237,20 @@ void Telephone::execute() {
 				}
 
 				if (shouldRing) {
-					if (_ringSound.name == "NO SOUND") {
-						// Will not ring, so skip text
-						_callState = kRinging;
-					} else {
-						NancySceneState.getTextbox().clear();
-						NancySceneState.getTextbox().addTextLine(g_nancy->getStaticData().ringingText);
+					if (_ringSound.name != "NO SOUND") {
+						if (_hasDisplay) {
+							_drawSurface.blitFrom(_image, _displayDialingSrc, _displayDest);
+							_needsRedraw = true;
+						} else {
+							NancySceneState.getTextbox().clear();
+							NancySceneState.getTextbox().addTextLine(g_nancy->getStaticData().ringingText);
+						}
+						
 						g_nancy->_sound->loadSound(_ringSound);
 						g_nancy->_sound->playSound(_ringSound);
-						_callState = kRinging;
 					}
+
+					_callState = kRinging;
 				}
 
 				_checkNumbers = false;
@@ -176,7 +260,16 @@ void Telephone::execute() {
 		case kButtonPress:
 			if (!g_nancy->_sound->isSoundPlaying(_genericButtonSound)) {
 				g_nancy->_sound->stopSound(_genericButtonSound);
-				undrawButton(_buttonLastPushed);
+				_drawSurface.fillRect(_destRects[_buttonLastPushed], g_nancy->_graphics->getTransColor());
+				_needsRedraw = true;
+
+				if (_isShowingDirectory) {
+					_drawSurface.blitFrom(_image, _dirHighlightSrc, _destRects[_dirButtonID]);
+					_drawSurface.blitFrom(_image, _calls[_displayedDirectory].displaySrc, _displayDest);
+				} else if (_dirButtonID != -1) {
+					_drawSurface.fillRect(_destRects[_dirButtonID], _drawSurface.getTransparentColor());
+				}
+
 				_buttonLastPushed = -1;
 				_callState = kWaiting;
 			}
@@ -188,18 +281,39 @@ void Telephone::execute() {
 
 				if (_selected != -1) {
 					// Called a valid number
-					NancySceneState.getTextbox().clear();
-					NancySceneState.getTextbox().addTextLine(_calls[_selected].text);
-					
-					_genericDialogueSound.name = _calls[_selected].soundName;
-					g_nancy->_sound->loadSound(_genericDialogueSound);
-					g_nancy->_sound->playSound(_genericDialogueSound);
-					_callState = kCall;
+
+					if (_preCallSound.name == "NO SOUND") {
+						// Old phone, go directly to call
+						NancySceneState.getTextbox().clear();
+						NancySceneState.getTextbox().addTextLine(_calls[_selected].text);
+						
+						_genericDialogueSound.name = _calls[_selected].soundName;
+						g_nancy->_sound->loadSound(_genericDialogueSound);
+						g_nancy->_sound->playSound(_genericDialogueSound);
+						_callState = kCall;
+					} else {
+						// New phone, play a short sound of phone being picked up
+						g_nancy->_sound->loadSound(_preCallSound);
+						g_nancy->_sound->playSound(_preCallSound);
+						_callState = kPreCall;
+					}
 				} else {
 					// Called an invalid number
 					NancySceneState.getTextbox().clear();
 					NancySceneState.getTextbox().addTextLine(_dialAgainString);
 
+					if (_hasDisplay) {
+						_drawSurface.fillRect(_displayDest, _drawSurface.getTransparentColor());
+						_needsRedraw = true;
+					}
+
+					if (_dialButtonID != -1) {
+						_drawSurface.fillRect(_destRects[_dialButtonID], _drawSurface.getTransparentColor());
+						_needsRedraw = true;
+					}
+
+					_calledNumber.clear();
+
 					g_nancy->_sound->loadSound(_dialAgainSound);
 					g_nancy->_sound->playSound(_dialAgainSound);
 					_callState = kBadNumber;
@@ -208,6 +322,22 @@ void Telephone::execute() {
 				return;
 			}
 
+			break;
+		case kPreCall:
+			if (!g_nancy->_sound->isSoundPlaying(_preCallSound)) {
+				g_nancy->_sound->stopSound(_preCallSound);
+
+				if (!_calls[_selected].text.empty()) {
+					NancySceneState.getTextbox().clear();
+					NancySceneState.getTextbox().addTextLine(_calls[_selected].text);
+				}
+				
+				_genericDialogueSound.name = _calls[_selected].soundName;
+				g_nancy->_sound->loadSound(_genericDialogueSound);
+				g_nancy->_sound->playSound(_genericDialogueSound);
+				_callState = kCall;
+			}
+
 			break;
 		case kBadNumber:
 			if (!g_nancy->_sound->isSoundPlaying(_dialAgainSound)) {
@@ -260,12 +390,12 @@ void Telephone::execute() {
 			break;
 		}
 
-				g_nancy->_sound->stopSound(_hangUpSound);
-				g_nancy->_sound->stopSound(_genericDialogueSound);
-				g_nancy->_sound->stopSound(_genericButtonSound);
-				g_nancy->_sound->stopSound(_dialAgainSound);
-				g_nancy->_sound->stopSound(_ringSound);
-				g_nancy->_sound->stopSound(_dialToneSound);
+		g_nancy->_sound->stopSound(_hangUpSound);
+		g_nancy->_sound->stopSound(_genericDialogueSound);
+		g_nancy->_sound->stopSound(_genericButtonSound);
+		g_nancy->_sound->stopSound(_dialAgainSound);
+		g_nancy->_sound->stopSound(_ringSound);
+		g_nancy->_sound->stopSound(_dialToneSound);
 
 		finishExecution();
 	}
@@ -274,7 +404,12 @@ void Telephone::execute() {
 void Telephone::handleInput(NancyInput &input) {
 	int buttonNr = -1;
 	// Cursor gets changed regardless of state
-	for (uint i = 0; i < 12; ++i) {
+	for (int i = 0; i < (int)_destRects.size(); ++i) {
+		// Dial button is an exception
+		if (i == _dialButtonID && !_calledNumber.size() && !_isShowingDirectory) {
+			continue;
+		}
+
 		if (NancySceneState.getViewport().convertViewportToScreen(_destRects[i]).contains(input.mousePos)) {
 			g_nancy->_cursor->setCursorType(CursorManager::kHotspot);
 			buttonNr = i;
@@ -309,34 +444,128 @@ void Telephone::handleInput(NancyInput &input) {
 				g_nancy->_sound->stopSound(_dialToneSound);
 			}
 
-			_calledNumber.push_back(buttonNr);
+			// Handle non-digit numbers
+			bool directorySwitch = false;
+			bool changeDirectoryEntry = false;
+			int dirEntryDelta = 1;
+			if (_dialButtonID != -1 && buttonNr == _dialButtonID) {
+				_calledNumber = _calls[_displayedDirectory].phoneNumber;
+				while (_calledNumber.back() == 10) {
+					_calledNumber.pop_back();
+				}
+
+				_checkNumbers = true;
+
+				// Dial button doesn't make sound, and doesn't get pressed down
+				_drawSurface.blitFrom(_image, _dialHighlightSrc, _destRects[_dialButtonID]);
+
+				if (_dirButtonID != -1) {
+					_drawSurface.fillRect(_destRects[_dirButtonID], _drawSurface.getTransparentColor());
+				}
+
+				return;
+			} else if (_upDirButtonID != -1 && buttonNr == _upDirButtonID) {
+				if (!_isShowingDirectory) {
+					directorySwitch = true;
+				} else {
+					++_displayedDirectory;
+					changeDirectoryEntry = true;
+				}
+			} else if (_downDirButtonID != -1 && buttonNr == _downDirButtonID) {
+				if (!_isShowingDirectory) {
+					directorySwitch = true;
+				} else {
+					--_displayedDirectory;
+					dirEntryDelta = -1;
+					changeDirectoryEntry = true;
+				}
+			} else if (_dirButtonID != -1 && buttonNr == _dirButtonID) {
+				if (!_isShowingDirectory) {
+					directorySwitch = true;
+				}
+			} else {
+				if (_isShowingDirectory || !_calledNumber.size()) {
+					_isShowingDirectory = false;
+					_displayedDirectory = 0;
+					_drawSurface.fillRect(_displayDest, _drawSurface.getTransparentColor());
+				}
+
+				_calledNumber.push_back(buttonNr);
+				_checkNumbers = _dialAutomatically;
+				_animIsStopped = true;
+
+				if (_calledNumber.size() > 11) {
+					_calledNumber.clear();
+					
+					if (_hasDisplay) {
+						_drawSurface.fillRect(_displayDest, _drawSurface.getTransparentColor());
+					} else if (_isNewPhone) {
+						NancySceneState.getTextbox().clear();
+					}
+
+					_checkNumbers = false;
+				}
+
+				if (_isNewPhone && _calledNumber.size()) {
+					Common::String numberString;
+					for (uint j = 0; j < _calledNumber.size(); ++j) {
+						numberString += '0' + _calledNumber[j];
+					}
+
+					if (_hasDisplay) {
+						_font->drawString(&_drawSurface, numberString, _displayDest.left + 19, _displayDest.top + 21 - _font->getFontHeight(),
+							_displayDest.width() - 20, 0);
+					} else {
+						NancySceneState.getTextbox().clear();
+						NancySceneState.getTextbox().addTextLine(numberString);
+					}
+				}
+			}
+
+			if (directorySwitch) {
+				// Handle switch to directory mode
+				_isShowingDirectory = true;
+				changeDirectoryEntry = true;
+				_calledNumber.clear();
+			}
+
+			if (changeDirectoryEntry) {
+				int start = _displayedDirectory;
+
+				do {
+					if (_displayedDirectory >= (int)_calls.size()) {
+						_displayedDirectory = 0;
+					} else if (_displayedDirectory < 0) {
+						_displayedDirectory = _calls.size() - 1;
+					}
+
+					if (_calls[_displayedDirectory].eventFlagCondition == kEvNoEvent) {
+						break;
+					}
+
+					if (NancySceneState.getEventFlag(_calls[_displayedDirectory].eventFlagCondition, g_nancy->_true)) {
+						break;
+					}
+
+					_displayedDirectory += dirEntryDelta;
+				} while (_displayedDirectory != start);
+			}
+			
 			_genericButtonSound.name = _buttonSoundNames[buttonNr];
 			g_nancy->_sound->loadSound(_genericButtonSound);
 			g_nancy->_sound->playSound(_genericButtonSound);
 
-			drawButton(buttonNr);
+			_drawSurface.blitFrom(_image, _srcRects[buttonNr], _destRects[buttonNr]);
+			_needsRedraw = true;
+
+			_displayAnimEnd = 0;
+			_displayAnimFrame = 0;
 
 			_buttonLastPushed = buttonNr;
-			_checkNumbers = true;
 			_callState = kButtonPress;
 		}
 	}
 }
 
-void Telephone::drawButton(uint id) {
-	Common::Point destPoint(_destRects[id].left - _screenPosition.left, _destRects[id].top - _screenPosition.top);
-	_drawSurface.blitFrom(_image, _srcRects[id], destPoint);
-
-	_needsRedraw = true;
-}
-
-void Telephone::undrawButton(uint id) {
-	Common::Rect bounds = _destRects[id];
-	bounds.translate(-_screenPosition.left, -_screenPosition.top);
-
-	_drawSurface.fillRect(bounds, g_nancy->_graphics->getTransColor());
-	_needsRedraw = true;
-}
-
 } // End of namespace Action
 } // End of namespace Nancy
diff --git a/engines/nancy/action/puzzle/telephone.h b/engines/nancy/action/puzzle/telephone.h
index e36f007536a..0596727496f 100644
--- a/engines/nancy/action/puzzle/telephone.h
+++ b/engines/nancy/action/puzzle/telephone.h
@@ -25,6 +25,9 @@
 #include "engines/nancy/action/actionrecord.h"
 
 namespace Nancy {
+
+class Font;
+
 namespace Action {
 
 class Telephone : public RenderActionRecord {
@@ -34,16 +37,23 @@ public:
 		Common::String soundName;
 		Common::String text;
 		SceneChangeWithFlag sceneChange;
+
+		// NewPhone members
+		int16 eventFlagCondition = -1;
+		Common::Rect displaySrc;
 	};
 
-	enum CallState { kWaiting, kButtonPress, kRinging, kBadNumber, kCall, kHangUp };
+	enum CallState { kWaiting, kButtonPress, kRinging, kBadNumber, kPreCall, kCall, kHangUp };
 
-	Telephone() :
+	Telephone(bool isNewPhone) :
 		RenderActionRecord(7),
 		_callState(kWaiting),
 		_buttonLastPushed(-1),
 		_selected(-1),
-		_checkNumbers(false) {}
+		_checkNumbers(false),
+		_font(nullptr),
+		_animIsStopped(false),
+		_isNewPhone(isNewPhone) {}
 	virtual ~Telephone() {}
 
 	void init() override;
@@ -52,6 +62,10 @@ public:
 	void execute() override;
 	void handleInput(NancyInput &input) override;
 
+protected:
+	Common::String getRecordTypeName() const override { return _isNewPhone ? "NewPhone" : "Telephone"; }
+	bool isViewportRelative() const override { return true; }
+
 	Common::Path _imageName;
 	Common::Array<Common::Rect> _srcRects;
 	Common::Array<Common::Rect> _destRects;
@@ -69,19 +83,45 @@ public:
 	Common::Rect _exitHotspot;
 	Common::Array<PhoneCall> _calls;
 
+	// NewPhone properties
+	bool _hasDisplay = false;
+	uint16 _displayFont = 0;
+	Common::Path _displayAnimName;
+	uint32 _displayAnimFrameTime = 0;
+	Common::Array<Common::Rect> _displaySrcs;
+	Common::Rect _displayDest;
+
+	bool _dialAutomatically = true;
+
+	Common::Rect _dirHighlightSrc;
+	Common::Rect _dialHighlightSrc;
+
+	int16 _upDirButtonID = -1;
+	int16 _downDirButtonID = -1;
+	int16 _dialButtonID = -1;
+	int16 _dirButtonID = -1;
+
+	Common::Rect _displayDialingSrc;
+
+	SoundDescription _preCallSound;
+
 	Common::Array<byte> _calledNumber;
 	Graphics::ManagedSurface _image;
+	Graphics::ManagedSurface _animImage;
 	CallState _callState;
 	int _buttonLastPushed;
 	int _selected;
 	bool _checkNumbers;
+	bool _animIsStopped;
 
-protected:
-	Common::String getRecordTypeName() const override { return "Telephone"; }
-	bool isViewportRelative() const override { return true; }
+	uint32 _displayAnimEnd = 0;
+	uint16 _displayAnimFrame = 0;
+	int16 _displayedDirectory = 0;
+	bool _isShowingDirectory = false;
+
+	const Font *_font;
 
-	void drawButton(uint id);
-	void undrawButton(uint id);
+	bool _isNewPhone;
 };
 
 } // End of namespace Action
diff --git a/engines/nancy/resource.cpp b/engines/nancy/resource.cpp
index c549e0cd3aa..663eca3dde1 100644
--- a/engines/nancy/resource.cpp
+++ b/engines/nancy/resource.cpp
@@ -36,6 +36,10 @@ static char treePrefix[] = "_tree_";
 namespace Nancy {
 
 bool ResourceManager::loadImage(const Common::Path &name, Graphics::ManagedSurface &surf, const Common::String &treeName, Common::Rect *outSrc, Common::Rect *outDest) {
+	if (name.empty()) {
+		return false;
+	}
+
 	// Detect and load autotext surfaces
 	Common::String baseName(name.baseName());
 	if (baseName.hasPrefixIgnoreCase("USE_")) {


Commit: 4b274641fb88d0873ef36a3dcc844461c68f5d46
    https://github.com/scummvm/scummvm/commit/4b274641fb88d0873ef36a3dcc844461c68f5d46
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-18T22:31:13+01:00

Commit Message:
DEVTOOLS: Fix typos in nancy.dat

Changed paths:
    devtools/create_nancy/nancy4_data.h
    devtools/create_nancy/nancy5_data.h


diff --git a/devtools/create_nancy/nancy4_data.h b/devtools/create_nancy/nancy4_data.h
index 93986530f16..984a40cc1d0 100644
--- a/devtools/create_nancy/nancy4_data.h
+++ b/devtools/create_nancy/nancy4_data.h
@@ -30,7 +30,7 @@ const GameConstants _nancy4Constants ={
 	{	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,			// genericEventFlags
 		11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
 		21, 22, 23, 24, 25, 26, 27, 28, 29, 30 },
-	13,												// numCursorTypes
+	12,												// numCursorTypes
 	4000,											// logoEndAfter
 	32												// wonGameFlagID
 };
diff --git a/devtools/create_nancy/nancy5_data.h b/devtools/create_nancy/nancy5_data.h
index c62006c4910..5cdeaf2cb23 100644
--- a/devtools/create_nancy/nancy5_data.h
+++ b/devtools/create_nancy/nancy5_data.h
@@ -30,7 +30,7 @@ const GameConstants _nancy5Constants ={
 	{	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,			// genericEventFlags
 		11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
 		21, 22, 23, 24, 25, 26, 27, 28, 29, 30 },
-	13,												// numCursorTypes
+	12,												// numCursorTypes
 	4000,											// logoEndAfter
 	32												// wonGameFlagID
 };




More information about the Scummvm-git-logs mailing list