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

fracturehill noreply at scummvm.org
Sat Sep 9 09:51:35 UTC 2023


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

Summary:
c0b83b89e5 NANCY: Implement password puzzle in nancy4 and up
1134a02a18 NANCY: Overlay fixes
aede444424 NANCY: ConversationCel fixes
f53f88cdb7 NANCY: Correctly readRippedLetterPuzzle in nancy5
b918029f01 NANCY: Move PCAL chunk reading
b5efecf258 NANCY: Improve color text behavior


Commit: c0b83b89e5b9e637230fd0e593176a7520303303
    https://github.com/scummvm/scummvm/commit/c0b83b89e5b9e637230fd0e593176a7520303303
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-09T12:49:30+03:00

Commit Message:
NANCY: Implement password puzzle in nancy4 and up

Nancy4 added multiple answers and the option to only
have one answer field to PasswordPuzzle. Both are now
implemented.

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


diff --git a/engines/nancy/action/passwordpuzzle.cpp b/engines/nancy/action/passwordpuzzle.cpp
index 77d0f978843..99bcaef1f82 100644
--- a/engines/nancy/action/passwordpuzzle.cpp
+++ b/engines/nancy/action/passwordpuzzle.cpp
@@ -42,19 +42,41 @@ void PasswordPuzzle::init() {
 }
 
 void PasswordPuzzle::readData(Common::SeekableReadStream &stream) {
-	_fontID = stream.readUint16LE();
-	_cursorBlinkTime = stream.readUint16LE();
-	readRect(stream, _nameBounds);
-	readRect(stream, _passwordBounds);
-	readRect(stream, _screenPosition);
+	Common::Serializer s(&stream, nullptr);
+	s.setVersion(g_nancy->getGameType());
 
+	s.syncAsUint16LE(_fontID);
+	s.syncAsUint16LE(_cursorBlinkTime);
+	readRect(s, _nameBounds);
+	readRect(s, _passwordBounds);
+	readRect(s, _screenPosition);
+
+	uint numNames = 1;
+	uint numPasswords = 1;
 	char buf[20];
-	stream.read(buf, 20);
-	buf[19] = '\0';
-	_name = buf;
-	stream.read(buf, 20);
-	buf[19] = '\0';
-	_password = buf;
+
+	s.syncAsUint16LE(numNames);
+	_names.resize(numNames);
+	for (uint i = 0; i < numNames; ++i) {
+		stream.read(buf, 20);
+		buf[19] = '\0';
+		_names[i] = buf;
+
+		_maxNameLength = MAX(_maxNameLength, _names[i].size());
+	}
+	s.skip((5 - numNames) * 20);
+
+	s.syncAsUint16LE(numPasswords);
+	_passwords.resize(numPasswords);
+	for (uint i = 0; i < numPasswords; ++i) {
+		stream.read(buf, 20);
+		buf[19] = '\0';
+		_passwords[i] = buf;
+
+		_maxPasswordLength = MAX(_maxPasswordLength, _passwords[i].size());
+	}
+	s.skip((5 - numPasswords) * 20);
+
 	_solveExitScene.readData(stream);
 	_solveSound.readNormal(stream);
 	_failExitScene.readData(stream);
@@ -76,7 +98,7 @@ void PasswordPuzzle::execute() {
 		switch (_solveState) {
 		case kNotSolved: {
 			Common::String &activeField = _passwordFieldIsActive ? _playerPasswordInput : _playerNameInput;
-			Common::String &correctField = _passwordFieldIsActive ? _password : _name;
+			Common::Array<Common::String> &correctAnswers = _passwordFieldIsActive ? _passwords : _names;
 			Time currentTime = g_nancy->getTotalPlayTime();
 
 			if (_playerHasHitReturn) {
@@ -87,21 +109,31 @@ void PasswordPuzzle::execute() {
 					drawText();
 				}
 
-				if (activeField.equalsIgnoreCase(correctField)) {
-					if (!_passwordFieldIsActive) {
-						_passwordFieldIsActive = true;
-					} else {
+				bool solvedCurrentInput = false;
+				if (correctAnswers.size()) {
+					for (uint i = 0; i < correctAnswers.size(); ++i) {
+						if (activeField.equalsIgnoreCase(correctAnswers[i])) {
+							solvedCurrentInput = true;
+							break;
+						}
+					}
+				} else {
+					solvedCurrentInput = true;
+				}
+
+				if (solvedCurrentInput) {
+					if (_passwordFieldIsActive || _passwords.size() == 0) {
 						g_nancy->_sound->loadSound(_solveSound);
 						g_nancy->_sound->playSound(_solveSound);
 						_solveState = kSolved;
+					} else {
+						_passwordFieldIsActive = true;
 					}
 				} else {
 					g_nancy->_sound->loadSound(_failSound);
 					g_nancy->_sound->playSound(_failSound);
 					_solveState = kFailed;
 				}
-
-
 			} else if (currentTime >= _nextBlinkTime) {
 				_nextBlinkTime = currentTime + _cursorBlinkTime;
 
@@ -167,7 +199,7 @@ void PasswordPuzzle::handleInput(NancyInput &input) {
 	for (uint i = 0; i < input.otherKbdInput.size(); ++i) {
 		Common::KeyState &key = input.otherKbdInput[i];
 		Common::String &activeField = _passwordFieldIsActive ? _playerPasswordInput : _playerNameInput;
-		Common::String &correctField = _passwordFieldIsActive ? _password : _name;
+		uint &maxLength = _passwordFieldIsActive ? _maxPasswordLength : _maxNameLength;
 		if (key.keycode == Common::KEYCODE_BACKSPACE) {
 			if (activeField.size() && activeField.lastChar() == '-' ? activeField.size() > 1 : true) {
 				if (activeField.lastChar() == '-') {
@@ -182,13 +214,13 @@ void PasswordPuzzle::handleInput(NancyInput &input) {
 			_playerHasHitReturn = true;
 		} else if (Common::isAlnum(key.ascii) || Common::isSpace(key.ascii)) {
 			if (activeField.size() && activeField.lastChar() == '-') {
-				if (activeField.size() <= correctField.size() + 2) {
+				if (activeField.size() <= maxLength + 2) {
 					activeField.deleteLastChar();
 					activeField += key.ascii;
 					activeField += '-';
 				}
 			} else {
-				if (activeField.size() <= correctField.size() + 1) {
+				if (activeField.size() <= maxLength + 1) {
 					activeField += key.ascii;
 				}
 			}
diff --git a/engines/nancy/action/passwordpuzzle.h b/engines/nancy/action/passwordpuzzle.h
index 8f785070551..6e23f95b456 100644
--- a/engines/nancy/action/passwordpuzzle.h
+++ b/engines/nancy/action/passwordpuzzle.h
@@ -40,12 +40,12 @@ public:
 	void handleInput(NancyInput &input) override;
 
 	uint16 _fontID = 0;
-	Time _cursorBlinkTime;
+	uint16 _cursorBlinkTime;
 	Common::Rect _nameBounds;
 	Common::Rect _passwordBounds;
 	// _screenPosition 0x24
-	Common::String _name;
-	Common::String _password;
+	Common::Array<Common::String> _names;
+	Common::Array<Common::String> _passwords;
 	SceneChangeWithFlag _solveExitScene;
 	SoundDescription _solveSound;
 	SceneChangeWithFlag _failExitScene;
@@ -60,6 +60,9 @@ public:
 	bool _playerHasHitReturn = false;
 	SolveState _solveState = kNotSolved;
 
+	uint _maxNameLength = 0;
+	uint _maxPasswordLength = 0;
+
 protected:
 	Common::String getRecordTypeName() const override { return "PasswordPuzzle"; }
 	bool isViewportRelative() const override { return true; }


Commit: 1134a02a1822467f2758570720d3639ea853e9c3
    https://github.com/scummvm/scummvm/commit/1134a02a1822467f2758570720d3639ea853e9c3
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-09T12:49:30+03:00

Commit Message:
NANCY: Overlay fixes

Animated overlays in nancy3 and up now ignore their
scene changes and hotspots. This fixes the chandelier
in nancy3 and several conversations with Hotchkiss
in nancy4. This fix is NOT to be applied to earlier games,
as they used those fields even when the overlay is animated.

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


diff --git a/engines/nancy/action/overlay.cpp b/engines/nancy/action/overlay.cpp
index 169eca49305..b663ee96c82 100644
--- a/engines/nancy/action/overlay.cpp
+++ b/engines/nancy/action/overlay.cpp
@@ -134,7 +134,7 @@ void Overlay::execute() {
 							moveTo(_bitmaps[i].dest);
 							setVisible(true);
 
-							if (_enableHotspot == kPlayOverlayWithHotspot) {
+							if ((_overlayType == kPlayOverlayStatic || g_nancy->getGameType() <= kGameTypeNancy1) && _enableHotspot == kPlayOverlayWithHotspot) {
 								_hotspot = _screenPosition;
 								_hasHotspot = true;
 							}
@@ -206,10 +206,11 @@ void Overlay::execute() {
 		g_nancy->_sound->stopSound(_sound);
 
 		_flagsOnTrigger.execute();
-		if (_hasSceneChange == kPlayOverlaySceneChange) {
+		if ((_overlayType == kPlayOverlayStatic || g_nancy->getGameType() <= kGameTypeNancy1) && _hasSceneChange == kPlayOverlaySceneChange) {
 			NancySceneState.changeScene(_sceneChange);
-			finishExecution();
 		}
+		
+		finishExecution();
 
 		break;
 	}


Commit: aede44442420b932813d9153b88c27b41bc5b9a2
    https://github.com/scummvm/scummvm/commit/aede44442420b932813d9153b88c27b41bc5b9a2
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-09T12:49:30+03:00

Commit Message:
NANCY: ConversationCel fixes

Improved ConversationCel reading so it no longer
assumes there are only two cels drawn at a time (the engine
supports up to 4). Also fixed a gap between conversation
scenes where the character would become invisible for a
single frame.

Changed paths:
    engines/nancy/action/conversation.cpp
    engines/nancy/action/conversation.h


diff --git a/engines/nancy/action/conversation.cpp b/engines/nancy/action/conversation.cpp
index 1d5684d5d79..59fba80957d 100644
--- a/engines/nancy/action/conversation.cpp
+++ b/engines/nancy/action/conversation.cpp
@@ -561,23 +561,25 @@ private:
 };
 
 bool ConversationCelLoader::loadInner() {
-	for (uint i = _owner._curFrame; i < _owner._bodyCelNames.size(); ++i) {
-		if (!_owner._celCache.contains(_owner._bodyCelNames[i])) {
-			_owner.loadCel(_owner._bodyCelNames[i], _owner._bodyTreeName);
-			return false;
-		}
-
-		if (!_owner._celCache.contains(_owner._headCelNames[i])) {
-			_owner.loadCel(_owner._headCelNames[i], _owner._headTreeName);
-			return false;
+	for (uint i = _owner._curFrame; i < _owner._celNames[0].size(); ++i) {
+		for (uint j = 0; j < _owner._celRObjects.size(); ++j) {
+			if (!_owner._celCache.contains(_owner._celNames[j][i])) {
+				_owner.loadCel(_owner._celNames[j][i], _owner._treeNames[j]);
+				return false;
+			}
 		}
 	}
 
 	return true;
 }
 
+ConversationCel::~ConversationCel() {
+	// Make sure there isn't a single-frame gap between conversation scenes where
+	// the character is invisible
+	g_nancy->_graphicsManager->suppressNextDraw();
+}
+
 void ConversationCel::init() {
-	registerGraphics();
 	_curFrame = _firstFrame;
 	_nextFrameTime = g_nancy->getTotalPlayTime();
 	ConversationSound::init();
@@ -585,25 +587,41 @@ void ConversationCel::init() {
 	_loaderPtr.reset(new ConversationCelLoader(*this));
 	auto castedPtr = _loaderPtr.dynamicCast<DeferredLoader>();
 	g_nancy->addDeferredLoader(castedPtr);
+
+	for (uint i = 0; i < _treeNames.size(); ++i) {
+		if (_treeNames[i].size()) {
+			_celRObjects.push_back(RenderedCel());
+		} else break;
+	}
+
+	registerGraphics();
 }
 
 void ConversationCel::registerGraphics() {
-	RenderObject::registerGraphics();
-	_headRObj.registerGraphics();
+	for (uint i = 0; i < _celRObjects.size(); ++i) {
+		_celRObjects[i]._z = 9 + _drawingOrder[i];
+		_celRObjects[i].setVisible(true);
+		_celRObjects[i].setTransparent(true);
+		_celRObjects[i].registerGraphics();
+	}
+
+	RenderActionRecord::registerGraphics();
 }
 
 void ConversationCel::updateGraphics() {
 	uint32 currentTime = g_nancy->getTotalPlayTime();
 
 	if (_state == kRun && currentTime > _nextFrameTime && _curFrame <= _lastFrame) {
-		Cel &bodyCel = loadCel(_bodyCelNames[_curFrame], _bodyTreeName);
-		Cel &headCel = loadCel(_headCelNames[_curFrame], _headTreeName);
-
-		_drawSurface.create(bodyCel.surf, bodyCel.src);
-		moveTo(bodyCel.dest);
-
-		_headRObj._drawSurface.create(headCel.surf, headCel.src);
-		_headRObj.moveTo(headCel.dest);
+		for (uint i = 0; i < _celRObjects.size(); ++i) {
+			Cel &cel = loadCel(_celNames[i][_curFrame], _treeNames[i]);
+			if (_overrideTreeRects[i] == kCelOverrideTreeRectsOn) {
+				_celRObjects[i]._drawSurface.create(cel.surf, _overrideRectSrcs[i]);
+				_celRObjects[i].moveTo(_overrideRectDests[i]);
+			} else {
+				_celRObjects[i]._drawSurface.create(cel.surf, cel.src);
+				_celRObjects[i].moveTo(cel.dest);
+			}
+		}
 
 		_nextFrameTime += _frameTime;
 		++_curFrame;
@@ -611,11 +629,10 @@ void ConversationCel::updateGraphics() {
 }
 
 void ConversationCel::readData(Common::SeekableReadStream &stream) {
-	Nancy::GameType gameType = g_nancy->getGameType();
 	Common::String xsheetName;
 	readFilename(stream, xsheetName);
-	readFilename(stream, _bodyTreeName);
-	readFilename(stream, _headTreeName);
+	
+	readFilenameArray(stream, _treeNames, 4);
 
 	uint xsheetDataSize = 0;
 	byte *xsbuf = g_nancy->_resource->loadData(xsheetName, xsheetDataSize);
@@ -640,37 +657,38 @@ void ConversationCel::readData(Common::SeekableReadStream &stream) {
 	_frameTime = xsheet.readUint16LE();
 	xsheet.skip(2);
 
-	_bodyCelNames.resize(numFrames);
-	_headCelNames.resize(numFrames);
+	_celNames.resize(4, Common::Array<Common::String>(numFrames));
 	for (uint i = 0; i < numFrames; ++i) {
-		readFilename(xsheet, _bodyCelNames[i]);
-		readFilename(xsheet, _headCelNames[i]);
-
-		// Zeroes
-		if (gameType >= kGameTypeNancy3) {
-			xsheet.skip(74);
-		} else {
-			xsheet.skip(28);
+		for (uint j = 0; j < _celNames.size(); ++j) {
+			readFilename(xsheet, _celNames[j][i]);
 		}
+
+		// 4 unknown values
+		xsheet.skip(8);
 	}
 
 	// Continue reading the AR stream
 
-	// Zeroes
-	if (g_nancy->getGameType() >= kGameTypeNancy3) {
-		stream.skip(66);
-	} else {
-		stream.skip(20);
-	}
-
 	// Something related to quality
 	stream.skip(3);
 
 	_firstFrame = stream.readUint16LE();
 	_lastFrame = stream.readUint16LE();
 
-	// A few more quality-related bytes and more zeroes
-	stream.skip(0x8E);
+	stream.skip(6);
+
+	_drawingOrder.resize(4);
+	for (uint i = 0; i < 4; ++i) {
+		_drawingOrder[i] = stream.readByte();
+	}
+
+	_overrideTreeRects.resize(4);
+	for (uint i = 0; i < 4; ++i) {
+		_overrideTreeRects[i] = stream.readByte();
+	}
+
+	readRectArray(stream, _overrideRectSrcs, 4);
+	readRectArray(stream, _overrideRectDests, 4);
 
 	ConversationSound::readData(stream);
 }
diff --git a/engines/nancy/action/conversation.h b/engines/nancy/action/conversation.h
index a2c0a0ac979..45294a20cdd 100644
--- a/engines/nancy/action/conversation.h
+++ b/engines/nancy/action/conversation.h
@@ -142,6 +142,7 @@ class ConversationCel : public ConversationSound {
 	friend class ConversationCelLoader;
 public:
 	ConversationCel() {}
+	virtual ~ConversationCel();
 
 	void init() override;
 	void registerGraphics() override;
@@ -158,30 +159,37 @@ protected:
 		Common::Rect dest;
 	};
 
-	class HeadCel : public RenderObject {
+	class RenderedCel : public RenderObject {
+		friend class ConversationCel;
 	public:
-		HeadCel() : RenderObject(9) {}
+		RenderedCel() : RenderObject(9) {}
 		bool isViewportRelative() const override { return true; }
 	};
 
+	static const byte kCelOverrideTreeRectsOff	= 1;
+	static const byte kCelOverrideTreeRectsOn	= 2;
+
 	bool isVideoDonePlaying() override;
 	Cel &loadCel(const Common::String &name, const Common::String &treeName);
 
-	Common::Array<Common::String> _bodyCelNames;
-	Common::Array<Common::String> _headCelNames;
-	Common::String _bodyTreeName;
-	Common::String _headTreeName;
+	Common::Array<Common::Array<Common::String>> _celNames;
+	Common::Array<Common::String> _treeNames;
 
 	uint16 _frameTime = 0;
 	uint _videoFormat = kLargeVideoFormat;
 	uint16 _firstFrame = 0;
 	uint16 _lastFrame = 0;
 
+	Common::Array<byte> _drawingOrder;
+	Common::Array<byte> _overrideTreeRects;
+
+	Common::Array<Common::Rect> _overrideRectSrcs;
+	Common::Array<Common::Rect> _overrideRectDests;
+
 	uint _curFrame = 0;
 	uint32 _nextFrameTime = 0;
 
-	// We use the built-in RenderObject for the body
-	HeadCel _headRObj;
+	Common::Array<RenderedCel> _celRObjects;
 
 	Common::HashMap<Common::String, Cel> _celCache;
 	Common::SharedPtr<ConversationCelLoader> _loaderPtr;


Commit: f53f88cdb7d61e4ace1e12c89e2d8805843787c8
    https://github.com/scummvm/scummvm/commit/f53f88cdb7d61e4ace1e12c89e2d8805843787c8
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-09T12:49:30+03:00

Commit Message:
NANCY: Correctly readRippedLetterPuzzle in nancy5

Nancy5 added a width and height parameters in the data,
which are now read correctly

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


diff --git a/engines/nancy/action/rippedletterpuzzle.cpp b/engines/nancy/action/rippedletterpuzzle.cpp
index f4d986104d9..8ecd1a420e7 100644
--- a/engines/nancy/action/rippedletterpuzzle.cpp
+++ b/engines/nancy/action/rippedletterpuzzle.cpp
@@ -61,32 +61,71 @@ void RippedLetterPuzzle::readData(Common::SeekableReadStream &stream) {
 
 	readFilename(stream, _imageName);
 
-	readRectArray(stream, _srcRects, 24);
-	readRectArray(stream, _destRects, 24);
+	byte width = 6;
+	byte height = 4;
+
+	if (g_nancy->getGameType() >= kGameTypeNancy5) {
+		width = stream.readByte();
+		height = stream.readByte();
+	}
+
+	_srcRects.resize(width * height);
+	_destRects.resize(width * height);
+	for (uint i = 0; i < height; ++i) {
+		for (uint j = 0; j < width; ++j) {
+			readRect(stream, _srcRects[i * width + j]);
+		}
+		stream.skip((6 - width) * 16);
+	}
+	stream.skip((4 - height) * 6 * 16);
+
+	for (uint i = 0; i < height; ++i) {
+		for (uint j = 0; j < width; ++j) {
+			readRect(stream, _destRects[i * width + j]);
+		}
+		stream.skip((6 - width) * 16);
+	}
+	stream.skip((4 - height) * 6 * 16);
 
 	readRect(stream, _rotateHotspot);
 	readRect(stream, _takeHotspot);
 	readRect(stream, _dropHotspot);
 
-	_initOrder.resize(24);
-	for (uint i = 0; i < 24; ++i) {
-		_initOrder[i] = stream.readByte();
+	_initOrder.resize(width * height);
+	for (uint i = 0; i < height; ++i) {
+		for (uint j = 0; j < width; ++j) {
+			_initOrder[i * width + j] = stream.readByte();
+		}
+		stream.skip((6 - width));
 	}
+	stream.skip((4 - height) * 6);
 
-	_initRotations.resize(24);
-	for (uint i = 0; i < 24; ++i) {
-		_initRotations[i] = stream.readByte();
+	_initRotations.resize(width * height);
+	for (uint i = 0; i < height; ++i) {
+		for (uint j = 0; j < width; ++j) {
+			_initRotations[i * width + j] = stream.readByte();
+		}
+		stream.skip((6 - width));
 	}
+	stream.skip((4 - height) * 6);
 
-	_solveOrder.resize(24);
-	for (uint i = 0; i < 24; ++i) {
-		_solveOrder[i] = stream.readByte();
+	_solveOrder.resize(width * height);
+	for (uint i = 0; i < height; ++i) {
+		for (uint j = 0; j < width; ++j) {
+			_solveOrder[i * width + j] = stream.readByte();
+		}
+		stream.skip((6 - width));
 	}
+	stream.skip((4 - height) * 6);
 
-	_solveRotations.resize(24);
-	for (uint i = 0; i < 24; ++i) {
-		_solveRotations[i] = stream.readByte();
+	_solveRotations.resize(width * height);
+	for (uint i = 0; i < height; ++i) {
+		for (uint j = 0; j < width; ++j) {
+			_solveRotations[i * width + j] = stream.readByte();
+		}
+		stream.skip((6 - width));
 	}
+	stream.skip((4 - height) * 6);
 
 	_takeSound.readNormal(stream);
 	_dropSound.readNormal(stream);
@@ -110,7 +149,7 @@ void RippedLetterPuzzle::execute() {
 			_puzzleState->playerHasTriedPuzzle = true;
 		}
 
-		for (uint i = 0; i < 24; ++i) {
+		for (uint i = 0; i < _puzzleState->order.size(); ++i) {
 			drawPiece(i, _puzzleState->rotations[i], _puzzleState->order[i]);
 		}
 
@@ -123,7 +162,7 @@ void RippedLetterPuzzle::execute() {
 	case kRun:
 		switch (_solveState) {
 		case kNotSolved :
-			for (uint i = 0; i < 24; ++i) {
+			for (uint i = 0; i < _puzzleState->order.size(); ++i) {
 				if (_puzzleState->order[i] != _solveOrder[i] || _puzzleState->rotations[i] != _solveRotations[i]) {
 					return;
 				}
@@ -166,7 +205,7 @@ void RippedLetterPuzzle::handleInput(NancyInput &input) {
 		return;
 	}
 
-	for (uint i = 0; i < 24; ++i) {
+	for (uint i = 0; i < _puzzleState->order.size(); ++i) {
 		Common::Rect screenHotspot = NancySceneState.getViewport().convertViewportToScreen(_destRects[i]);
 		if (screenHotspot.contains(input.mousePos)) {
 			Common::Rect insideRect;


Commit: b918029f010b440d9eec7d9a55c9ec1ecf94e260
    https://github.com/scummvm/scummvm/commit/b918029f010b440d9eec7d9a55c9ec1ecf94e260
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-09T12:49:30+03:00

Commit Message:
NANCY: Move PCAL chunk reading

The PCAL chunk is no longer an exception to the
way BOOT chunks are read and processed; it now has
its own struct type and can be accessed through
getEngineData().

Changed paths:
    engines/nancy/enginedata.cpp
    engines/nancy/enginedata.h
    engines/nancy/iff.h
    engines/nancy/nancy.cpp
    engines/nancy/nancy.h


diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index f6d5cbc5ec4..8f02f021b84 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -33,7 +33,6 @@ EngineData::EngineData(Common::SeekableReadStream *chunkStream) {
 }
 
 BSUM::BSUM(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
-	
 	Common::Serializer s(chunkStream, nullptr);
 	s.setVersion(g_nancy->getGameType());
 
@@ -89,8 +88,14 @@ VIEW::VIEW(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
 	readRect(*chunkStream, bounds);
 }
 
+PCAL::PCAL(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
+	assert(chunkStream);
+	uint num = chunkStream->readUint16LE();
+	readFilenameArray(*chunkStream, calNames, num);
+}
+
 INV::INV(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
-		Common::Serializer s(chunkStream, nullptr);
+	Common::Serializer s(chunkStream, nullptr);
 	s.setVersion(g_nancy->getGameType());
 
 	readRect(*chunkStream, scrollbarSrcBounds);
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index 3e51a8d457c..e4e7270c916 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -73,6 +73,12 @@ struct VIEW : public EngineData {
 	Common::Rect bounds;
 };
 
+struct PCAL : public EngineData {
+	PCAL(Common::SeekableReadStream *chunkStream);
+
+	Common::Array<Common::String> calNames;
+};
+
 struct INV : public EngineData {
 	struct ItemDescription {
 		Common::String name;
diff --git a/engines/nancy/iff.h b/engines/nancy/iff.h
index f893c6f9b5a..c849e00d15d 100644
--- a/engines/nancy/iff.h
+++ b/engines/nancy/iff.h
@@ -34,7 +34,6 @@ namespace Nancy {
 class NancyEngine;
 
 #define ID_DATA		MKTAG('D', 'A', 'T', 'A')
-#define ID_PCAL		MKTAG('P', 'C', 'A', 'L')
 
 class IFF {
 public:
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 4249f4b7e37..a33ab81720d 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -363,7 +363,6 @@ void NancyEngine::bootGameEngine() {
 	IFF *boot = new IFF("boot");
 	if (!boot->load())
 		error("Failed to load boot script");
-	preloadCals(*boot);
 
 	// Load BOOT chunks data
 	Common::SeekableReadStream *chunkStream = nullptr;
@@ -375,6 +374,7 @@ void NancyEngine::bootGameEngine() {
 
 	LOAD_BOOT(BSUM)
 	LOAD_BOOT(VIEW)
+	LOAD_BOOT(PCAL)
 	LOAD_BOOT(INV)
 	LOAD_BOOT(TBOX)
 	LOAD_BOOT(HELP)
@@ -412,6 +412,8 @@ void NancyEngine::bootGameEngine() {
 	#undef LOAD_BOOT_L
 	#undef LOAD_BOOT
 
+	preloadCals();
+
 	_sound->initSoundChannels();
 	_sound->loadCommonSounds(boot);
 
@@ -495,33 +497,18 @@ void NancyEngine::destroyState(NancyState::NancyState state) const {
 	}
 }
 
-void NancyEngine::preloadCals(const IFF &boot) {
-	const byte *buf;
-	uint size;
-	buf = boot.getChunk(ID_PCAL, size);
-
-	if (buf) {
-		Common::MemoryReadStream stream(buf, size);
-		uint16 count = stream.readUint16LE();
-		debugC(1, kDebugEngine, "Preloading %d CALs", count);
-		int nameLen = size / count;
-
-		char *name = new char[nameLen];
-
-		for (uint i = 0; i < count; i++) {
-			stream.read(name, nameLen);
-			name[nameLen - 1] = 0;
-			debugC(1, kDebugEngine, "Preloading CAL '%s'", name);
-			if (!_resource->loadCifTree(name, "cal"))
-				error("Failed to preload CAL '%s'", name);
-		}
-
-		delete[] name;
+void NancyEngine::preloadCals() {
+	const PCAL *pcal = (const PCAL *)getEngineData("PCAL");
+	if (!pcal) {
+		// CALs only appeared in nancy2 so a PCAL chunk may not exist
+		return;
+	}
 
-		if (stream.err())
-			error("Error reading PCAL chunk");
-	} else
-		debugC(1, kDebugEngine, "No PCAL chunk found");
+	for (const Common::String &name : pcal->calNames) {
+		if (!_resource->loadCifTree(name, "cal")) {
+			error("Failed to preload CAL '%s'", name.c_str());
+		}
+	}
 }
 
 void NancyEngine::readDatFile() {
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index 133b794b006..9a698c09788 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -138,8 +138,7 @@ private:
 	State::State *getStateObject(NancyState::NancyState state) const;
 	void destroyState(NancyState::NancyState state) const;
 
-	void preloadCals(const IFF &boot);
-
+	void preloadCals();
 	void readDatFile();
 
 	Common::Error synchronize(Common::Serializer &serializer);


Commit: b5efecf258437ed2dcffe0865b9b566217408000
    https://github.com/scummvm/scummvm/commit/b5efecf258437ed2dcffe0865b9b566217408000
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-09-09T12:49:30+03:00

Commit Message:
NANCY: Improve color text behavior

Fixed an issue where strings with invalid color markup
were being processed differently from the way the original
engine did, making some strings colored when they
shouldn't be. This fixes the nancy4 intro and some other
strings in the same game.

Changed paths:
    engines/nancy/ui/textbox.cpp


diff --git a/engines/nancy/ui/textbox.cpp b/engines/nancy/ui/textbox.cpp
index 53111027703..f40e352feff 100644
--- a/engines/nancy/ui/textbox.cpp
+++ b/engines/nancy/ui/textbox.cpp
@@ -193,11 +193,11 @@ void Textbox::drawTextbox() {
 						break;
 					}
 
-					if (curToken[1] == '0' && colorTokens.size() == 0) {
+					if (curToken[1] == '0' && colorTokens.size() % 2 == 0) {
 						// Found a color end token ("c0") without a corresponding begin ("c1"),
-						// insert a fake one at the beginning of the queue to make the color logic work.
-						// This happens in nancy5's intro
-						colorTokens.push(0);
+						// or following another color end token. This is invalid, so we just skip it
+						// This happens in nancy4's intro, and nancy5's beginning cutscene
+						continue;
 					}
 
 					if (curToken[1] == '1' && colorTokens.size() % 2 == 1) {
@@ -206,13 +206,6 @@ void Textbox::drawTextbox() {
 						// This probably also happens somewhere
 						continue;
 					}
-
-					if (curToken[1] == '0' && colorTokens.size() % 2 == 0) {
-						// Found a color end token ("c0") following another color end token.
-						// This is invalid, so we just skip it
-						// This happens in nancy5's intro
-						continue;
-					}
 					
 					colorTokens.push(currentLine.size());
 					continue;




More information about the Scummvm-git-logs mailing list