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

fracturehill noreply at scummvm.org
Thu Mar 30 18:28:16 UTC 2023


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

Summary:
379ea8b73a NANCY: Credits improvements
60d67f27d0 NANCY: Fix pause issues
8b13bc1f4b NANCY: Remove handwritten list of boot chunks
0945613bd8 NANCY: Wrap color text
504cec69b9 NANCY: Add chunk_export debug command
e0f74000ef NANCY: Implement structs for some BOOT chunks
e696064615 NANCY: Implement struct for MAP chunk
6a873a0013 NANCY: Fix BSUM loading for nancy2 and up
74ee83c9e1 NANCY: Change cursor data loading
7abdf5c126 NANCY: Add list of image chunks
812ec1acb3 NANCY: Implement structs for HELP, CRED and HINT chunks
cbe958db0c NANCY: Change font loading
e23acc9d1f NANCY: Implement struct for CLOK chunk
323b65c023 NANCY: Implement struct for SPUZ chunk
525d2383fb NANCY: Change loading of common sounds
bb613925c3 NANCY: Stop storing BOOT chunks in memory
856f6f89e9 NANCY: Add data reading utility functions
e2109499bd NANCY: Fix missing underscore in class member name


Commit: 379ea8b73a30b9c708a18c6d3de58a0064ac15e7
    https://github.com/scummvm/scummvm/commit/379ea8b73a30b9c708a18c6d3de58a0064ac15e7
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:31+03:00

Commit Message:
NANCY: Credits improvements

Added code to correctly load the credits in The Vampire Diaries.
Added the missing empty space between credits pages. Enabled
input during credits so they can be skipped with a mouse click.

Changed paths:
    engines/nancy/input.cpp
    engines/nancy/state/credits.cpp
    engines/nancy/state/credits.h


diff --git a/engines/nancy/input.cpp b/engines/nancy/input.cpp
index 86b119c8b45..ca75c2e2c44 100644
--- a/engines/nancy/input.cpp
+++ b/engines/nancy/input.cpp
@@ -133,7 +133,7 @@ NancyInput InputManager::getInput() const {
 		ret.input = 0;
 	}
 
-	if (_mouseEnabled) {
+	if (_mouseEnabled || g_nancy->getState() == NancyState::kCredits) {
 		ret.mousePos = g_nancy->getEventManager()->getMousePos();
 	} else {
 		ret.eatMouseInput();
diff --git a/engines/nancy/state/credits.cpp b/engines/nancy/state/credits.cpp
index 175bc2450b2..476eb9eb26f 100644
--- a/engines/nancy/state/credits.cpp
+++ b/engines/nancy/state/credits.cpp
@@ -48,6 +48,7 @@ void Credits::process() {
 }
 
 void Credits::init() {
+	bool isVampire = g_nancy->getGameType() == kGameTypeVampire;
 	Common::SeekableReadStream *cred = g_nancy->getBootChunkStream("CRED");
 	cred->seek(0);
 
@@ -55,22 +56,24 @@ void Credits::init() {
 	readFilename(*cred, imageName);
 	_background.init(imageName);
 
-	readFilename(*cred, imageName);
+	_textNames.resize(isVampire ? 7 : 1);
+	for (Common::String &str : _textNames) {
+		readFilename(*cred, str);
+	}
 
+	Common::Rect rect;
 	cred->skip(0x20); // Skip the src and dest rectangles
-	readRect(*cred, _text._screenPosition);
+	readRect(*cred, rect);
+	_textSurface.moveTo(rect);
 	cred->skip(0x10);
 	_updateTime = cred->readUint16LE();
 	_pixelsToScroll = cred->readUint16LE();
 	_sound.read(*cred, SoundDescription::kMenu);
 
-	g_nancy->_resource->loadImage(imageName, _fullTextSurface);
+	drawTextSurface(0);
 
-	Common::Rect src = _text._screenPosition;
-	src.moveTo(Common::Point());
-	_fullTextSurface.setTransparentColor(g_nancy->_graphicsManager->getTransColor());
-	_text._drawSurface.create(_fullTextSurface, src);
-	_text.init();
+	_textSurface._drawSurface.create(_fullTextSurface, _textSurface.getBounds());
+	_textSurface.init();
 
 	g_nancy->_sound->stopSound("MSND");
 
@@ -78,7 +81,7 @@ void Credits::init() {
 	g_nancy->_sound->playSound(_sound);
 
 	_background.registerGraphics();
-	_text.registerGraphics();
+	_textSurface.registerGraphics();
 
 	g_nancy->setMouseEnabled(false);
 
@@ -101,18 +104,39 @@ void Credits::run() {
 	if (currentTime >= _nextUpdateTime) {
 		_nextUpdateTime = currentTime + _updateTime;
 
-		Common::Rect newSrc = _text._screenPosition;
-		newSrc.moveTo(_text._drawSurface.getOffsetFromOwner());
+		Common::Rect newSrc = _textSurface.getScreenPosition();
+		newSrc.moveTo(_textSurface._drawSurface.getOffsetFromOwner());
 		newSrc.translate(0, _pixelsToScroll);
 
 		if (newSrc.bottom > _fullTextSurface.h) {
 			newSrc.moveTo(Common::Point());
+			if (_textNames.size() > 1) {
+				drawTextSurface(_currentTextImage == _textNames.size() - 1 ? 0 : _currentTextImage + 1);
+			}
 		}
 
-		_text._drawSurface.create(_fullTextSurface, newSrc);
-		_text._needsRedraw = true;
+		_textSurface._drawSurface.create(_fullTextSurface, newSrc);
+		_textSurface.setVisible(true);
 	}
 }
 
+void Credits::drawTextSurface(uint id) {
+	Graphics::ManagedSurface image;
+	uint surfaceHeight = _textSurface.getBounds().height();
+	g_nancy->_resource->loadImage(_textNames[id], image);
+	_fullTextSurface.create(image.w, image.h + (surfaceHeight * 2), g_nancy->_graphicsManager->getInputPixelFormat());
+	_fullTextSurface.setTransparentColor(g_nancy->_graphicsManager->getTransColor());
+	_fullTextSurface.clear(_fullTextSurface.getTransparentColor());
+	_fullTextSurface.blitFrom(image, Common::Point(0, surfaceHeight));
+
+	if (image.hasPalette()) {
+		uint8 palette[256 * 3];
+		image.grabPalette(palette, 0, 256);
+		_fullTextSurface.setPalette(palette, 0, 256);
+	}
+
+	_currentTextImage = id;
+}
+
 } // End of namespace State
 } // End of namespace Nancy
diff --git a/engines/nancy/state/credits.h b/engines/nancy/state/credits.h
index 2e982003ed6..ac66e5d49a8 100644
--- a/engines/nancy/state/credits.h
+++ b/engines/nancy/state/credits.h
@@ -38,7 +38,7 @@ namespace State {
 class Credits : public State, public Common::Singleton<Credits> {
 public:
 	enum State { kInit, kRun };
-	Credits() : _state(kInit), _background(), _text(), _pixelsToScroll(0) {}
+	Credits() : _state(kInit), _background(), _textSurface(1), _pixelsToScroll(0), _currentTextImage(0) {}
 
 	// State API
 	void process() override;
@@ -48,19 +48,16 @@ protected:
 	void init();
 	void run();
 
-	class CreditsText : public RenderObject {
-		friend class Credits;
-	public:
-		CreditsText() : RenderObject(1) {}
-		virtual ~CreditsText() = default;
-	};
+	void drawTextSurface(uint id);
 
 	State _state;
 	UI::FullScreenImage _background;
-	CreditsText _text;
+	RenderObject _textSurface;
 	Time _nextUpdateTime;
 	Graphics::ManagedSurface _fullTextSurface;
-
+	
+	Common::Array<Common::String> _textNames;
+	uint _currentTextImage;
 	Time _updateTime; // 0x54
 	uint16 _pixelsToScroll; // 0x56
 	SoundDescription _sound; // 0x58, kMenu?


Commit: 60d67f27d003e4877f1877180fde90acb88e76a1
    https://github.com/scummvm/scummvm/commit/60d67f27d003e4877f1877180fde90acb88e76a1
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:32+03:00

Commit Message:
NANCY: Fix pause issues

Implemented pauseEngineIntern() and hooked existing pausing code
to it. This fixes issues with videos skipping ahead after returning from
the GMM.

Changed paths:
    engines/nancy/action/primaryvideo.cpp
    engines/nancy/action/secondarymovie.cpp
    engines/nancy/action/secondaryvideo.cpp
    engines/nancy/nancy.cpp
    engines/nancy/nancy.h


diff --git a/engines/nancy/action/primaryvideo.cpp b/engines/nancy/action/primaryvideo.cpp
index 16cd896e302..0f0af4415be 100644
--- a/engines/nancy/action/primaryvideo.cpp
+++ b/engines/nancy/action/primaryvideo.cpp
@@ -163,10 +163,6 @@ void PlayPrimaryVideoChan0::updateGraphics() {
 
 void PlayPrimaryVideoChan0::onPause(bool pause) {
 	_decoder.pauseVideo(pause);
-
-	if (!pause) {
-		registerGraphics();
-	}
 }
 
 void PlayPrimaryVideoChan0::readData(Common::SeekableReadStream &stream) {
diff --git a/engines/nancy/action/secondarymovie.cpp b/engines/nancy/action/secondarymovie.cpp
index a6aa532a647..a40fe4d09ff 100644
--- a/engines/nancy/action/secondarymovie.cpp
+++ b/engines/nancy/action/secondarymovie.cpp
@@ -173,10 +173,6 @@ void PlaySecondaryMovie::updateGraphics() {
 
 void PlaySecondaryMovie::onPause(bool pause) {
 	_decoder.pauseVideo(pause);
-
-	if (!pause) {
-		registerGraphics();
-	}
 }
 
 void PlaySecondaryMovie::execute() {
diff --git a/engines/nancy/action/secondaryvideo.cpp b/engines/nancy/action/secondaryvideo.cpp
index 5d788259a8a..615bf2393f9 100644
--- a/engines/nancy/action/secondaryvideo.cpp
+++ b/engines/nancy/action/secondaryvideo.cpp
@@ -143,10 +143,6 @@ void PlaySecondaryVideo::updateGraphics() {
 
 void PlaySecondaryVideo::onPause(bool pause) {
 	_decoder.pauseVideo(pause);
-
-	if (!pause) {
-		registerGraphics();
-	}
 }
 
 void PlaySecondaryVideo::handleInput(NancyInput &input) {
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index dc29684f3b3..b921433370e 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -188,22 +188,12 @@ void NancyEngine::setState(NancyState::NancyState state, NancyState::NancyState
 		}
 
 		// Do not use the original engine's menus, call the GMM instead
-		State::State *s = getStateObject(_gameFlow.curState);
-		if (s) {
-			s->onStateExit();
-		}
-
 		openMainMenuDialog();
 
 		if (shouldQuit()) {
 			return;
 		}
 
-		s = getStateObject(_gameFlow.curState);
-		if (s) {
-			s->onStateEnter();
-		}
-
 		_input->forceCleanInput();
 
 		return;
@@ -298,6 +288,15 @@ Common::Error NancyEngine::run() {
 	return Common::kNoError;
 }
 
+void NancyEngine::pauseEngineIntern(bool pause) {
+	State::State *s = getStateObject(_gameFlow.curState);
+	if (pause) {
+		s->onStateExit();
+	} else {
+		s->onStateEnter();
+	}
+}
+
 void NancyEngine::bootGameEngine() {
 	// Load paths
 	const Common::FSNode gameDataDir(ConfMan.get("path"));
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index e122bd5f88c..fdaef5c834a 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -129,14 +129,16 @@ public:
 
 	Common::Rect _textboxScreenPosition;
 
+protected:
+	Common::Error run() override;
+	void pauseEngineIntern(bool pause) override;
+
 private:
 	struct GameFlow {
 		NancyState::NancyState curState = NancyState::kNone;
 		NancyState::NancyState prevState = NancyState::kNone;
 	};
 
-	Common::Error run() override;
-
 	void bootGameEngine();
 
 	State::State *getStateObject(NancyState::NancyState state) const;


Commit: 8b13bc1f4b2ac11c20b937c6c928acc1f99b51ab
    https://github.com/scummvm/scummvm/commit/8b13bc1f4b2ac11c20b937c6c928acc1f99b51ab
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:33+03:00

Commit Message:
NANCY: Remove handwritten list of boot chunks

Removed the manually typed out list of chunk names to load during
boot, and replaced it with code that simply loads all BOOT chunks.

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


diff --git a/engines/nancy/iff.cpp b/engines/nancy/iff.cpp
index fa132b83a89..4b7d37b738f 100644
--- a/engines/nancy/iff.cpp
+++ b/engines/nancy/iff.cpp
@@ -146,9 +146,12 @@ uint32 IFF::stringToId(const Common::String &s) {
 }
 
 void IFF::list(Common::Array<Common::String> &nameList) const {
+	Common::String chunkName;
 	nameList.reserve(_chunks.size());
 	for (uint i = 0; i < _chunks.size(); ++i) {
-		nameList.push_back(idToString(_chunks[i].id));
+		chunkName = idToString(_chunks[i].id);
+		chunkName.trim();
+		nameList.push_back(chunkName);
 	}
 }
 
diff --git a/engines/nancy/iff.h b/engines/nancy/iff.h
index 1956cbe3407..f893c6f9b5a 100644
--- a/engines/nancy/iff.h
+++ b/engines/nancy/iff.h
@@ -45,7 +45,6 @@ public:
 	const byte *getChunk(uint32 id, uint &size, uint index = 0) const;
 	Common::SeekableReadStream *getChunkStream(const Common::String &id, uint index = 0) const;
 
-	// Debugger functions
 	void list(Common::Array<Common::String> &nameList) const;
 
 private:
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index b921433370e..2f99db00a13 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -337,18 +337,12 @@ void NancyEngine::bootGameEngine() {
 	addBootChunk("BSUM", boot->getChunkStream("BSUM"));
 	readBootSummary(*boot);
 
-	// Data chunks found in BOOT. These get used in many places in the engine,
-	// so we always keep them in memory
-	Common::String names[] = {
-		"INTR", "HINT", "LOGO", "SPUZ", "INV",
-		"FONT", "MENU", "HELP", "CRED", "LOAD",
-		"MAP", "CD", "TBOX", "CURS", "VIEW", "MSND",
-		"BUOK", "BUDE", "BULS", "GLOB", "SLID",
-		"SET", "CURT", "CANT", "TH1", "TH2",
-		"QUOT", "TMOD", "CLOK", "SPEC"
-	};
-
-	for (auto const &n : names) {
+	// Load all data chunks found in BOOT. These get used in a lot of places
+	// across the engine, so we always keep them in memory
+	Common::Array<Common::String> bootChunkNames;
+	boot->list(bootChunkNames);
+
+	for (auto const &n : bootChunkNames) {
 		addBootChunk(n, boot->getChunkStream(n));
 	}
 


Commit: 0945613bd8e399aa00c28b07fd7c26f54139a287
    https://github.com/scummvm/scummvm/commit/0945613bd8e399aa00c28b07fd7c26f54139a287
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:33+03:00

Commit Message:
NANCY: Wrap color text

Added wrapping to colored text, which fixes the player speech in the
Russian variant of nancy1 not being displayed fully.

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


diff --git a/engines/nancy/ui/textbox.cpp b/engines/nancy/ui/textbox.cpp
index 8906e9f5fa3..689f89fe8e6 100644
--- a/engines/nancy/ui/textbox.cpp
+++ b/engines/nancy/ui/textbox.cpp
@@ -197,40 +197,54 @@ void Textbox::drawTextbox() {
 				currentLine = currentLine.substr(ARRAYSIZE(_tabToken) - 1);
 			}
 
-			String currentSubLine;
+			String currentSubstring;
 			_lastResponseisMultiline = false;
 
 			uint32 nextTabPos = currentLine.find(_tabToken);
 			if (nextTabPos != String::npos) {
-				currentSubLine = currentLine.substr(0, nextTabPos);
+				currentSubstring = currentLine.substr(0, nextTabPos);
 				currentLine = currentLine.substr(nextTabPos);
 			} else {
-				currentSubLine = currentLine;
+				currentSubstring = currentLine;
 				currentLine.clear();
 			}
+			
+			Array<Common::String> wrappedLines;
+			uint numColorLines = 0;
+			uint colorLinesWidth = 0;
 
-			// Assumes color token will be at the beginning of the line, and color string will not need wrapping
-			if (currentSubLine.hasPrefix(_colorBeginToken)) {
+			// Color token denotes a highlighted section of the dialogue
+			// The russian variant of nancy1 makes all player text colored, so we need to do font wrapping here
+			if (currentSubstring.hasPrefix(_colorBeginToken)) {
 				// Found color string, look for end token
-				uint32 colorEndPos = currentSubLine.find(_colorEndToken);
+				uint32 colorEndPos = currentSubstring.find(_colorEndToken);
 
-				Common::String colorSubLine = currentSubLine.substr(ARRAYSIZE(_colorBeginToken) - 1, colorEndPos - ARRAYSIZE(_colorBeginToken) + 1);
-				currentSubLine = currentSubLine.substr(ARRAYSIZE(_colorBeginToken) + ARRAYSIZE(_colorEndToken) + colorSubLine.size() - 2);
+				Common::String colorSubstring = currentSubstring.substr(ARRAYSIZE(_colorBeginToken) - 1, colorEndPos - ARRAYSIZE(_colorBeginToken) + 1);
+				currentSubstring = currentSubstring.substr(ARRAYSIZE(_colorBeginToken) + ARRAYSIZE(_colorEndToken) + colorSubstring.size() - 2);
 
-				// Draw the color line
-				font->drawString(&_fullSurface, colorSubLine, _borderWidth + horizontalOffset, _firstLineOffset - font->getFontHeight() + _numLines * lineDist, maxWidth, 1);
-				horizontalOffset += font->getStringWidth(colorSubLine);
-			}
+				font->wordWrap(colorSubstring, maxWidth, wrappedLines, 0);
 
-			Array<Common::String> wrappedLines;
+				// Draw the color lines
+				for (uint i = 0; i < wrappedLines.size(); ++i) {
+					font->drawString(&_fullSurface, wrappedLines[i], _borderWidth + horizontalOffset, _firstLineOffset - font->getFontHeight() + _numLines * lineDist, maxWidth, 1);
+					colorLinesWidth = MAX<int16>(colorLinesWidth, font->getStringWidth(wrappedLines[i]));
+					if (i != wrappedLines.size() - 1) {
+						++_numLines;
+						++numColorLines;
+					}
+				}
+				
+				horizontalOffset += font->getStringWidth(wrappedLines.back());
+				wrappedLines.clear();
+			}
 
 			// Do word wrapping on the rest of the text
-			font->wordWrap(currentSubLine, maxWidth, wrappedLines, horizontalOffset);
+			font->wordWrap(currentSubstring, maxWidth, wrappedLines, horizontalOffset);
 
 			if (hasHotspot) {
 				hotspot.left = _borderWidth;
-				hotspot.top = _firstLineOffset - font->getFontHeight() + (_numLines + 1) * lineDist;
-				hotspot.setHeight((wrappedLines.size() - 1) * _lineHeight + lineDist);
+				hotspot.top = _firstLineOffset - font->getFontHeight() + (_numLines + 1 - numColorLines) * lineDist;
+				hotspot.setHeight(MAX<int16>((wrappedLines.size() + numColorLines - 1), 1) * _lineHeight + lineDist);
 				hotspot.setWidth(0);
 			}
 
@@ -243,9 +257,12 @@ void Textbox::drawTextbox() {
 				++_numLines;
 			}
 
+			// Make sure to adjust the hotspot width if we had a multi-line color string
+			hotspot.setWidth(MAX<int16>(hotspot.width(), colorLinesWidth));
+
 			// Simulate a bug in the original engine where player text longer than
 			// a single line gets a double newline afterwards
-			if (wrappedLines.size() > 1 && hasHotspot) {
+			if ((wrappedLines.size() + numColorLines) > 1 && hasHotspot) {
 				++_numLines;
 				_lastResponseisMultiline = true;
 			}


Commit: 504cec69b910488487caf1126aa2e48fcc842a80
    https://github.com/scummvm/scummvm/commit/504cec69b910488487caf1126aa2e48fcc842a80
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:34+03:00

Commit Message:
NANCY: Add chunk_export debug command

Changed paths:
    engines/nancy/console.cpp
    engines/nancy/console.h


diff --git a/engines/nancy/console.cpp b/engines/nancy/console.cpp
index 6248845f172..8ef61c57186 100644
--- a/engines/nancy/console.cpp
+++ b/engines/nancy/console.cpp
@@ -44,6 +44,7 @@ NancyConsole::NancyConsole() : GUI::Debugger() {
 	registerCmd("cif_export", WRAP_METHOD(NancyConsole, Cmd_cifExport));
 	registerCmd("cif_list", WRAP_METHOD(NancyConsole, Cmd_cifList));
 	registerCmd("cif_info", WRAP_METHOD(NancyConsole, Cmd_cifInfo));
+	registerCmd("chunk_export", WRAP_METHOD(NancyConsole, Cmd_chunkExport));
 	registerCmd("chunk_hexdump", WRAP_METHOD(NancyConsole, Cmd_chunkHexDump));
 	registerCmd("chunk_list", WRAP_METHOD(NancyConsole, Cmd_chunkList));
 	registerCmd("show_image", WRAP_METHOD(NancyConsole, Cmd_showImage));
@@ -205,6 +206,50 @@ bool NancyConsole::Cmd_cifInfo(int argc, const char **argv) {
 	return true;
 }
 
+bool NancyConsole::Cmd_chunkExport(int argc, const char **argv) {
+	if (argc < 3 || argc > 4) {
+		debugPrintf("Exports an IFF chunk\n");
+		debugPrintf("Usage: %s <iffname> <chunkname> [index]\n", argv[0]);
+		return true;
+	}
+
+	IFF iff(argv[1]);
+	if (!iff.load()) {
+		debugPrintf("Failed to load IFF '%s'\n", argv[1]);
+		return true;
+	}
+
+	const byte *buf;
+	uint size;
+
+	char idStr[4] = { ' ', ' ', ' ', ' ' };
+	uint len = strlen(argv[2]);
+	memcpy(idStr, argv[2], (len <= 4 ? len : 4));
+	uint32 id = READ_BE_UINT32(idStr);
+	uint index = 0;
+
+	if (argc == 4)
+		index = atoi(argv[3]);
+
+	buf = iff.getChunk(id, size, index);
+	if (!buf) {
+		debugPrintf("Failed to find chunk '%s' (index %d) in IFF '%s'\n", argv[2], index, argv[1]);
+		return true;
+	}
+
+	Common::DumpFile dumpfile;
+	Common::String filename = g_nancy->getGameId();
+	filename += '_';
+	filename += argv[1];
+	filename += '_';
+	filename += argv[2];
+	filename += ".dat";
+	dumpfile.open(filename);
+	dumpfile.write(buf, size);
+	dumpfile.close();
+	return true;
+}
+
 bool NancyConsole::Cmd_chunkHexDump(int argc, const char **argv) {
 	if (argc < 3 || argc > 4) {
 		debugPrintf("Hexdumps an IFF chunk\n");
diff --git a/engines/nancy/console.h b/engines/nancy/console.h
index f697cb602ac..3265600a596 100644
--- a/engines/nancy/console.h
+++ b/engines/nancy/console.h
@@ -41,6 +41,7 @@ private:
 	bool Cmd_cifExport(int argc, const char **argv);
 	bool Cmd_cifList(int argc, const char **argv);
 	bool Cmd_cifInfo(int argc, const char **argv);
+	bool Cmd_chunkExport(int argc, const char **argv);
 	bool Cmd_chunkHexDump(int argc, const char **argv);
 	bool Cmd_chunkList(int argc, const char **argv);
 	bool Cmd_showImage(int argc, const char **argv);


Commit: e0f74000efa87f70dec928584b5ca39cd4a74ed5
    https://github.com/scummvm/scummvm/commit/e0f74000efa87f70dec928584b5ca39cd4a74ed5
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:36+03:00

Commit Message:
NANCY: Implement structs for some BOOT chunks

Boot chunks BSUM, VIEW, INV, and TBOX are now read only at startup,
and their data is kept permanently inside NancyEngine. This removes the
need for the chunks to be read by multiple classes and always kept
in memory.

Changed paths:
  A engines/nancy/enginedata.cpp
  A engines/nancy/enginedata.h
    engines/nancy/action/actionmanager.cpp
    engines/nancy/cursor.cpp
    engines/nancy/module.mk
    engines/nancy/nancy.cpp
    engines/nancy/nancy.h
    engines/nancy/state/map.cpp
    engines/nancy/state/scene.cpp
    engines/nancy/ui/inventorybox.cpp
    engines/nancy/ui/inventorybox.h
    engines/nancy/ui/ornaments.cpp
    engines/nancy/ui/textbox.cpp
    engines/nancy/ui/textbox.h
    engines/nancy/ui/viewport.cpp
    engines/nancy/ui/viewport.h


diff --git a/engines/nancy/action/actionmanager.cpp b/engines/nancy/action/actionmanager.cpp
index faa2703f0ad..90952714467 100644
--- a/engines/nancy/action/actionmanager.cpp
+++ b/engines/nancy/action/actionmanager.cpp
@@ -77,7 +77,7 @@ void ActionManager::handleInput(NancyInput &input) {
 
 					// Re-add the object to the inventory unless it's marked as a one-time use
 					if (rec->_itemRequired == heldItem && rec->_itemRequired != -1) {
-						if (NancySceneState.getInventoryBox().getItemDescription(heldItem).keepItem == kInvItemKeepAlways) {
+						if (g_nancy->_inventoryData->itemDescriptions[heldItem].keepItem == kInvItemKeepAlways) {
 							NancySceneState.addItemToInventory(heldItem);
 						}
 
diff --git a/engines/nancy/cursor.cpp b/engines/nancy/cursor.cpp
index 69fe7800a6e..1e0d9774e34 100644
--- a/engines/nancy/cursor.cpp
+++ b/engines/nancy/cursor.cpp
@@ -30,11 +30,7 @@
 namespace Nancy {
 
 void CursorManager::init() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("INV");
-	chunk->seek(0xD6 + g_nancy->getStaticData().numCurtainAnimationFrames * 0x20 + 0x1C);
-	Common::String inventoryCursorsImageName = chunk->readString();
-
-	chunk = g_nancy->getBootChunkStream("CURS");
+	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("CURS");
 	chunk->seek(0);
 	uint numCursors = g_nancy->getStaticData().numNonItemCursors + g_nancy->getStaticData().numItems * 4;
 	_cursors.reserve(numCursors);
@@ -52,7 +48,7 @@ void CursorManager::init() {
 	_primaryVideoInitialPos.x = chunk->readUint16LE();
 	_primaryVideoInitialPos.y = chunk->readUint16LE();
 
-	g_nancy->_resource->loadImage(inventoryCursorsImageName, _invCursorsSurface);
+	g_nancy->_resource->loadImage(g_nancy->_inventoryData->inventoryCursorsImageName, _invCursorsSurface);
 
 	setCursor(kNormalArrow, -1);
 	showCursor(false);
diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
new file mode 100644
index 00000000000..be7009b624d
--- /dev/null
+++ b/engines/nancy/enginedata.cpp
@@ -0,0 +1,181 @@
+/* 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/enginedata.h"
+#include "engines/nancy/nancy.h"
+#include "engines/nancy/util.h"
+
+#include "common/serializer.h"
+
+namespace Nancy {
+
+BSUM::BSUM(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+	
+	chunkStream->seek(0);
+	Common::Serializer s(chunkStream, nullptr);
+	s.setVersion(g_nancy->getGameType());
+
+	// The header is used to verify savegames
+	s.syncBytes(header, 90);
+	
+	s.skip(0x17, kGameTypeVampire, kGameTypeVampire);
+	s.skip(0x49, kGameTypeNancy1, kGameTypeNancy1);
+	s.skip(0xF7, kGameTypeNancy2, kGameTypeNancy3);
+	s.syncAsUint16LE(firstScene.sceneID);
+	s.skip(0xC, kGameTypeVampire, kGameTypeVampire); // Palette name + unknown 2 bytes
+	s.syncAsUint16LE(firstScene.frameID);
+	s.syncAsUint16LE(firstScene.verticalOffset);
+	s.syncAsUint16LE(startTimeHours);
+	s.syncAsUint16LE(startTimeMinutes);
+
+	s.skip(0xA7, kGameTypeVampire, kGameTypeNancy2);
+	s.skip(4, kGameTypeNancy3);
+
+	s.skip(8, kGameTypeVampire, kGameTypeVampire);
+	if (s.getVersion() == kGameTypeVampire) {
+		readRect(*chunkStream, mapButtonHotspot);
+	}
+
+	s.skip(0x10, kGameTypeVampire, kGameTypeNancy1);
+	s.skip(0x20, kGameTypeNancy2, kGameTypeNancy3);
+	readRect(*chunkStream, textboxScreenPosition);
+
+	s.skip(0x10);
+	readRect(*chunkStream, menuButtonSrc);
+	readRect(*chunkStream, helpButtonSrc);
+	readRect(*chunkStream, menuButtonDest);
+	readRect(*chunkStream, helpButtonDest);
+
+	s.skip(0xE, kGameTypeVampire, kGameTypeVampire);
+	s.skip(9, kGameTypeNancy1, kGameTypeNancy1);
+	s.skip(0x39, kGameTypeNancy2, kGameTypeNancy3);
+	s.syncAsUint16LE(horizontalEdgesSize);
+	s.syncAsUint16LE(verticalEdgesSize);
+
+	s.skip(0x1A, kGameTypeVampire, kGameTypeVampire);
+	s.skip(0x1C, kGameTypeNancy1);
+	s.syncAsSint16LE(playerTimeMinuteLength);
+
+	s.skip(2);
+	s.syncAsByte(overrideMovementTimeDeltas);
+	s.syncAsSint16LE(slowMovementTimeDelta);
+	s.syncAsSint16LE(fastMovementTimeDelta);
+
+	delete chunkStream;
+}
+
+VIEW::VIEW(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+	
+	chunkStream->seek(0);
+	readRect(*chunkStream, screenPosition);
+	readRect(*chunkStream, bounds);
+
+	delete chunkStream;
+}
+
+INV::INV(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
+	Common::Serializer s(chunkStream, nullptr);
+	s.setVersion(g_nancy->getGameType());
+
+	readRect(*chunkStream, scrollbarSrcBounds);
+	s.syncAsUint16LE(scrollbarDefaultPos.x);
+	s.syncAsUint16LE(scrollbarDefaultPos.y);
+	s.syncAsUint16LE(scrollbarMaxScroll);
+
+	s.skip(0xC0);
+
+	uint numFrames = g_nancy->getStaticData().numCurtainAnimationFrames;
+	curtainAnimationSrcs.resize(numFrames * 2);
+	for (uint i = 0; i < numFrames * 2; ++i) {
+		readRect(*chunkStream, curtainAnimationSrcs[i]);
+	}
+
+	readRect(*chunkStream, inventoryScreenPosition);
+	s.syncAsUint16LE(curtainsFrameTime);
+
+	readFilename(*chunkStream, inventoryBoxIconsImageName);
+	readFilename(*chunkStream, inventoryCursorsImageName);
+
+	s.skip(0x18);
+	byte itemName[20];
+	uint itemNameLength = g_nancy->getGameType() == kGameTypeVampire ? 15 : 20;
+
+	uint16 numItems = g_nancy->getStaticData().numItems;
+	itemDescriptions.resize(numItems);
+	for (uint i = 0; i < numItems; ++i) {
+		ItemDescription &item = itemDescriptions[i];
+		
+		s.syncBytes(itemName, itemNameLength);
+		itemName[itemNameLength - 1] = '\0';
+		item.name = (char *)itemName;
+		s.syncAsUint16LE(item.keepItem);
+		readRect(*chunkStream, item.sourceRect);
+	}
+
+	delete chunkStream;
+}
+
+TBOX::TBOX(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	bool isVampire = g_nancy->getGameType() == Nancy::GameType::kGameTypeVampire;
+
+	chunkStream->seek(0);
+	readRect(*chunkStream, scrollbarSrcBounds);
+
+	chunkStream->seek(0x20);
+	readRect(*chunkStream, innerBoundingBox);
+
+	scrollbarDefaultPos.x = chunkStream->readUint16LE() - (isVampire ? 1 : 0);
+	scrollbarDefaultPos.y = chunkStream->readUint16LE();
+	scrollbarMaxScroll = chunkStream->readUint16LE();
+
+	firstLineOffset = chunkStream->readUint16LE() + 1;
+	lineHeight = chunkStream->readUint16LE() + (isVampire ? 1 : 0);
+	borderWidth = chunkStream->readUint16LE() - 1;
+	maxWidthDifference = chunkStream->readUint16LE();
+
+	if (isVampire) {
+		ornamentSrcs.resize(14);
+		ornamentDests.resize(14);
+		
+		chunkStream->seek(0x3E);
+		for (uint i = 0; i < 14; ++i) {
+			readRect(*chunkStream, ornamentSrcs[i]);
+		}
+
+		for (uint i = 0; i < 14; ++i) {
+			readRect(*chunkStream, ornamentDests[i]);
+		}
+	}
+
+	chunkStream->seek(0x1FE);
+	fontID = chunkStream->readUint16LE();
+
+	delete chunkStream;
+}
+
+} // End of namespace Nancy
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
new file mode 100644
index 00000000000..15aaedd55ea
--- /dev/null
+++ b/engines/nancy/enginedata.h
@@ -0,0 +1,109 @@
+/* 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_ENGINEDATA_H
+#define NANCY_ENGINEDATA_H
+
+#include "engines/nancy/commontypes.h"
+
+namespace Nancy {
+
+// Data types corresponding to chunks found inside BOOT
+
+struct BSUM {
+	BSUM(Common::SeekableReadStream *chunkStream);
+
+	byte header[90];
+
+	// Game start section
+	SceneChangeDescription firstScene;
+	uint16 startTimeHours;
+	uint16 startTimeMinutes;
+
+	// UI
+	Common::Rect mapButtonHotspot;
+	Common::Rect textboxScreenPosition;
+	Common::Rect menuButtonSrc;
+	Common::Rect helpButtonSrc;
+	Common::Rect menuButtonDest;
+	Common::Rect helpButtonDest;
+
+	uint16 horizontalEdgesSize;
+	uint16 verticalEdgesSize;
+
+	uint16 playerTimeMinuteLength;
+	byte overrideMovementTimeDeltas;
+	uint16 slowMovementTimeDelta;
+	uint16 fastMovementTimeDelta;
+};
+
+struct VIEW {
+	VIEW(Common::SeekableReadStream *chunkStream);
+
+	Common::Rect screenPosition;
+	Common::Rect bounds;
+};
+
+struct INV {
+	struct ItemDescription {
+		Common::String name;
+		byte keepItem;
+		Common::Rect sourceRect;
+	};
+
+	INV(Common::SeekableReadStream *chunkStream);
+
+	Common::Rect scrollbarSrcBounds;
+	Common::Point scrollbarDefaultPos;
+	uint16 scrollbarMaxScroll;
+
+	Common::Array<Common::Rect> curtainAnimationSrcs;
+	Common::Rect inventoryScreenPosition;
+	uint16 curtainsFrameTime;
+
+	Common::String inventoryBoxIconsImageName;
+	Common::String inventoryCursorsImageName;
+
+	Common::Array<ItemDescription> itemDescriptions;
+};
+
+struct TBOX {
+	TBOX(Common::SeekableReadStream *chunkStream);
+
+	Common::Rect scrollbarSrcBounds;
+	Common::Rect innerBoundingBox;
+	Common::Point scrollbarDefaultPos;
+	uint16 scrollbarMaxScroll;
+
+	uint16 firstLineOffset;
+	uint16 lineHeight;
+	uint16 borderWidth;
+	uint16 maxWidthDifference;
+
+	Common::Array<Common::Rect> ornamentSrcs;
+	Common::Array<Common::Rect> ornamentDests;
+
+	uint16 fontID;
+};
+
+} // End of namespace Nancy
+
+#endif // NANCY_ENGINEDATA_H
diff --git a/engines/nancy/module.mk b/engines/nancy/module.mk
index 18c98f5ee70..8fb00a1f180 100644
--- a/engines/nancy/module.mk
+++ b/engines/nancy/module.mk
@@ -36,6 +36,7 @@ MODULE_OBJS = \
   cursor.o \
   decompress.o \
   dialogs.o \
+  enginedata.o \
   font.o \
   graphics.o \
   iff.o \
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 2f99db00a13..0b86123907e 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -68,10 +68,11 @@ NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) :
 	_cursorManager = new CursorManager();
 
 	_resource = nullptr;
-	_startTimeHours = 0;
-	_overrideMovementTimeDeltas = false;
-	_horizontalEdgesSize = 0;
-	_verticalEdgesSize = 0;
+
+	_bootSummary = nullptr;
+	_viewportData = nullptr;
+	_inventoryData = nullptr;
+	_textboxData = nullptr;
 }
 
 NancyEngine::~NancyEngine() {
@@ -82,6 +83,11 @@ NancyEngine::~NancyEngine() {
 	delete _cursorManager;
 	delete _input;
 	delete _sound;
+
+	delete _bootSummary;
+	delete _viewportData;
+	delete _inventoryData;
+	delete _textboxData;
 }
 
 NancyEngine *NancyEngine::create(GameType type, OSystem *syst, const NancyGameDescription *gd) {
@@ -334,8 +340,11 @@ void NancyEngine::bootGameEngine() {
 		error("Failed to load boot script");
 	preloadCals(*boot);
 
-	addBootChunk("BSUM", boot->getChunkStream("BSUM"));
-	readBootSummary(*boot);
+	// Load BOOT chunks data
+	_bootSummary = new BSUM(boot->getChunkStream("BSUM"));
+	_viewportData = new VIEW(boot->getChunkStream("VIEW"));
+	_inventoryData = new INV(boot->getChunkStream("INV"));
+	_textboxData = new TBOX(boot->getChunkStream("TBOX"));
 
 	// Load all data chunks found in BOOT. These get used in a lot of places
 	// across the engine, so we always keep them in memory
@@ -424,70 +433,6 @@ void NancyEngine::preloadCals(const IFF &boot) {
 		debugC(1, kDebugEngine, "No PCAL chunk found");
 }
 
-void NancyEngine::readChunkList(const IFF &boot, Common::Serializer &ser, const Common::String &prefix) {
-	byte numChunks = 0;
-	ser.syncAsByte(numChunks);
-	for (byte i = 0; i < numChunks; ++ i) {
-		Common::String name = Common::String::format("%s%d", prefix.c_str(), i);
-		addBootChunk(name, boot.getChunkStream(name));
-	}
-}
-
-void NancyEngine::readBootSummary(const IFF &boot) {
-	Common::SeekableReadStream *bsum = getBootChunkStream("BSUM");
-	bsum->seek(0);
-
-	// Use a serializer to handle several games' BSUMs in the same function
-	Common::Serializer ser(bsum, nullptr);
-	ser.setVersion(_gameDescription->gameType);
-
-	ser.skip(0x71, kGameTypeVampire, kGameTypeVampire);
-	ser.skip(0xA3, kGameTypeNancy1, kGameTypeNancy1);
-	ser.skip(0x9D, kGameTypeNancy2, kGameTypeNancy3);
-	ser.syncAsUint16LE(_firstScene.sceneID);
-	ser.skip(12, kGameTypeVampire, kGameTypeVampire); // Palette
-	ser.syncAsUint16LE(_firstScene.frameID);
-	ser.syncAsUint16LE(_firstScene.verticalOffset);
-	ser.syncAsUint16LE(_startTimeHours);
-	ser.syncAsUint16LE(_startTimeMinutes);
-
-	ser.skip(0xA4, kGameTypeVampire, kGameTypeNancy2);
-
-	readChunkList(boot, ser, "FR"); // frames
-	readChunkList(boot, ser, "LG"); // logos
-
-	if (ser.getVersion() == kGameTypeNancy3) {
-		readChunkList(boot, ser, "PLG"); // partner logos
-	}
-
-	readChunkList(boot, ser, "OB"); // objects
-
-	ser.skip(0x28, kGameTypeVampire, kGameTypeVampire);
-	ser.skip(0x10, kGameTypeNancy1, kGameTypeNancy1);
-	ser.skip(0x20, kGameTypeNancy2, kGameTypeNancy3);
-	readRect(*bsum, _textboxScreenPosition);
-
-	ser.skip(0x5E, kGameTypeVampire, kGameTypeVampire);
-	ser.skip(0x59, kGameTypeNancy1, kGameTypeNancy1);
-	ser.skip(0x89, kGameTypeNancy2, kGameTypeNancy3);
-	ser.syncAsUint16LE(_horizontalEdgesSize);
-	ser.syncAsUint16LE(_verticalEdgesSize);
-	ser.skip(0x1A, kGameTypeVampire, kGameTypeVampire);
-	ser.skip(0x1C, kGameTypeNancy1);
-	int16 time = 0;
-	ser.syncAsSint16LE(time);
-	_playerTimeMinuteLength = time;
-	ser.skip(2);
-	ser.syncAsByte(_overrideMovementTimeDeltas);
-
-	if (_overrideMovementTimeDeltas) {
-		ser.syncAsSint16LE(time);
-		_slowMovementTimeDelta = time;
-		ser.syncAsSint16LE(time);
-		_fastMovementTimeDelta = time;
-	}
-}
-
 void NancyEngine::readDatFile() {
 	Common::SeekableReadStream *datFile = SearchMan.createReadStreamForMember("nancy.dat");
 	if (!datFile) {
@@ -519,14 +464,11 @@ void NancyEngine::readDatFile() {
 }
 
 Common::Error NancyEngine::synchronize(Common::Serializer &ser) {
-	Common::SeekableReadStream *bsum = getBootChunkStream("BSUM");
-	bsum->seek(0);
+	assert(_bootSummary);
 
 	// Sync boot summary header, which includes full game title
 	ser.syncVersion(kSavegameVersion);
-	char buf[90];
-	bsum->read(buf, 90);
-	ser.matchBytes(buf, 90);
+	ser.matchBytes((char *)_bootSummary->header, 90);
 
 	// Sync scene and action records
 	NancySceneState.synchronize(ser);
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index fdaef5c834a..ea3ce053c9b 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -30,6 +30,7 @@
 #include "nancy/detection.h"
 #include "nancy/time.h"
 #include "nancy/commontypes.h"
+#include "nancy/enginedata.h"
 
 namespace Common {
 class RandomSource;
@@ -113,21 +114,11 @@ public:
 
 	Common::RandomSource *_randomSource;
 
-	// BSUM data
-	SceneChangeDescription _firstScene;
-
-	uint16 _startTimeHours;
-	uint16 _startTimeMinutes;
-
-	bool _overrideMovementTimeDeltas;
-	Time _slowMovementTimeDelta;
-	Time _fastMovementTimeDelta;
-	Time _playerTimeMinuteLength;
-
-	uint _horizontalEdgesSize;
-	uint _verticalEdgesSize;
-
-	Common::Rect _textboxScreenPosition;
+	// BOOT chunks data
+	BSUM *_bootSummary;
+	VIEW *_viewportData;
+	INV *_inventoryData;
+	TBOX *_textboxData;
 
 protected:
 	Common::Error run() override;
@@ -147,9 +138,7 @@ private:
 	void clearBootChunks();
 
 	void preloadCals(const IFF &boot);
-	void readChunkList(const IFF &boot, Common::Serializer &ser, const Common::String &prefix);
 
-	void readBootSummary(const IFF &boot);
 	void readDatFile();
 
 	Common::Error synchronize(Common::Serializer &serializer);
diff --git a/engines/nancy/state/map.cpp b/engines/nancy/state/map.cpp
index 36e1f7c6379..389a78f9b03 100644
--- a/engines/nancy/state/map.cpp
+++ b/engines/nancy/state/map.cpp
@@ -112,16 +112,8 @@ void Map::setLabel(int labelID) {
 }
 
 void Map::MapViewport::init() {
-	Common::SeekableReadStream *viewChunk = g_nancy->getBootChunkStream("VIEW");
-
-	if (viewChunk) {
-		viewChunk->seek(0);
-		Common::Rect dest;
-		readRect(*viewChunk, dest);
-		moveTo(dest);
-
-		_drawSurface.create(dest.width(), dest.height(), g_nancy->_graphicsManager->getInputPixelFormat());
-	}
+	moveTo(g_nancy->_viewportData->screenPosition);
+	_drawSurface.create(_screenPosition.width(), _screenPosition.height(), g_nancy->_graphicsManager->getInputPixelFormat());
 
 	RenderObject::init();
 }
@@ -165,7 +157,7 @@ void TVDMap::init() {
 	_globe.init();
 
 	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("MAP");
-	Common::Rect textboxScreenPosition = NancySceneState.getTextbox().getScreenPosition();
+	Common::Rect textboxScreenPosition =g_nancy->_bootSummary->textboxScreenPosition;
 
 	if (chunk) {
 		chunk->seek(0);
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index a60f3aa8df1..be33aad1750 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -87,9 +87,9 @@ void Scene::SceneSummary::read(Common::SeekableReadStream &stream) {
 	ser.syncAsUint16LE((uint32 &)slowMoveTimeDelta);
 	ser.syncAsUint16LE((uint32 &)fastMoveTimeDelta);
 
-	if (g_nancy->_overrideMovementTimeDeltas) {
-		slowMoveTimeDelta = g_nancy->_slowMovementTimeDelta;
-		fastMoveTimeDelta = g_nancy->_fastMovementTimeDelta;
+	if (g_nancy->_bootSummary->overrideMovementTimeDeltas) {
+		slowMoveTimeDelta = g_nancy->_bootSummary->slowMovementTimeDelta;
+		fastMoveTimeDelta = g_nancy->_bootSummary->fastMovementTimeDelta;
 	}
 
 	delete[] buf;
@@ -249,7 +249,7 @@ void Scene::setPlayerTime(Time time, byte relative) {
 		_timers.playerTime = _timers.playerTime.getDays() * 86400000 + time;
 	}
 
-	_timers.playerTimeNextMinute = g_nancy->getTotalPlayTime() + g_nancy->_playerTimeMinuteLength;
+	_timers.playerTimeNextMinute = g_nancy->getTotalPlayTime() + g_nancy->_bootSummary->playerTimeMinuteLength;
 }
 
 byte Scene::getPlayerTOD() const {
@@ -481,14 +481,14 @@ void Scene::init() {
 	_flags.items.resize(g_nancy->getStaticData().numItems, kInvEmpty);
 
 	_timers.lastTotalTime = 0;
-	_timers.playerTime = g_nancy->_startTimeHours * 3600000;
+	_timers.playerTime = g_nancy->_bootSummary->startTimeHours * 3600000;
 	_timers.sceneTime = 0;
 	_timers.timerTime = 0;
 	_timers.timerIsActive = false;
 	_timers.playerTimeNextMinute = 0;
 	_timers.pushedPlayTime = 0;
 
-	changeScene(g_nancy->_firstScene);
+	changeScene(g_nancy->_bootSummary->firstScene);
 
 	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("HINT");
 
@@ -638,7 +638,7 @@ void Scene::run() {
 	// Calculate the in-game time (playerTime)
 	if (currentPlayTime > _timers.playerTimeNextMinute) {
 		_timers.playerTime += 60000; // Add a minute
-		_timers.playerTimeNextMinute = currentPlayTime + g_nancy->_playerTimeMinuteLength;
+		_timers.playerTimeNextMinute = currentPlayTime + g_nancy->_bootSummary->playerTimeMinuteLength;
 	}
 
 	handleInput();
@@ -741,34 +741,17 @@ void Scene::initStaticData() {
 	_inventoryBox.init();
 
 	// Init buttons
-	chunk = g_nancy->getBootChunkStream("BSUM");
-	if (chunk) {
-		chunk->seek(0);
-		Common::Serializer ser(chunk, nullptr);
-		ser.setVersion(g_nancy->getGameType());
-
-		// TVD checks if the _entire_ cursor is within the bounds of the hotspot,
-		// which results in the actual hotspot being about a quarter of the size 
-		// it should be. This is stupid so we sacrifice some accuracy and ignore it.
-		ser.skip(0x136, kGameTypeVampire, kGameTypeVampire);
-		if (ser.getVersion() == kGameTypeVampire) {
-			readRect(*chunk, _mapHotspot);
-		}
-
-		ser.skip(0x30, kGameTypeVampire, kGameTypeVampire);
-		ser.skip(0x184, kGameTypeNancy1);
-		Common::Rect menuSrc, helpSrc, menuDest, helpDest;
-		readRect(*chunk, menuSrc);
-		readRect(*chunk, helpSrc);
-		readRect(*chunk, menuDest);
-		readRect(*chunk, helpDest);
-		_menuButton = new UI::Button(5, g_nancy->_graphicsManager->_object0, menuSrc, menuDest);
-		_helpButton = new UI::Button(5, g_nancy->_graphicsManager->_object0, helpSrc, helpDest);
-		_menuButton->init();
-		_helpButton->init();
-		g_nancy->setMouseEnabled(true);
+	BSUM *bsum = g_nancy->_bootSummary;
+	assert(bsum);
+	
+	if (g_nancy->getGameType() == kGameTypeVampire) {
+		_mapHotspot = bsum->mapButtonHotspot;
 	}
 
+	_menuButton = new UI::Button(5, g_nancy->_graphicsManager->_object0, bsum->menuButtonSrc, bsum->menuButtonDest);
+	_helpButton = new UI::Button(5, g_nancy->_graphicsManager->_object0, bsum->helpButtonSrc, bsum->helpButtonDest);
+	g_nancy->setMouseEnabled(true);
+
 	if (g_nancy->getGameType() == kGameTypeNancy1) {
 		chunk = g_nancy->getBootChunkStream("MAP");
 		if (chunk) {
diff --git a/engines/nancy/ui/inventorybox.cpp b/engines/nancy/ui/inventorybox.cpp
index aeeaa741b70..2de673e5516 100644
--- a/engines/nancy/ui/inventorybox.cpp
+++ b/engines/nancy/ui/inventorybox.cpp
@@ -39,9 +39,7 @@ namespace UI {
 InventoryBox::InventoryBox() :
 		RenderObject(6),
 		_scrollbar(nullptr),
-		_curtains(this),
-		_scrollbarPos(0),
-		_curtainsFrameTime(0) {}
+		_scrollbarPos(0) {}
 
 InventoryBox::~InventoryBox() {
 	_fullInventorySurface.free();
@@ -49,51 +47,10 @@ InventoryBox::~InventoryBox() {
 }
 
 void InventoryBox::init() {
-	Common::SeekableReadStream &stream = *g_nancy->getBootChunkStream("INV");
-	stream.seek(0, SEEK_SET);
-
 	_order.clear();
 
-	Common::Rect scrollbarSrcBounds;
-	readRect(stream, scrollbarSrcBounds);
-	Common::Point scrollbarDefaultPos;
-	scrollbarDefaultPos.x = stream.readUint16LE();
-	scrollbarDefaultPos.y = stream.readUint16LE();
-	uint16 scrollbarMaxScroll = stream.readUint16LE();
-
-	stream.seek(0xD6, SEEK_SET);
-
-	uint numFrames = g_nancy->getStaticData().numCurtainAnimationFrames;
-	_curtainsSrc.resize(numFrames * 2);
-	for (uint i = 0; i < numFrames * 2; ++i) {
-		readRect(stream, _curtainsSrc[i]);
-	}
-
-	readRect(stream, _screenPosition);
-	_curtainsFrameTime = stream.readUint16LE();
-
-	Common::String inventoryBoxIconsImageName;
-	readFilename(stream, inventoryBoxIconsImageName);
-	readFilename(stream, _inventoryCursorsImageName);
-
-	stream.skip(8);
-	readRect(stream, _emptySpace);
-
-	char itemName[20];
-	uint itemNameLength = g_nancy->getGameType() == kGameTypeVampire ? 15 : 20;
-
-	_itemDescriptions.reserve(g_nancy->getStaticData().numItems);
-	for (uint i = 0; i < g_nancy->getStaticData().numItems; ++i) {
-		stream.read(itemName, itemNameLength);
-		itemName[itemNameLength - 1] = '\0';
-		_itemDescriptions.push_back(ItemDescription());
-		ItemDescription &desc = _itemDescriptions.back();
-		desc.name = Common::String(itemName);
-		desc.keepItem = stream.readUint16LE();
-		readRect(stream, desc.sourceRect);
-	}
-
-	g_nancy->_resource->loadImage(inventoryBoxIconsImageName, _iconsSurface);
+	moveTo(g_nancy->_inventoryData->inventoryScreenPosition);
+	g_nancy->_resource->loadImage(g_nancy->_inventoryData->inventoryBoxIconsImageName, _iconsSurface);
 
 	_fullInventorySurface.create(_screenPosition.width(), _screenPosition.height() * ((g_nancy->getStaticData().numItems / 4) + 1), g_nancy->_graphicsManager->getScreenPixelFormat());
 	Common::Rect sourceRect = _screenPosition;
@@ -110,7 +67,10 @@ void InventoryBox::init() {
 
 	RenderObject::init();
 
-	_scrollbar = new Scrollbar(9, scrollbarSrcBounds, scrollbarDefaultPos, scrollbarMaxScroll - scrollbarDefaultPos.y);
+	_scrollbar = new Scrollbar(	9,
+								g_nancy->_inventoryData->scrollbarSrcBounds,
+								g_nancy->_inventoryData->scrollbarDefaultPos,
+								g_nancy->_inventoryData->scrollbarMaxScroll - g_nancy->_inventoryData->scrollbarDefaultPos.y);
 	_scrollbar->init();
 	_curtains.init();
 }
@@ -188,7 +148,7 @@ void InventoryBox::onReorder() {
 		dest.moveTo((i % 2) * dest.width(), (i / 2) * dest.height());
 		Common::Point destPoint = Common::Point (dest.left, dest.top);
 
-		_fullInventorySurface.blitFrom(_iconsSurface, _itemDescriptions[_order[i]].sourceRect, destPoint);
+		_fullInventorySurface.blitFrom(_iconsSurface, g_nancy->_inventoryData->itemDescriptions[_order[i]].sourceRect, destPoint);
 	}
 
 	if (_order.size() > 0) {
@@ -227,7 +187,9 @@ void InventoryBox::onScrollbarMove() {
 }
 
 void InventoryBox::Curtains::init() {
-	Common::Rect bounds = _parent->getBounds();
+	moveTo(g_nancy->_inventoryData->inventoryScreenPosition);
+	Common::Rect bounds = _screenPosition;
+	bounds.moveTo(0, 0);
 	_drawSurface.create(bounds.width(), bounds.height(), g_nancy->_graphicsManager->getInputPixelFormat());
 
 	if (g_nancy->getGameType() == kGameTypeVampire) {
@@ -236,7 +198,6 @@ void InventoryBox::Curtains::init() {
 		_drawSurface.setPalette(palette, 0, 256);
 	}
 
-	_screenPosition = _parent->getScreenPosition();
 	_nextFrameTime = 0;
 	setAnimationFrame(_curFrame);
 
@@ -250,7 +211,7 @@ void InventoryBox::Curtains::updateGraphics() {
 	if (_areOpen) {
 		if (_curFrame < g_nancy->getStaticData().numCurtainAnimationFrames && time > _nextFrameTime) {
 			setAnimationFrame(++_curFrame);
-			_nextFrameTime = time + _parent->_curtainsFrameTime;
+			_nextFrameTime = time + g_nancy->_inventoryData->curtainsFrameTime;
 
 			if (!_soundTriggered) {
 				_soundTriggered = true;
@@ -260,7 +221,7 @@ void InventoryBox::Curtains::updateGraphics() {
 	} else {
 		if (_curFrame > 0 && time > _nextFrameTime) {
 			setAnimationFrame(--_curFrame);
-			_nextFrameTime = time + _parent->_curtainsFrameTime;
+			_nextFrameTime = time + g_nancy->_inventoryData->curtainsFrameTime;
 
 			if (!_soundTriggered) {
 				_soundTriggered = true;
@@ -289,11 +250,11 @@ void InventoryBox::Curtains::setAnimationFrame(uint frame) {
 	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
 
 	// Draw left shade
-	srcRect = _parent->_curtainsSrc[frame * 2];
+	srcRect = g_nancy->_inventoryData->curtainAnimationSrcs[frame * 2];
 	_drawSurface.blitFrom(_object0, srcRect, destPoint);
 
 	// Draw right shade
-	srcRect = _parent->_curtainsSrc[frame * 2 + 1];
+	srcRect = g_nancy->_inventoryData->curtainAnimationSrcs[frame * 2 + 1];
 	destPoint.x = getBounds().width() - srcRect.width();
 	_drawSurface.blitFrom(_object0, srcRect, destPoint);
 
diff --git a/engines/nancy/ui/inventorybox.h b/engines/nancy/ui/inventorybox.h
index 1511b657fe2..23431cef382 100644
--- a/engines/nancy/ui/inventorybox.h
+++ b/engines/nancy/ui/inventorybox.h
@@ -57,8 +57,6 @@ public:
 	void registerGraphics() override;
 	void handleInput(NancyInput &input);
 
-	ItemDescription getItemDescription(uint id) const { return _itemDescriptions[id]; }
-
 	void onScrollbarMove();
 
 private:
@@ -71,9 +69,8 @@ private:
 
 	class Curtains : public RenderObject {
 	public:
-		Curtains(InventoryBox *parent) :
+		Curtains() :
 			RenderObject(9),
-			_parent(parent),
 			_soundTriggered(false),
 			_areOpen(false),
 			_curFrame(0) {}
@@ -86,8 +83,6 @@ private:
 
 		void setAnimationFrame(uint frame);
 
-		InventoryBox *_parent;
-
 		uint _curFrame;
 		Time _nextFrameTime;
 		bool _areOpen;
@@ -109,16 +104,6 @@ private:
 
 	Common::Array<int16> _order;
 	ItemHotspot _itemHotspots[4];
-
-	// INV contents
-	//...
-	Common::Array<Common::Rect> _curtainsSrc; // 0xD6
-	// _screenPosition 0x1B6
-	uint16 _curtainsFrameTime; // 0x1C6
-	Common::String _inventoryCursorsImageName; // 0x1D2, should this be here?
-
-	Common::Rect _emptySpace; // 0x1E4
-	Common::Array<ItemDescription> _itemDescriptions; // 0x1F4
 };
 
 } // End of namespace UI
diff --git a/engines/nancy/ui/ornaments.cpp b/engines/nancy/ui/ornaments.cpp
index 7c8b51a8419..fd832338b0a 100644
--- a/engines/nancy/ui/ornaments.cpp
+++ b/engines/nancy/ui/ornaments.cpp
@@ -29,11 +29,8 @@ namespace Nancy {
 namespace UI {
 
 void ViewportOrnaments::init() {
-	Common::Rect viewportBounds;
-	Common::SeekableReadStream *viewChunk = g_nancy->getBootChunkStream("VIEW");
-	viewChunk->seek(0);
-	readRect(*viewChunk, _screenPosition);
-	readRect(*viewChunk, viewportBounds);
+	Common::Rect viewportBounds = g_nancy->_viewportData->bounds;
+	moveTo(g_nancy->_viewportData->screenPosition);
 
 	Graphics::ManagedSurface &object0 = g_nancy->_graphicsManager->_object0;
 
@@ -74,7 +71,7 @@ void ViewportOrnaments::init() {
 }
 
 void TextboxOrnaments::init() {
-	_screenPosition = g_nancy->_textboxScreenPosition;
+	_screenPosition = g_nancy->_bootSummary->textboxScreenPosition;
 	Common::Rect textboxBounds = _screenPosition;
 	textboxBounds.moveTo(0, 0);
 
@@ -89,23 +86,10 @@ void TextboxOrnaments::init() {
 	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
 	setTransparent(true);
 
-	// Values for textbox ornaments are stored in the TBOX chunk
-	Common::Rect src[14];
-	Common::Rect dest[14];
-
-	Common::SeekableReadStream *tboxChunk = g_nancy->getBootChunkStream("TBOX");
-	tboxChunk->seek(0x3E);
-
-	for (uint i = 0; i < 14; ++i) {
-		readRect(*tboxChunk, src[i]);
-	}
-
-	for (uint i = 0; i < 14; ++i) {
-		readRect(*tboxChunk, dest[i]);
-	}
-
 	for (uint i = 0; i < 14; ++i) {
-		_drawSurface.blitFrom(object0, src[i], Common::Point(dest[i].left - _screenPosition.left, dest[i].top - _screenPosition.top));
+		_drawSurface.blitFrom(object0, g_nancy->_textboxData->ornamentSrcs[i],
+								Common::Point(	g_nancy->_textboxData->ornamentDests[i].left - _screenPosition.left,
+												g_nancy->_textboxData->ornamentDests[i].top - _screenPosition.top));
 	}
 
 	RenderObject::init();
diff --git a/engines/nancy/ui/textbox.cpp b/engines/nancy/ui/textbox.cpp
index 689f89fe8e6..c7aecca6b17 100644
--- a/engines/nancy/ui/textbox.cpp
+++ b/engines/nancy/ui/textbox.cpp
@@ -44,9 +44,6 @@ const char Textbox::_telephoneEndToken[] = "<e>";
 
 Textbox::Textbox() :
 		RenderObject(6),
-		_firstLineOffset(0),
-		_lineHeight(0),
-		_borderWidth(0),
 		_needsTextRedraw(false),
 		_scrollbar(nullptr),
 		_scrollbarPos(0),
@@ -58,36 +55,11 @@ Textbox::~Textbox() {
 }
 
 void Textbox::init() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("TBOX");
-	chunk->seek(0);
-	Common::Rect scrollbarSrcBounds;
-	readRect(*chunk, scrollbarSrcBounds);
-
-	chunk->seek(0x20);
-	Common::Rect innerBoundingBox;
-	readRect(*chunk, innerBoundingBox);
-	_fullSurface.create(innerBoundingBox.width(), innerBoundingBox.height(), g_nancy->_graphicsManager->getScreenPixelFormat());
-
-	Common::Point scrollbarDefaultPos;
-	scrollbarDefaultPos.x = chunk->readUint16LE();
-	scrollbarDefaultPos.y = chunk->readUint16LE();
-
-	// TVD handles coordinates differently, so we need to nudge scrollbars one pixel to the left
-	if (g_nancy->getGameType() == Nancy::GameType::kGameTypeVampire) {
-		scrollbarDefaultPos.x -= 1;
-	}
-
-	uint16 scrollbarMaxScroll = chunk->readUint16LE();
-
-	_firstLineOffset = chunk->readUint16LE() + 1;
-	_lineHeight = chunk->readUint16LE() + (g_nancy->getGameType() == Nancy::GameType::kGameTypeVampire ? 1 : 0);
-	_borderWidth = chunk->readUint16LE() - 1;
-	_maxWidthDifference = chunk->readUint16LE();
+	TBOX *tbox = g_nancy->_textboxData;
+	assert(tbox);
 
-	chunk->seek(0x1FE, SEEK_SET);
-	_fontID = chunk->readUint16LE();
-
-	_screenPosition = g_nancy->_textboxScreenPosition;
+	moveTo(g_nancy->_bootSummary->textboxScreenPosition);
+	_fullSurface.create(tbox->innerBoundingBox.width(), tbox->innerBoundingBox.height(), g_nancy->_graphicsManager->getScreenPixelFormat());
 
 	Common::Rect outerBoundingBox = _screenPosition;
 	outerBoundingBox.moveTo(0, 0);
@@ -96,7 +68,10 @@ void Textbox::init() {
 	RenderObject::init();
 
 	// zOrder bumped by 1 to avoid overlap with the inventory box curtains in The Vampire Diaries
-	_scrollbar = new Scrollbar(10, scrollbarSrcBounds, scrollbarDefaultPos, scrollbarMaxScroll - scrollbarDefaultPos.y);
+	_scrollbar = new Scrollbar(	10,
+								tbox->scrollbarSrcBounds,
+								tbox->scrollbarDefaultPos,
+								tbox->scrollbarMaxScroll - tbox->scrollbarDefaultPos.y);
 	_scrollbar->init();
 }
 
@@ -142,12 +117,15 @@ void Textbox::handleInput(NancyInput &input) {
 void Textbox::drawTextbox() {
 	using namespace Common;
 
+	TBOX *tbox = g_nancy->_textboxData;
+	assert(tbox);
+
 	_numLines = 0;
 
-	const Font *font = g_nancy->_graphicsManager->getFont(_fontID);
+	const Font *font = g_nancy->_graphicsManager->getFont(tbox->fontID);
 
-	uint maxWidth = _fullSurface.w - _maxWidthDifference - _borderWidth - 2;
-	uint lineDist = _lineHeight + _lineHeight / 4;
+	uint maxWidth = _fullSurface.w - tbox->maxWidthDifference - tbox->borderWidth - 2;
+	uint lineDist = tbox->lineHeight + tbox->lineHeight / 4;
 
 	for (uint lineID = 0; lineID < _textLines.size(); ++lineID) {
 		Common::String currentLine = _textLines[lineID];
@@ -226,7 +204,7 @@ void Textbox::drawTextbox() {
 
 				// Draw the color lines
 				for (uint i = 0; i < wrappedLines.size(); ++i) {
-					font->drawString(&_fullSurface, wrappedLines[i], _borderWidth + horizontalOffset, _firstLineOffset - font->getFontHeight() + _numLines * lineDist, maxWidth, 1);
+					font->drawString(&_fullSurface, wrappedLines[i], tbox->borderWidth + horizontalOffset, tbox->firstLineOffset - font->getFontHeight() + _numLines * lineDist, maxWidth, 1);
 					colorLinesWidth = MAX<int16>(colorLinesWidth, font->getStringWidth(wrappedLines[i]));
 					if (i != wrappedLines.size() - 1) {
 						++_numLines;
@@ -242,15 +220,15 @@ void Textbox::drawTextbox() {
 			font->wordWrap(currentSubstring, maxWidth, wrappedLines, horizontalOffset);
 
 			if (hasHotspot) {
-				hotspot.left = _borderWidth;
-				hotspot.top = _firstLineOffset - font->getFontHeight() + (_numLines + 1 - numColorLines) * lineDist;
-				hotspot.setHeight(MAX<int16>((wrappedLines.size() + numColorLines - 1), 1) * _lineHeight + lineDist);
+				hotspot.left = tbox->borderWidth;
+				hotspot.top = tbox->firstLineOffset - font->getFontHeight() + (_numLines + 1 - numColorLines) * lineDist;
+				hotspot.setHeight(MAX<int16>((wrappedLines.size() + numColorLines - 1), 1) * tbox->lineHeight + lineDist);
 				hotspot.setWidth(0);
 			}
 
 			// Draw the wrapped lines
 			for (uint i = 0; i < wrappedLines.size(); ++i) {
-				font->drawString(&_fullSurface, wrappedLines[i], _borderWidth + (i == 0 ? horizontalOffset : 0), _firstLineOffset - font->getFontHeight() + _numLines * lineDist, maxWidth, 0);
+				font->drawString(&_fullSurface, wrappedLines[i], tbox->borderWidth + (i == 0 ? horizontalOffset : 0), tbox->firstLineOffset - font->getFontHeight() + _numLines * lineDist, maxWidth, 0);
 				if (hasHotspot) {
 					hotspot.setWidth(MAX<int16>(hotspot.width(), font->getStringWidth(wrappedLines[i]) + (i == 0 ? horizontalOffset : 0)));
 				}
@@ -341,12 +319,15 @@ void Textbox::onScrollbarMove() {
 }
 
 uint16 Textbox::getInnerHeight() const {
+	TBOX *tbox = g_nancy->_textboxData;
+	assert(tbox);
+	
 	// These calculations are _almost_ correct, but off by a pixel sometimes
-	uint lineDist = _lineHeight + _lineHeight / 4;
+	uint lineDist = tbox->lineHeight + tbox->lineHeight / 4;
 	if (g_nancy->getGameType() == kGameTypeVampire) {
-		return _numLines * lineDist + _firstLineOffset + (_lastResponseisMultiline ? - _lineHeight / 2 : 1);
+		return _numLines * lineDist + tbox->firstLineOffset + (_lastResponseisMultiline ? - tbox->lineHeight / 2 : 1);
 	} else {
-		return _numLines * lineDist + _firstLineOffset + lineDist / 2 - 1;
+		return _numLines * lineDist + tbox->firstLineOffset + lineDist / 2 - 1;
 	}
 }
 
diff --git a/engines/nancy/ui/textbox.h b/engines/nancy/ui/textbox.h
index 9d81c87423e..ab44c85936a 100644
--- a/engines/nancy/ui/textbox.h
+++ b/engines/nancy/ui/textbox.h
@@ -68,13 +68,7 @@ private:
 	Common::Array<Common::String> _textLines;
 	Common::Array<Common::Rect> _hotspots;
 
-	uint16 _firstLineOffset;
-	uint16 _lineHeight;
-	uint16 _borderWidth;
-	uint16 _maxWidthDifference;
 	uint16 _numLines;
-	uint16 _fontID;
-
 	bool _lastResponseisMultiline;
 
 	bool _needsTextRedraw;
diff --git a/engines/nancy/ui/viewport.cpp b/engines/nancy/ui/viewport.cpp
index 8256d1acac1..eab86e89482 100644
--- a/engines/nancy/ui/viewport.cpp
+++ b/engines/nancy/ui/viewport.cpp
@@ -36,18 +36,12 @@ namespace UI {
 
 // does NOT put the object in a valid state until loadVideo is called
 void Viewport::init() {
-	Common::SeekableReadStream *viewChunk = g_nancy->getBootChunkStream("VIEW");
-	viewChunk->seek(0);
+	moveTo(g_nancy->_viewportData->screenPosition);
 
-	Common::Rect dest;
-	readRect(*viewChunk, dest);
-	viewChunk->skip(16); // skip viewport source rect
-	readRect(*viewChunk, _format1Bounds);
-	readRect(*viewChunk, _format2Bounds);
-
-	_screenPosition = dest;
-
-	setEdgesSize(g_nancy->_verticalEdgesSize, g_nancy->_verticalEdgesSize, g_nancy->_horizontalEdgesSize, g_nancy->_horizontalEdgesSize);
+	setEdgesSize(	g_nancy->_bootSummary->verticalEdgesSize,
+					g_nancy->_bootSummary->verticalEdgesSize,
+					g_nancy->_bootSummary->horizontalEdgesSize,
+					g_nancy->_bootSummary->horizontalEdgesSize);
 
 	RenderObject::init();
 }
@@ -282,16 +276,6 @@ uint16 Viewport::getMaxScroll() const {
 	return _fullFrame.h - _drawSurface.h - (g_nancy->getGameType() == kGameTypeVampire ? 1 : 0);
 }
 
-Common::Rect Viewport::getBoundsByFormat(uint format) const {
-	if (format == 1) {
-		return _format1Bounds;
-	} else if (format == 2) {
-		return _format2Bounds;
-	} else {
-		return Common::Rect();
-	}
-}
-
 // Convert a viewport-space rectangle to screen coordinates
 Common::Rect Viewport::convertViewportToScreen(const Common::Rect &viewportRect) const {
 	Common::Rect ret = convertToScreen(viewportRect);
diff --git a/engines/nancy/ui/viewport.h b/engines/nancy/ui/viewport.h
index 137050c1646..7ed0674179f 100644
--- a/engines/nancy/ui/viewport.h
+++ b/engines/nancy/ui/viewport.h
@@ -73,8 +73,6 @@ public:
 	uint16 getCurVerticalScroll() const { return _drawSurface.getOffsetFromOwner().y; }
 	uint16 getMaxScroll() const;
 
-	Common::Rect getBoundsByFormat(uint format) const; // used by video
-
 	Common::Rect convertViewportToScreen(const Common::Rect &viewportRect) const;
 	Common::Rect convertScreenToViewport(const Common::Rect &viewportRect) const;
 


Commit: e696064615e94ede3ede9c546cd9b7959e8d064a
    https://github.com/scummvm/scummvm/commit/e696064615e94ede3ede9c546cd9b7959e8d064a
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:37+03:00

Commit Message:
NANCY: Implement struct for MAP chunk

Changed paths:
    engines/nancy/enginedata.cpp
    engines/nancy/enginedata.h
    engines/nancy/nancy.cpp
    engines/nancy/nancy.h
    engines/nancy/state/map.cpp
    engines/nancy/state/map.h
    engines/nancy/state/scene.cpp


diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index be7009b624d..9406e932265 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -178,4 +178,94 @@ TBOX::TBOX(Common::SeekableReadStream *chunkStream) {
 	delete chunkStream;
 }
 
+MAP::MAP(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
+	Common::Serializer s(chunkStream, nullptr);
+	s.setVersion(g_nancy->getGameType());
+	uint numLocations = s.getVersion() == kGameTypeVampire ? 7 : 4;
+	uint numMaps = s.getVersion() == kGameTypeVampire ? 4 : 2;
+
+	mapNames.resize(numMaps);
+	for (uint i = 0; i < numMaps; ++i) {
+		readFilename(*chunkStream, mapNames[i]);
+	}
+
+	if (s.getVersion() == kGameTypeVampire) {
+		mapPaletteNames.resize(numMaps);
+		for (uint i = 0; i < numMaps; ++i) {
+			readFilename(*chunkStream, mapPaletteNames[i]);
+		}
+	}
+
+	s.skip(4);
+
+	sounds.resize(numMaps);
+	for (uint i = 0; i < numMaps; ++i) {
+		sounds[i].read(*chunkStream, SoundDescription::kMenu);
+	}
+
+	s.skip(0x20);
+
+	if (s.getVersion() == kGameTypeVampire) {
+		s.syncAsUint16LE(globeFrameTime);
+
+		globeSrcs.resize(8);
+		for (uint i = 0; i < 8; ++i) {
+			readRect(*chunkStream, globeSrcs[i]);
+		}
+
+		readRect(*chunkStream, globeDest);
+	}
+
+	if (s.getVersion() == kGameTypeNancy1) {
+		s.skip(2);
+		readRect(*chunkStream, buttonSrc);
+		readRect(*chunkStream, buttonDest);
+	}
+
+	locations.resize(numLocations);
+	for (uint i = 0; i < numLocations; ++i) {
+		readRect(*chunkStream, locations[i].labelSrc);
+	}
+
+	readRect(*chunkStream, closedLabelSrc);
+
+	if (s.getVersion() == kGameTypeVampire) {
+		readRect(*chunkStream, globeGargoyleSrc);
+		readRect(*chunkStream, globeGargoyleDest);
+	}
+
+	char buf[30];
+
+	for (uint i = 0; i < numLocations; ++i) {
+		s.syncBytes((byte *)buf, 30);
+		buf[29] = '\0';
+		locations[i].description = buf;
+	}
+
+	for (uint i = 0; i < numLocations; ++i) {
+		readRect(*chunkStream, locations[i].hotspot);
+	}
+
+	s.skip(numLocations * 2);
+	s.skip(0x10);
+
+	s.syncAsUint16LE(cursorPosition.x);
+	s.syncAsUint16LE(cursorPosition.y);
+
+	for (uint j = 0; j < 2; ++j) {
+		for (uint i = 0; i < numLocations; ++i) {
+			SceneChangeDescription &sc = locations[i].scenes[j];
+			s.syncAsUint16LE(sc.sceneID);
+			s.syncAsUint16LE(sc.frameID);
+			s.syncAsUint16LE(sc.verticalOffset);
+			s.syncAsUint16LE(sc.paletteID, kGameTypeVampire, kGameTypeVampire);
+		}
+	}
+
+	delete chunkStream;
+}
+
 } // End of namespace Nancy
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index 15aaedd55ea..51d4e0ef696 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -104,6 +104,39 @@ struct TBOX {
 	uint16 fontID;
 };
 
+struct MAP {
+	struct Location {
+		Common::String description;
+		Common::Rect hotspot;
+		SceneChangeDescription scenes[2];
+
+		Common::Rect labelSrc;
+	};
+
+	MAP(Common::SeekableReadStream *chunkStream);
+
+	Common::Array<Common::String> mapNames;
+	Common::Array<Common::String> mapPaletteNames;
+	Common::Array<SoundDescription> sounds;
+
+	// Globe section, TVD only
+	uint16 globeFrameTime;
+	Common::Array<Common::Rect> globeSrcs;
+	Common::Rect globeDest;
+	Common::Rect globeGargoyleSrc;
+	Common::Rect globeGargoyleDest;
+
+	// Button section, nancy1 only
+	Common::Rect buttonSrc;
+	Common::Rect buttonDest;
+
+	Common::Rect closedLabelSrc;
+
+	Common::Array<Location> locations;
+
+	Common::Point cursorPosition;
+};
+
 } // End of namespace Nancy
 
 #endif // NANCY_ENGINEDATA_H
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 0b86123907e..726d3040812 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -73,6 +73,7 @@ NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) :
 	_viewportData = nullptr;
 	_inventoryData = nullptr;
 	_textboxData = nullptr;
+	_mapData = nullptr;
 }
 
 NancyEngine::~NancyEngine() {
@@ -88,6 +89,7 @@ NancyEngine::~NancyEngine() {
 	delete _viewportData;
 	delete _inventoryData;
 	delete _textboxData;
+	delete _mapData;
 }
 
 NancyEngine *NancyEngine::create(GameType type, OSystem *syst, const NancyGameDescription *gd) {
@@ -346,6 +348,11 @@ void NancyEngine::bootGameEngine() {
 	_inventoryData = new INV(boot->getChunkStream("INV"));
 	_textboxData = new TBOX(boot->getChunkStream("TBOX"));
 
+	auto *chunkStream = boot->getChunkStream("MAP");
+	if (chunkStream) {
+		_mapData = new MAP(chunkStream);
+	}
+
 	// Load all data chunks found in BOOT. These get used in a lot of places
 	// across the engine, so we always keep them in memory
 	Common::Array<Common::String> bootChunkNames;
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index ea3ce053c9b..de279a4f053 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -119,6 +119,7 @@ public:
 	VIEW *_viewportData;
 	INV *_inventoryData;
 	TBOX *_textboxData;
+	MAP *_mapData;
 
 protected:
 	Common::Error run() override;
diff --git a/engines/nancy/state/map.cpp b/engines/nancy/state/map.cpp
index 389a78f9b03..fee4034797a 100644
--- a/engines/nancy/state/map.cpp
+++ b/engines/nancy/state/map.cpp
@@ -53,7 +53,10 @@ Map::Map() : _state(kInit),
 			_pickedLocationID(-1),
 			_label(7),
 			_closedLabel(7),
-			_background(0) {}
+			_background(0) {
+	mapData = g_nancy->_mapData;
+	assert(mapData);
+}
 
 void Map::process() {
 	switch (_state) {
@@ -78,6 +81,10 @@ void Map::onStateExit() {
 	_state = kLoad;
 }
 
+const SoundDescription &Map::getSound() {
+	return mapData->sounds[_mapID];
+}
+
 void Map::load() {
 	// Get a screenshot of the Scene state and set it as the background
 	// to allow the labels to clear when not hovered
@@ -100,12 +107,12 @@ void Map::setLabel(int labelID) {
 		_label.setVisible(false);
 		_closedLabel.setVisible(false);
 	} else {
-		_label.moveTo(_locations[labelID].labelDest);
-		_label._drawSurface.create(g_nancy->_graphicsManager->_object0, _locations[labelID].labelSrc);
+		_label.moveTo(_locationLabelDests[labelID]);
+		_label._drawSurface.create(g_nancy->_graphicsManager->_object0, mapData->locations[labelID].labelSrc);
 		_label.setVisible(true);
 		_label.setTransparent(true);
 
-		if (!_locations[labelID].isActive) {
+		if (!_activeLocations[labelID]) {
 			_closedLabel.setVisible(true);
 		}
 	}
@@ -156,84 +163,26 @@ void TVDMap::init() {
 	_ornaments.init();
 	_globe.init();
 
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("MAP");
-	Common::Rect textboxScreenPosition =g_nancy->_bootSummary->textboxScreenPosition;
-
-	if (chunk) {
-		chunk->seek(0);
-
-		_mapNames.resize(4);
-		for (uint i = 0; i < 4; ++i) {
-			readFilename(*chunk, _mapNames[i]);
-		}
-
-		_mapPalettes.resize(4);
-		for (uint i = 0; i < 4; ++i) {
-			readFilename(*chunk, _mapPalettes[i]);
-		}
-
-		chunk->skip(4);
-
-		_mapSounds.resize(4);
-		for (uint i = 0; i < 4; ++i) {
-			_mapSounds[i].read(*chunk, SoundDescription::kMenu);
-		}
-
-		chunk->seek(0x1E6);
-		Common::Rect closedLabelSrc;
-		readRect(*chunk, closedLabelSrc);
-
-		_closedLabel._drawSurface.create(g_nancy->_graphicsManager->_object0, closedLabelSrc);
+	Common::Rect textboxScreenPosition = g_nancy->_bootSummary->textboxScreenPosition;
+	_closedLabel._drawSurface.create(g_nancy->_graphicsManager->_object0, mapData->closedLabelSrc);
 
-		Common::Rect newScreenRect;
+	Common::Rect closedScreenRect;
+	closedScreenRect.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - mapData->closedLabelSrc.width()) / 2);
+	closedScreenRect.right = closedScreenRect.left + mapData->closedLabelSrc.width();
+	closedScreenRect.bottom = textboxScreenPosition.bottom - 10;
+	closedScreenRect.top = closedScreenRect.bottom - mapData->closedLabelSrc.height();
 
-		newScreenRect.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - closedLabelSrc.width()) / 2);
-		newScreenRect.right = newScreenRect.left + closedLabelSrc.width();
-		newScreenRect.bottom = textboxScreenPosition.bottom - 10;
-		newScreenRect.top = newScreenRect.bottom - closedLabelSrc.height();
+	_closedLabel.moveTo(closedScreenRect);
+	_closedLabel.setTransparent(true);
 
-		_closedLabel.moveTo(newScreenRect);
-		_closedLabel.setTransparent(true);
+	_activeLocations.resize(7, true);
+	_locationLabelDests.resize(7);
 
-		char buf[30];
-		_locations.resize(7);
-		for (uint i = 0; i < 7; ++i) {
-			Location &loc = _locations[i];
-
-			chunk->seek(0x226 + i * 30);
-			chunk->read(buf, 30);
-			buf[29] = '\0';
-			loc.description = buf;
-
-			chunk->seek(0x2F8 + i * 16);
-			readRect(*chunk, loc.hotspot);
-
-			loc.scenes.resize(2);
-			for (uint j = 0; j < 2; ++j) {
-				SceneChangeDescription &sc = loc.scenes[j];
-				chunk->seek(0x38A + (8 * i) + (56 * j));
-				sc.sceneID = chunk->readUint16LE();
-				sc.frameID = chunk->readUint16LE();
-				sc.verticalOffset = chunk->readUint16LE();
-				sc.paletteID = chunk->readUint16LE();
-			}
-
-			chunk->seek(0x186 + i * 16);
-			readRect(*chunk, loc.labelSrc);
-
-			Common::Rect closedScreenRect = _closedLabel.getScreenPosition();
-
-			loc.labelDest.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - loc.labelSrc.width()) / 2);
-			loc.labelDest.right = loc.labelDest.left + loc.labelSrc.width();
-			loc.labelDest.bottom = closedScreenRect.bottom - ((closedScreenRect.bottom - loc.labelSrc.height() - textboxScreenPosition.top) / 2) - 10;
-			loc.labelDest.top = loc.labelDest.bottom - loc.labelSrc.height();
-
-			loc.isActive = true;
-		}
-
-		chunk->seek(0x386);
-		_cursorPosition.x = chunk->readUint16LE();
-		_cursorPosition.y = chunk->readUint16LE();
+	for (uint i = 0; i < 7; ++i) {
+		_locationLabelDests[i].left = textboxScreenPosition.left + ((textboxScreenPosition.width() - mapData->locations[i].labelSrc.width()) / 2);
+		_locationLabelDests[i].right = _locationLabelDests[i].left + mapData->locations[i].labelSrc.width();
+		_locationLabelDests[i].bottom = closedScreenRect.bottom - ((closedScreenRect.bottom - mapData->locations[i].labelSrc.height() - textboxScreenPosition.top) / 2) - 10;
+		_locationLabelDests[i].top = _locationLabelDests[i].bottom - mapData->locations[i].labelSrc.height();
 	}
 
 	_state = kLoad;
@@ -258,7 +207,7 @@ void TVDMap::load() {
 		}
 	}
 
-	_viewport.loadVideo(_mapNames[_mapID], _mapPalettes[_mapID]);
+	_viewport.loadVideo(mapData->mapNames[_mapID], mapData->mapPaletteNames[_mapID]);
 
 	g_nancy->_cursorManager->setCursorItemID(-1);
 
@@ -278,8 +227,7 @@ void TVDMap::load() {
 
 void TVDMap::onStateExit() {
 	if (_pickedLocationID != -1) {
-		auto &loc = _locations[_pickedLocationID];
-		NancySceneState.changeScene(loc.scenes[NancySceneState.getPlayerTOD() == kPlayerDay ? 0 : 1]);
+		NancySceneState.changeScene(mapData->locations[_pickedLocationID].scenes[NancySceneState.getPlayerTOD() == kPlayerDay ? 0 : 1]);
 
 		g_nancy->_sound->playSound("BUOK");
 	} else {
@@ -302,12 +250,11 @@ void TVDMap::run() {
 
 		_globe.handleInput(input);
 
-		for (uint i = 0; i < _locations.size(); ++i) {
-			auto &loc = _locations[i];
-			if (_viewport.convertToScreen(loc.hotspot).contains(input.mousePos)) {
+		for (uint i = 0; i < 7; ++i) {
+			if (_viewport.convertToScreen(mapData->locations[i].hotspot).contains(input.mousePos)) {
 				setLabel(i);
 
-				if (loc.isActive){
+				if (_activeLocations[i]){
 					g_nancy->_cursorManager->setCursorType(CursorManager::kHotspot);
 
 					if (input.input & NancyInput::kLeftMouseButtonUp) {
@@ -330,35 +277,18 @@ void TVDMap::registerGraphics() {
 }
 
 void TVDMap::MapGlobe::init() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("MAP");
-
-	if (chunk) {
-		chunk->seek(0xf4);
-
-		_frameTime = chunk->readUint16LE();
-
-		_srcRects.resize(8);
-		for (uint i = 0; i < 8; ++i) {
-			readRect(*chunk, _srcRects[i]);
-		}
-
-		Common::Rect screenDest;
-		readRect(*chunk, screenDest);
-		moveTo(screenDest);
+	moveTo(_owner->mapData->globeDest);
 
-		Common::Rect gargoyleSrc, gargoyleDest;
-		chunk->skip(0x80);
-		readRect(*chunk, gargoyleSrc);
-		readRect(*chunk, gargoyleDest);
+	_frameTime = _owner->mapData->globeFrameTime;
+	_srcRects = _owner->mapData->globeSrcs;
 
-		_gargoyleEyes._drawSurface.create(g_nancy->_graphicsManager->_object0, gargoyleSrc);
-		_gargoyleEyes.moveTo(gargoyleDest);
-		_gargoyleEyes.setTransparent(true);
-		_gargoyleEyes.setVisible(false);
+	_gargoyleEyes._drawSurface.create(g_nancy->_graphicsManager->_object0, _owner->mapData->globeGargoyleSrc);
+	_gargoyleEyes.moveTo(_owner->mapData->globeGargoyleDest);
+	_gargoyleEyes.setTransparent(true);
+	_gargoyleEyes.setVisible(false);
 
-		_alwaysHighlightCursor = false;
-		_hotspot = _screenPosition;
-	}
+	_alwaysHighlightCursor = false;
+	_hotspot = _screenPosition;
 
 	AnimatedButton::init();
 }
@@ -378,7 +308,7 @@ void TVDMap::MapGlobe::onTrigger() {
 		_gargoyleEyes.setVisible(true);
 		_owner->_viewport.setVisible(true);
 		_owner->_viewport.playVideo();
-		g_system->warpMouse(_owner->_cursorPosition.x, _owner->_cursorPosition.y);
+		g_system->warpMouse(_owner->mapData->cursorPosition.x, _owner->mapData->cursorPosition.y);
 		g_nancy->setMouseEnabled(true);
 	} else {
 		_owner->_state = kExit;
@@ -396,84 +326,31 @@ void Nancy1Map::init() {
 	_viewport.init();
 	_label.init();
 
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("MAP");
 	Common::Rect textboxScreenPosition = NancySceneState.getTextbox().getScreenPosition();
+	_closedLabel._drawSurface.create(g_nancy->_graphicsManager->_object0, mapData->closedLabelSrc);
 
-	if (chunk) {
-		chunk->seek(0);
-
-		_mapNames.resize(2);
-		for (uint i = 0; i < 2; ++i) {
-			readFilename(*chunk, _mapNames[i]);
-		}
-
-		chunk->skip(4);
-
-		_mapSounds.resize(2);
-		for (uint i = 0; i < 2; ++i) {
-			_mapSounds[i].read(*chunk, SoundDescription::kMenu);
-		}
-
-		Common::Rect buttonSrc, buttonDest;
-		chunk->seek(0x7A, SEEK_SET);
-		readRect(*chunk, buttonSrc);
-		readRect(*chunk, buttonDest);
-
-		chunk->seek(0xDA, SEEK_SET);
-		Common::Rect closedLabelSrc;
-		readRect(*chunk, closedLabelSrc);
-
-		_closedLabel._drawSurface.create(g_nancy->_graphicsManager->_object0, closedLabelSrc);
-
-		Common::Rect newScreenRect;
+	Common::Rect closedScreenRect;
+	closedScreenRect.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - mapData->closedLabelSrc.width()) / 2);
+	closedScreenRect.right = closedScreenRect.left + mapData->closedLabelSrc.width() - 1;
+	closedScreenRect.bottom = textboxScreenPosition.bottom - 11;
+	closedScreenRect.top = closedScreenRect.bottom - mapData->closedLabelSrc.height() + 1;
 
-		newScreenRect.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - closedLabelSrc.width()) / 2);
-		newScreenRect.right = newScreenRect.left + closedLabelSrc.width() - 1;
-		newScreenRect.bottom = textboxScreenPosition.bottom - 11;
-		newScreenRect.top = newScreenRect.bottom - closedLabelSrc.height() + 1;
+	_closedLabel.moveTo(closedScreenRect);
 
-		_closedLabel.moveTo(newScreenRect);
+	_activeLocations.resize(4, true);
+	_locationLabelDests.resize(4);
 
-		_button = new UI::Button(9, g_nancy->_graphicsManager->_object0, buttonSrc, buttonDest);
-		_button->init();
-		_button->setVisible(true);
-
-		char buf[30];
-		_locations.resize(4);
-		for (uint i = 0; i < 4; ++i) {
-			Location &loc = _locations[i];
-
-			chunk->seek(0xEA + i * 16);
-			chunk->read(buf, 30);
-			buf[29] = '\0';
-			loc.description = buf;
-
-			chunk->seek(0x162 + i * 16);
-			readRect(*chunk, loc.hotspot);
-
-			loc.scenes.resize(2);
-			for (uint j = 0; j < 2; ++j) {
-				SceneChangeDescription &sc = loc.scenes[j];
-				chunk->seek(0x1BE + (6 * i) + (24 * j));
-				sc.sceneID = chunk->readUint16LE();
-				sc.frameID = chunk->readUint16LE();
-				sc.verticalOffset = chunk->readUint16LE();
-			}
-
-			chunk->seek(0x9A + i * 16);
-			readRect(*chunk, loc.labelSrc);
-
-			Common::Rect closedScreenRect = _closedLabel.getScreenPosition();
-
-			loc.labelDest.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - loc.labelSrc.width()) / 2);
-			loc.labelDest.right = loc.labelDest.left + loc.labelSrc.width() - 1;
-			loc.labelDest.bottom = closedScreenRect.bottom - ((closedScreenRect.bottom - loc.labelSrc.height() - textboxScreenPosition.top) / 2) - 11;
-			loc.labelDest.top = loc.labelDest.bottom - loc.labelSrc.height() + 1;
-
-			loc.isActive = true;
-		}
+	for (uint i = 0; i < 4; ++i) {
+		_locationLabelDests[i].left = textboxScreenPosition.left + ((textboxScreenPosition.width() - mapData->locations[i].labelSrc.width()) / 2);
+		_locationLabelDests[i].right = _locationLabelDests[i].left + mapData->locations[i].labelSrc.width() - 1;
+		_locationLabelDests[i].bottom = closedScreenRect.bottom - ((closedScreenRect.bottom - mapData->locations[i].labelSrc.height() - textboxScreenPosition.top) / 2) - 11;
+		_locationLabelDests[i].top = _locationLabelDests[i].bottom - mapData->locations[i].labelSrc.height() + 1;
 	}
 
+	_button = new UI::Button(9, g_nancy->_graphicsManager->_object0, mapData->buttonSrc, mapData->buttonDest);
+	_button->init();
+	_button->setVisible(true);
+
 	_state = kLoad;
 }
 
@@ -485,20 +362,21 @@ void Nancy1Map::load() {
 		NancySceneState.getEventFlag(95, kEvOccurred)) {	// Connie chickens
 		_mapID = 1;		// Night
 
-		_locations[1].isActive = _locations[3].isActive = false;
+		_activeLocations[1] = _activeLocations[3] = false;
 	} else {
 		_mapID = 0;		// Day
 	}
 
-	_viewport.loadVideo(_mapNames[_mapID]);
+	_viewport.loadVideo(mapData->mapNames[_mapID]);
 
 	setLabel(-1);
 	g_nancy->_cursorManager->setCursorItemID(-1);
+	g_system->warpMouse(mapData->cursorPosition.x, mapData->cursorPosition.y);
 
 	if (!g_nancy->_sound->isSoundPlaying(getSound())) {
 		g_nancy->_sound->loadSound(getSound());
 	}
-
+		
 	registerGraphics();
 	_state = kRun;
 }
@@ -520,12 +398,11 @@ void Nancy1Map::run() {
 		return;
 	}
 
-	for (uint i = 0; i < _locations.size(); ++i) {
-		auto &loc = _locations[i];
-		if (_viewport.convertToScreen(loc.hotspot).contains(input.mousePos)) {
+	for (uint i = 0; i < 4; ++i) {
+		if (_viewport.convertToScreen(mapData->locations[i].hotspot).contains(input.mousePos)) {
 			setLabel(i);
 
-			if (loc.isActive){
+			if (_activeLocations[i]){
 				g_nancy->_cursorManager->setCursorType(CursorManager::kHotspotArrow);
 
 				if (input.input & NancyInput::kLeftMouseButtonUp) {
@@ -546,8 +423,7 @@ void Nancy1Map::registerGraphics() {
 
 void Nancy1Map::onStateExit() {
 	if (_pickedLocationID != -1) {
-		auto &loc = _locations[_pickedLocationID];
-		NancySceneState.changeScene(loc.scenes[_mapID]);
+		NancySceneState.changeScene(mapData->locations[_pickedLocationID].scenes[_mapID]);
 
 		g_nancy->_sound->playSound("BUOK");
 	}
diff --git a/engines/nancy/state/map.h b/engines/nancy/state/map.h
index b0b6a1ff76e..6313dd58134 100644
--- a/engines/nancy/state/map.h
+++ b/engines/nancy/state/map.h
@@ -51,7 +51,7 @@ public:
 	void process() override;
 	void onStateExit() override;
 
-	const SoundDescription &getSound() { return _mapSounds[_mapID]; }
+	const SoundDescription &getSound();
 
 protected:
 	class MapViewport : public Nancy::RenderObject {
@@ -70,17 +70,6 @@ protected:
 		AVFDecoder _decoder;
 	};
 
-	struct Location {
-		Common::String description;
-
-		bool isActive = false;
-		Common::Rect hotspot;
-		Common::Array<SceneChangeDescription> scenes;
-
-		Common::Rect labelSrc;
-		Common::Rect labelDest;
-	};
-
 	virtual void init() = 0;
 	virtual void load();
 	virtual void run() = 0;
@@ -88,9 +77,7 @@ protected:
 
 	void setLabel(int labelID);
 
-	Common::Array<Common::String> _mapNames;
-	Common::Array<Common::String> _mapPalettes;
-	Common::Array<SoundDescription> _mapSounds;
+	MAP *mapData;
 
 	MapViewport _viewport;
 	RenderObject _label;
@@ -100,7 +87,8 @@ protected:
 	State _state;
 	uint16 _mapID;
 	int16 _pickedLocationID;
-	Common::Array<Location> _locations;
+	Common::Array<bool> _activeLocations;
+	Common::Array<Common::Rect> _locationLabelDests;
 };
 
 class TVDMap : public Map {
@@ -135,8 +123,6 @@ private:
 
 	MapGlobe _globe;
 	UI::ViewportOrnaments _ornaments;
-
-	Common::Point _cursorPosition;
 };
 
 class Nancy1Map : public Map {
@@ -153,7 +139,6 @@ private:
 	void onStateExit() override;
 
 	UI::Button *_button;
-	//bool _mapButtonClicked;
 };
 
 #define NancyMapState Nancy::State::Map::instance()
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index be33aad1750..e7d5ac03bb8 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -746,19 +746,13 @@ void Scene::initStaticData() {
 	
 	if (g_nancy->getGameType() == kGameTypeVampire) {
 		_mapHotspot = bsum->mapButtonHotspot;
+	} else if (g_nancy->_mapData) {
+		_mapHotspot = g_nancy->_mapData->buttonDest;
 	}
 
 	_menuButton = new UI::Button(5, g_nancy->_graphicsManager->_object0, bsum->menuButtonSrc, bsum->menuButtonDest);
 	_helpButton = new UI::Button(5, g_nancy->_graphicsManager->_object0, bsum->helpButtonSrc, bsum->helpButtonDest);
 	g_nancy->setMouseEnabled(true);
-
-	if (g_nancy->getGameType() == kGameTypeNancy1) {
-		chunk = g_nancy->getBootChunkStream("MAP");
-		if (chunk) {
-			chunk->seek(0x8A);
-			readRect(*chunk, _mapHotspot);
-		}
-	}
 	
 	// Init ornaments and clock (TVD only)
 	if (g_nancy->getGameType() == kGameTypeVampire) {


Commit: 6a873a0013cfc5bc2743b2d6a59cd804c0eda53f
    https://github.com/scummvm/scummvm/commit/6a873a0013cfc5bc2743b2d6a59cd804c0eda53f
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:38+03:00

Commit Message:
NANCY: Fix BSUM loading for nancy2 and up

Changed paths:
    engines/nancy/enginedata.cpp


diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index 9406e932265..507e43d0de7 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -39,7 +39,7 @@ BSUM::BSUM(Common::SeekableReadStream *chunkStream) {
 	
 	s.skip(0x17, kGameTypeVampire, kGameTypeVampire);
 	s.skip(0x49, kGameTypeNancy1, kGameTypeNancy1);
-	s.skip(0xF7, kGameTypeNancy2, kGameTypeNancy3);
+	s.skip(0x43, kGameTypeNancy2, kGameTypeNancy3);
 	s.syncAsUint16LE(firstScene.sceneID);
 	s.skip(0xC, kGameTypeVampire, kGameTypeVampire); // Palette name + unknown 2 bytes
 	s.syncAsUint16LE(firstScene.frameID);


Commit: 74ee83c9e171a1bcf2d9aa337d9070540ec4adb7
    https://github.com/scummvm/scummvm/commit/74ee83c9e171a1bcf2d9aa337d9070540ec4adb7
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:39+03:00

Commit Message:
NANCY: Change cursor data loading

Made CursorManager::init() take the CURS chunk as an argument,
and changed it so it's more readable.

Changed paths:
    engines/nancy/cursor.cpp
    engines/nancy/cursor.h
    engines/nancy/nancy.cpp


diff --git a/engines/nancy/cursor.cpp b/engines/nancy/cursor.cpp
index 1e0d9774e34..860183d8957 100644
--- a/engines/nancy/cursor.cpp
+++ b/engines/nancy/cursor.cpp
@@ -29,24 +29,25 @@
 
 namespace Nancy {
 
-void CursorManager::init() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("CURS");
-	chunk->seek(0);
+void CursorManager::init(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
 	uint numCursors = g_nancy->getStaticData().numNonItemCursors + g_nancy->getStaticData().numItems * 4;
-	_cursors.reserve(numCursors);
+	_cursors.resize(numCursors);
+
+	for (uint i = 0; i < numCursors; ++i) {
+		readRect(*chunkStream, _cursors[i].bounds);
+	}
+
 	for (uint i = 0; i < numCursors; ++i) {
-		_cursors.push_back(Cursor());
-		chunk->seek(i * 16, SEEK_SET);
-		Cursor &cur = _cursors.back();
-		readRect(*chunk, cur.bounds);
-		chunk->seek(numCursors * 16 + i * 8, SEEK_SET);
-		cur.hotspot.x = chunk->readUint32LE();
-		cur.hotspot.y = chunk->readUint32LE();
+		_cursors[i].hotspot.x = chunkStream->readUint32LE();
+		_cursors[i].hotspot.y = chunkStream->readUint32LE();
 	}
 
-	readRect(*chunk, _primaryVideoInactiveZone);
-	_primaryVideoInitialPos.x = chunk->readUint16LE();
-	_primaryVideoInitialPos.y = chunk->readUint16LE();
+	readRect(*chunkStream, _primaryVideoInactiveZone);
+	_primaryVideoInitialPos.x = chunkStream->readUint16LE();
+	_primaryVideoInitialPos.y = chunkStream->readUint16LE();
 
 	g_nancy->_resource->loadImage(g_nancy->_inventoryData->inventoryCursorsImageName, _invCursorsSurface);
 
@@ -54,6 +55,8 @@ void CursorManager::init() {
 	showCursor(false);
 
 	_isInitialized = true;
+	
+	delete chunkStream;
 }
 
 void CursorManager::setCursor(CursorType type, int16 itemID) {
diff --git a/engines/nancy/cursor.h b/engines/nancy/cursor.h
index 397b7a205bc..4cbb3578afe 100644
--- a/engines/nancy/cursor.h
+++ b/engines/nancy/cursor.h
@@ -42,7 +42,7 @@ public:
 		_curCursorType(kNormal),
 		_curCursorID(0) {}
 
-	void init();
+	void init(Common::SeekableReadStream *chunkStream);
 
 	void setCursor(CursorType type, int16 itemID);
 	void setCursorType(CursorType type);
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 726d3040812..6a2c2be2784 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -348,6 +348,8 @@ void NancyEngine::bootGameEngine() {
 	_inventoryData = new INV(boot->getChunkStream("INV"));
 	_textboxData = new TBOX(boot->getChunkStream("TBOX"));
 
+	_cursorManager->init(boot->getChunkStream("CURS"));
+
 	auto *chunkStream = boot->getChunkStream("MAP");
 	if (chunkStream) {
 		_mapData = new MAP(chunkStream);
@@ -364,10 +366,9 @@ void NancyEngine::bootGameEngine() {
 
 	_sound->loadCommonSounds();
 
-	delete boot;
-
 	_graphicsManager->init();
-	_cursorManager->init();
+
+	delete boot;
 }
 
 State::State *NancyEngine::getStateObject(NancyState::NancyState state) const {


Commit: 7abdf5c126b8584944014196d965199616489d1a
    https://github.com/scummvm/scummvm/commit/7abdf5c126b8584944014196d965199616489d1a
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:42+03:00

Commit Message:
NANCY: Add list of image chunks

Changed paths:
    engines/nancy/enginedata.cpp
    engines/nancy/enginedata.h
    engines/nancy/graphics.cpp
    engines/nancy/nancy.cpp
    engines/nancy/nancy.h
    engines/nancy/state/logo.cpp
    engines/nancy/state/scene.cpp


diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index 507e43d0de7..e74349e30b5 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -268,4 +268,15 @@ MAP::MAP(Common::SeekableReadStream *chunkStream) {
 	delete chunkStream;
 }
 
+ImageChunk::ImageChunk(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
+	readFilename(*chunkStream, imageName);
+	width = chunkStream->readUint16LE();
+	height = chunkStream->readUint16LE();
+
+	delete chunkStream;
+}
+
 } // End of namespace Nancy
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index 51d4e0ef696..efd7e318a23 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -137,6 +137,15 @@ struct MAP {
 	Common::Point cursorPosition;
 };
 
+struct ImageChunk {
+	ImageChunk() : width(0), height(0) {}
+	ImageChunk(Common::SeekableReadStream *chunkStream);
+
+	Common::String imageName;
+	uint16 width;
+	uint16 height;
+};
+
 } // End of namespace Nancy
 
 #endif // NANCY_ENGINEDATA_H
diff --git a/engines/nancy/graphics.cpp b/engines/nancy/graphics.cpp
index 0344a7171f4..11ae02ffb00 100644
--- a/engines/nancy/graphics.cpp
+++ b/engines/nancy/graphics.cpp
@@ -43,10 +43,7 @@ void GraphicsManager::init() {
 	_screen.setTransparentColor(getTransColor());
 	_screen.clear();
 
-	Common::SeekableReadStream *ob = g_nancy->getBootChunkStream("OB0");
-	ob->seek(0);
-
-	g_nancy->_resource->loadImage(ob->readString(), _object0);
+	g_nancy->_resource->loadImage(g_nancy->_imageChunks["OB0"].imageName, _object0);
 
 	loadFonts();
 }
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 6a2c2be2784..f7f50b4ee83 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -355,6 +355,11 @@ void NancyEngine::bootGameEngine() {
 		_mapData = new MAP(chunkStream);
 	}
 
+	// For now we ignore the potential for more than one of each of these
+	_imageChunks.setVal("OB0", boot->getChunkStream("OB0"));
+	_imageChunks.setVal("FR0", boot->getChunkStream("FR0"));
+	_imageChunks.setVal("LG0", boot->getChunkStream("LG0"));
+
 	// Load all data chunks found in BOOT. These get used in a lot of places
 	// across the engine, so we always keep them in memory
 	Common::Array<Common::String> bootChunkNames;
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index de279a4f053..7abd0c38f97 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -121,6 +121,8 @@ public:
 	TBOX *_textboxData;
 	MAP *_mapData;
 
+	Common::HashMap<Common::String, ImageChunk> _imageChunks;
+
 protected:
 	Common::Error run() override;
 	void pauseEngineIntern(bool pause) override;
diff --git a/engines/nancy/state/logo.cpp b/engines/nancy/state/logo.cpp
index 0b4c74a0cda..06ec5283d8e 100644
--- a/engines/nancy/state/logo.cpp
+++ b/engines/nancy/state/logo.cpp
@@ -55,10 +55,8 @@ void Logo::onStateExit() {
 }
 
 void Logo::init() {
-	Common::SeekableReadStream *lg = g_nancy->getBootChunkStream("LG0");
-	lg->seek(0);
 
-	_logoImage.init(lg->readString());
+	_logoImage.init(g_nancy->_imageChunks["LG0"].imageName);
 	_logoImage.registerGraphics();
 
 	_state = kStartSound;
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index e7d5ac03bb8..ced0924aac2 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -728,14 +728,7 @@ void Scene::handleInput() {
 }
 
 void Scene::initStaticData() {
-	Common::SeekableReadStream *chunk;
-
-	chunk = g_nancy->getBootChunkStream("FR0");
-	chunk->seek(0);
-	if (chunk) {
-		_frame.init(chunk->readString());
-	}
-
+	_frame.init(g_nancy->_imageChunks["FR0"].imageName);
 	_viewport.init();
 	_textbox.init();
 	_inventoryBox.init();


Commit: 812ec1acb3cd0b0b0bd3d545fea317f740280d8b
    https://github.com/scummvm/scummvm/commit/812ec1acb3cd0b0b0bd3d545fea317f740280d8b
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:43+03:00

Commit Message:
NANCY: Implement structs for HELP, CRED and HINT chunks

Changed paths:
    engines/nancy/enginedata.cpp
    engines/nancy/enginedata.h
    engines/nancy/nancy.cpp
    engines/nancy/nancy.h
    engines/nancy/state/credits.cpp
    engines/nancy/state/credits.h
    engines/nancy/state/help.cpp
    engines/nancy/state/scene.cpp


diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index e74349e30b5..a04d4dcf593 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -268,6 +268,61 @@ MAP::MAP(Common::SeekableReadStream *chunkStream) {
 	delete chunkStream;
 }
 
+HELP::HELP(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
+	readFilename(*chunkStream, imageName);
+
+	chunkStream->skip(20);
+	buttonDest.left = chunkStream->readUint16LE();
+	buttonDest.top = chunkStream->readUint16LE();
+	buttonDest.right = chunkStream->readUint16LE();
+	buttonDest.bottom = chunkStream->readUint16LE();
+	buttonSrc.left = chunkStream->readUint16LE();
+	buttonSrc.top = chunkStream->readUint16LE();
+	buttonSrc.right = chunkStream->readUint16LE();
+	buttonSrc.bottom = chunkStream->readUint16LE();
+
+	delete chunkStream;
+}
+
+CRED::CRED(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	bool isVampire = g_nancy->getGameType() == kGameTypeVampire;
+	chunkStream->seek(0);
+
+	readFilename(*chunkStream, imageName);
+
+	textNames.resize(isVampire ? 7 : 1);
+	for (Common::String &str : textNames) {
+		readFilename(*chunkStream, str);
+	}
+
+	chunkStream->skip(0x20);
+	readRect(*chunkStream, textScreenPosition);
+	chunkStream->skip(0x10);
+
+	updateTime = chunkStream->readUint16LE();
+	pixelsToScroll = chunkStream->readUint16LE();
+	sound.read(*chunkStream, SoundDescription::kMenu);
+
+	delete chunkStream;
+}
+
+HINT::HINT(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
+	numHints.resize(chunkStream->size());
+	for (uint i = 0; i < chunkStream->size(); ++i) {
+		numHints[i] = chunkStream->readByte();
+	}
+
+	delete chunkStream;
+}
+
 ImageChunk::ImageChunk(Common::SeekableReadStream *chunkStream) {
 	assert(chunkStream);
 
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index efd7e318a23..18060c5c522 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -137,6 +137,31 @@ struct MAP {
 	Common::Point cursorPosition;
 };
 
+struct HELP {
+	HELP(Common::SeekableReadStream *chunkStream);
+
+	Common::String imageName;
+	Common::Rect buttonSrc;
+	Common::Rect buttonDest;
+};
+
+struct CRED {
+	CRED(Common::SeekableReadStream *chunkStream);
+
+	Common::String imageName;
+	Common::Array<Common::String> textNames;
+	Common::Rect textScreenPosition;
+	uint16 updateTime;
+	uint16 pixelsToScroll;
+	SoundDescription sound;
+};
+
+struct HINT {
+	HINT(Common::SeekableReadStream *chunkStream);
+
+	Common::Array<uint16> numHints;
+};
+
 struct ImageChunk {
 	ImageChunk() : width(0), height(0) {}
 	ImageChunk(Common::SeekableReadStream *chunkStream);
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index f7f50b4ee83..0f0cdf626ef 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -74,6 +74,9 @@ NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) :
 	_inventoryData = nullptr;
 	_textboxData = nullptr;
 	_mapData = nullptr;
+	_helpData = nullptr;
+	_creditsData = nullptr;
+	_hintData = nullptr;
 }
 
 NancyEngine::~NancyEngine() {
@@ -90,6 +93,9 @@ NancyEngine::~NancyEngine() {
 	delete _inventoryData;
 	delete _textboxData;
 	delete _mapData;
+	delete _helpData;
+	delete _creditsData;
+	delete _hintData;
 }
 
 NancyEngine *NancyEngine::create(GameType type, OSystem *syst, const NancyGameDescription *gd) {
@@ -347,6 +353,8 @@ void NancyEngine::bootGameEngine() {
 	_viewportData = new VIEW(boot->getChunkStream("VIEW"));
 	_inventoryData = new INV(boot->getChunkStream("INV"));
 	_textboxData = new TBOX(boot->getChunkStream("TBOX"));
+	_helpData = new HELP(boot->getChunkStream("HELP"));
+	_creditsData = new CRED(boot->getChunkStream("CRED"));
 
 	_cursorManager->init(boot->getChunkStream("CURS"));
 
@@ -355,6 +363,11 @@ void NancyEngine::bootGameEngine() {
 		_mapData = new MAP(chunkStream);
 	}
 
+	chunkStream = boot->getChunkStream("HINT");
+	if (chunkStream) {
+		_hintData = new HINT(chunkStream);
+	}
+
 	// For now we ignore the potential for more than one of each of these
 	_imageChunks.setVal("OB0", boot->getChunkStream("OB0"));
 	_imageChunks.setVal("FR0", boot->getChunkStream("FR0"));
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index 7abd0c38f97..5221af5749a 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -120,6 +120,9 @@ public:
 	INV *_inventoryData;
 	TBOX *_textboxData;
 	MAP *_mapData;
+	HELP *_helpData;
+	CRED *_creditsData;
+	HINT *_hintData;
 
 	Common::HashMap<Common::String, ImageChunk> _imageChunks;
 
diff --git a/engines/nancy/state/credits.cpp b/engines/nancy/state/credits.cpp
index 476eb9eb26f..df0b9ba7593 100644
--- a/engines/nancy/state/credits.cpp
+++ b/engines/nancy/state/credits.cpp
@@ -48,27 +48,11 @@ void Credits::process() {
 }
 
 void Credits::init() {
-	bool isVampire = g_nancy->getGameType() == kGameTypeVampire;
-	Common::SeekableReadStream *cred = g_nancy->getBootChunkStream("CRED");
-	cred->seek(0);
+	_creditsData = g_nancy->_creditsData;
+	assert(_creditsData);
 
-	Common::String imageName;
-	readFilename(*cred, imageName);
-	_background.init(imageName);
-
-	_textNames.resize(isVampire ? 7 : 1);
-	for (Common::String &str : _textNames) {
-		readFilename(*cred, str);
-	}
-
-	Common::Rect rect;
-	cred->skip(0x20); // Skip the src and dest rectangles
-	readRect(*cred, rect);
-	_textSurface.moveTo(rect);
-	cred->skip(0x10);
-	_updateTime = cred->readUint16LE();
-	_pixelsToScroll = cred->readUint16LE();
-	_sound.read(*cred, SoundDescription::kMenu);
+	_background.init(_creditsData->imageName);
+	_textSurface.moveTo(_creditsData->textScreenPosition);
 
 	drawTextSurface(0);
 
@@ -77,8 +61,8 @@ void Credits::init() {
 
 	g_nancy->_sound->stopSound("MSND");
 
-	g_nancy->_sound->loadSound(_sound);
-	g_nancy->_sound->playSound(_sound);
+	g_nancy->_sound->loadSound(_creditsData->sound);
+	g_nancy->_sound->playSound(_creditsData->sound);
 
 	_background.registerGraphics();
 	_textSurface.registerGraphics();
@@ -93,7 +77,7 @@ void Credits::run() {
 
 	if (input.input & NancyInput::kLeftMouseButtonDown) {
 		_state = kInit;
-		g_nancy->_sound->stopSound(_sound);
+		g_nancy->_sound->stopSound(_creditsData->sound);
 		g_nancy->setMouseEnabled(true);
 		_fullTextSurface.free();
 		g_nancy->setState(NancyState::kMainMenu);
@@ -102,16 +86,16 @@ void Credits::run() {
 
 	Time currentTime = g_nancy->getTotalPlayTime();
 	if (currentTime >= _nextUpdateTime) {
-		_nextUpdateTime = currentTime + _updateTime;
+		_nextUpdateTime = currentTime + _creditsData->updateTime;
 
 		Common::Rect newSrc = _textSurface.getScreenPosition();
 		newSrc.moveTo(_textSurface._drawSurface.getOffsetFromOwner());
-		newSrc.translate(0, _pixelsToScroll);
+		newSrc.translate(0, _creditsData->pixelsToScroll);
 
 		if (newSrc.bottom > _fullTextSurface.h) {
 			newSrc.moveTo(Common::Point());
-			if (_textNames.size() > 1) {
-				drawTextSurface(_currentTextImage == _textNames.size() - 1 ? 0 : _currentTextImage + 1);
+			if (_creditsData->textNames.size() > 1) {
+				drawTextSurface(_currentTextImage == _creditsData->textNames.size() - 1 ? 0 : _currentTextImage + 1);
 			}
 		}
 
@@ -123,7 +107,7 @@ void Credits::run() {
 void Credits::drawTextSurface(uint id) {
 	Graphics::ManagedSurface image;
 	uint surfaceHeight = _textSurface.getBounds().height();
-	g_nancy->_resource->loadImage(_textNames[id], image);
+	g_nancy->_resource->loadImage(_creditsData->textNames[id], image);
 	_fullTextSurface.create(image.w, image.h + (surfaceHeight * 2), g_nancy->_graphicsManager->getInputPixelFormat());
 	_fullTextSurface.setTransparentColor(g_nancy->_graphicsManager->getTransColor());
 	_fullTextSurface.clear(_fullTextSurface.getTransparentColor());
diff --git a/engines/nancy/state/credits.h b/engines/nancy/state/credits.h
index ac66e5d49a8..6d53f6b3c03 100644
--- a/engines/nancy/state/credits.h
+++ b/engines/nancy/state/credits.h
@@ -38,7 +38,7 @@ namespace State {
 class Credits : public State, public Common::Singleton<Credits> {
 public:
 	enum State { kInit, kRun };
-	Credits() : _state(kInit), _background(), _textSurface(1), _pixelsToScroll(0), _currentTextImage(0) {}
+	Credits() : _state(kInit), _background(), _textSurface(1), _currentTextImage(0), _creditsData(nullptr) {}
 
 	// State API
 	void process() override;
@@ -50,17 +50,13 @@ protected:
 
 	void drawTextSurface(uint id);
 
+	CRED *_creditsData;
 	State _state;
 	UI::FullScreenImage _background;
 	RenderObject _textSurface;
 	Time _nextUpdateTime;
 	Graphics::ManagedSurface _fullTextSurface;
-	
-	Common::Array<Common::String> _textNames;
 	uint _currentTextImage;
-	Time _updateTime; // 0x54
-	uint16 _pixelsToScroll; // 0x56
-	SoundDescription _sound; // 0x58, kMenu?
 };
 
 #define NancyCreditsState Nancy::State::Credits::instance()
diff --git a/engines/nancy/state/help.cpp b/engines/nancy/state/help.cpp
index 1e1a15e844e..4f53beec761 100644
--- a/engines/nancy/state/help.cpp
+++ b/engines/nancy/state/help.cpp
@@ -63,25 +63,11 @@ void Help::process() {
 }
 
 void Help::init() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("HELP");
-
-	chunk->seek(0);
-	Common::String imageName;
-	readFilename(*chunk, imageName);
-	_image.init(imageName);
-
-	chunk->skip(20);
-	Common::Rect buttonSrc, buttonDest;
-	buttonDest.left = chunk->readUint16LE();
-	buttonDest.top = chunk->readUint16LE();
-	buttonDest.right = chunk->readUint16LE();
-	buttonDest.bottom = chunk->readUint16LE();
-	buttonSrc.left = chunk->readUint16LE();
-	buttonSrc.top = chunk->readUint16LE();
-	buttonSrc.right = chunk->readUint16LE();
-	buttonSrc.bottom = chunk->readUint16LE();
-
-	_button = new UI::Button(5, _image._drawSurface, buttonSrc, buttonDest);
+	HELP *helpData = g_nancy->_helpData;
+	assert(helpData);
+	_image.init(helpData->imageName);
+
+	_button = new UI::Button(5, _image._drawSurface, helpData->buttonSrc, helpData->buttonDest);
 	_button->init();
 
 	_state = kBegin;
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index ced0924aac2..b1858ea07a6 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -490,17 +490,10 @@ void Scene::init() {
 
 	changeScene(g_nancy->_bootSummary->firstScene);
 
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("HINT");
-
-	if (chunk) {
-		chunk->seek(0);
-
+	if (g_nancy->_hintData) {
 		_hintsRemaining.clear();
 
-		_hintsRemaining.reserve(3);
-		for (uint i = 0; i < 3; ++i) {
-			_hintsRemaining.push_back(chunk->readByte());
-		}
+		_hintsRemaining = g_nancy->_hintData->numHints;
 
 		_lastHintCharacter = _lastHintID = -1;
 	}


Commit: cbe958db0c5df5670435c45c50a876c46aa6e3e0
    https://github.com/scummvm/scummvm/commit/cbe958db0c5df5670435c45c50a876c46aa6e3e0
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:43+03:00

Commit Message:
NANCY: Change font loading

Changed the font loading code so it doesn't need to call getBootChunk().

Changed paths:
    engines/nancy/graphics.cpp
    engines/nancy/graphics.h
    engines/nancy/nancy.cpp


diff --git a/engines/nancy/graphics.cpp b/engines/nancy/graphics.cpp
index 11ae02ffb00..c8822d5cf65 100644
--- a/engines/nancy/graphics.cpp
+++ b/engines/nancy/graphics.cpp
@@ -44,8 +44,6 @@ void GraphicsManager::init() {
 	_screen.clear();
 
 	g_nancy->_resource->loadImage(g_nancy->_imageChunks["OB0"].imageName, _object0);
-
-	loadFonts();
 }
 
 void GraphicsManager::draw() {
@@ -106,6 +104,18 @@ void GraphicsManager::draw() {
 	_screen.update();
 }
 
+void GraphicsManager::loadFonts(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
+	while (chunkStream->pos() < chunkStream->size() - 1) {
+		_fonts.push_back(Font());
+		_fonts.back().read(*chunkStream);
+	}
+
+	delete chunkStream;
+}
+
 void GraphicsManager::addObject(RenderObject *object) {
 	for (const auto &r : _objects) {
 		if (r == object) {
@@ -278,16 +288,6 @@ void GraphicsManager::grabViewportObjects(Common::Array<RenderObject *> &inArray
 	}
 }
 
-void GraphicsManager::loadFonts() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("FONT");
-
-	chunk->seek(0);
-	while (chunk->pos() < chunk->size() - 1) {
-		_fonts.push_back(Font());
-		_fonts.back().read(*chunk);
-	}
-}
-
 // Draw a given screen-space rectangle to the screen
 void GraphicsManager::blitToScreen(const RenderObject &src, Common::Rect screenRect) {
 	_screen.blitFrom(src._drawSurface, src._drawSurface.getBounds().findIntersectingRect(src.convertToLocal(screenRect)), screenRect);
diff --git a/engines/nancy/graphics.h b/engines/nancy/graphics.h
index 86c5bfb1c7b..8dbebb700c0 100644
--- a/engines/nancy/graphics.h
+++ b/engines/nancy/graphics.h
@@ -38,6 +38,8 @@ public:
 
 	void init();
 	void draw();
+	
+	void loadFonts(Common::SeekableReadStream *chunkStream);
 
 	void addObject(RenderObject *object);
 	void removeObject(RenderObject *object);
@@ -66,7 +68,6 @@ public:
 	Graphics::PixelFormat _screenPixelFormat;
 
 private:
-	void loadFonts();
 	void blitToScreen(const RenderObject &src, Common::Rect dest);
 
 	static int objectComparator(const void *a, const void *b);
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 0f0cdf626ef..45027acc1ee 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -356,8 +356,16 @@ void NancyEngine::bootGameEngine() {
 	_helpData = new HELP(boot->getChunkStream("HELP"));
 	_creditsData = new CRED(boot->getChunkStream("CRED"));
 
+	// For now we ignore the potential for more than one of each of these
+	_imageChunks.setVal("OB0", boot->getChunkStream("OB0"));
+	_imageChunks.setVal("FR0", boot->getChunkStream("FR0"));
+	_imageChunks.setVal("LG0", boot->getChunkStream("LG0"));
+
 	_cursorManager->init(boot->getChunkStream("CURS"));
 
+	_graphicsManager->init();
+	_graphicsManager->loadFonts(boot->getChunkStream("FONT"));
+
 	auto *chunkStream = boot->getChunkStream("MAP");
 	if (chunkStream) {
 		_mapData = new MAP(chunkStream);
@@ -368,11 +376,6 @@ void NancyEngine::bootGameEngine() {
 		_hintData = new HINT(chunkStream);
 	}
 
-	// For now we ignore the potential for more than one of each of these
-	_imageChunks.setVal("OB0", boot->getChunkStream("OB0"));
-	_imageChunks.setVal("FR0", boot->getChunkStream("FR0"));
-	_imageChunks.setVal("LG0", boot->getChunkStream("LG0"));
-
 	// Load all data chunks found in BOOT. These get used in a lot of places
 	// across the engine, so we always keep them in memory
 	Common::Array<Common::String> bootChunkNames;
@@ -384,8 +387,6 @@ void NancyEngine::bootGameEngine() {
 
 	_sound->loadCommonSounds();
 
-	_graphicsManager->init();
-
 	delete boot;
 }
 


Commit: e23acc9d1f40e0a84bad50d7f45e91c0cd09fbe9
    https://github.com/scummvm/scummvm/commit/e23acc9d1f40e0a84bad50d7f45e91c0cd09fbe9
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:44+03:00

Commit Message:
NANCY: Implement struct for CLOK chunk

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


diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index a04d4dcf593..edec590f143 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -323,6 +323,49 @@ HINT::HINT(Common::SeekableReadStream *chunkStream) {
 	delete chunkStream;
 }
 
+CLOK::CLOK(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
+	Common::Serializer s(chunkStream, nullptr);
+	s.setVersion(g_nancy->getGameType());
+
+	animSrcs.resize(8);
+	for (uint i = 0; i < 8; ++i) {
+		readRect(*chunkStream, animSrcs[i]);
+	}
+
+	hoursHandSrcs.resize(12);
+	for (uint i = 0; i < 12; ++i) {
+		readRect(*chunkStream, hoursHandSrcs[i]);
+	}
+
+	minutesHandSrcs.resize(4);
+	for (uint i = 0; i < 4; ++i) {
+		readRect(*chunkStream, minutesHandSrcs[i]);
+	}
+
+	readRect(*chunkStream, screenPosition);
+
+	hoursHandDests.resize(12);
+	for (uint i = 0; i < 12; ++i) {
+		readRect(*chunkStream, hoursHandDests[i]);
+	}
+
+	minutesHandDests.resize(4);
+	for (uint i = 0; i < 4; ++i) {
+		readRect(*chunkStream, minutesHandDests[i]);
+	}
+
+	readRect(*chunkStream, gargoyleEyesSrc);
+	readRect(*chunkStream, gargoyleEyesDest);
+
+	s.syncAsUint32LE(timeToKeepOpen);
+	s.syncAsUint16LE(frameTime);
+
+	delete chunkStream;
+}
+
 ImageChunk::ImageChunk(Common::SeekableReadStream *chunkStream) {
 	assert(chunkStream);
 
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index 18060c5c522..9c35438f1ef 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -162,6 +162,24 @@ struct HINT {
 	Common::Array<uint16> numHints;
 };
 
+struct CLOK {
+	CLOK(Common::SeekableReadStream *chunkStream);
+
+	Common::Array<Common::Rect> animSrcs;
+
+	Common::Array<Common::Rect> hoursHandSrcs;
+	Common::Array<Common::Rect> minutesHandSrcs;
+	Common::Rect screenPosition;
+	Common::Array<Common::Rect> hoursHandDests;
+	Common::Array<Common::Rect> minutesHandDests;
+
+	Common::Rect gargoyleEyesSrc;
+	Common::Rect gargoyleEyesDest;
+
+	uint32 timeToKeepOpen;
+	uint16 frameTime;
+};
+
 struct ImageChunk {
 	ImageChunk() : width(0), height(0) {}
 	ImageChunk(Common::SeekableReadStream *chunkStream);
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 45027acc1ee..a9fa3637827 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -77,6 +77,7 @@ NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) :
 	_helpData = nullptr;
 	_creditsData = nullptr;
 	_hintData = nullptr;
+	_clockData = nullptr;
 }
 
 NancyEngine::~NancyEngine() {
@@ -96,6 +97,7 @@ NancyEngine::~NancyEngine() {
 	delete _helpData;
 	delete _creditsData;
 	delete _hintData;
+	delete _clockData;
 }
 
 NancyEngine *NancyEngine::create(GameType type, OSystem *syst, const NancyGameDescription *gd) {
@@ -376,6 +378,11 @@ void NancyEngine::bootGameEngine() {
 		_hintData = new HINT(chunkStream);
 	}
 
+	chunkStream = boot->getChunkStream("CLOK");
+	if (chunkStream) {
+		_clockData = new CLOK(chunkStream);
+	}
+
 	// Load all data chunks found in BOOT. These get used in a lot of places
 	// across the engine, so we always keep them in memory
 	Common::Array<Common::String> bootChunkNames;
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index 5221af5749a..b0c299b231e 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -123,6 +123,7 @@ public:
 	HELP *_helpData;
 	CRED *_creditsData;
 	HINT *_hintData;
+	CLOK *_clockData;
 
 	Common::HashMap<Common::String, ImageChunk> _imageChunks;
 
diff --git a/engines/nancy/ui/clock.cpp b/engines/nancy/ui/clock.cpp
index c64531d1640..83ca8cf518b 100644
--- a/engines/nancy/ui/clock.cpp
+++ b/engines/nancy/ui/clock.cpp
@@ -36,56 +36,28 @@ namespace UI {
 
 Clock::Clock() : 	RenderObject(11),
 					_globe(10, this),
-					_gargoyleEyes(9) {}
+					_gargoyleEyes(9),
+					_clockData(nullptr) {}
 
 void Clock::init() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("CLOK");
 	Graphics::ManagedSurface &object0 = g_nancy->_graphicsManager->_object0;
 
-	_globe.init();
-
-	if (chunk) {
-		chunk->seek(0x80);
-
-		_hoursHandSrcRects.resize(12);
-		for (uint i = 0; i < 12; ++i) {
-			readRect(*chunk, _hoursHandSrcRects[i]);
-		}
-
-		_minutesHandSrcRects.resize(4);
-		for (uint i = 0; i < 4; ++i) {
-			readRect(*chunk, _minutesHandSrcRects[i]);
-		}
-
-		Common::Rect dest;
-		readRect(*chunk, dest);
-		_drawSurface.create(dest.width(), dest.height(), g_nancy->_graphicsManager->getInputPixelFormat());
-		moveTo(dest);
-
-		_hoursHandDestRects.resize(12);
-		for (uint i = 0; i < 12; ++i) {
-			readRect(*chunk, _hoursHandDestRects[i]);
-		}
+	_clockData = g_nancy->_clockData;
+	assert(_clockData);
 
-		_minutesHandDestRects.resize(4);
-		for (uint i = 0; i < 4; ++i) {
-			readRect(*chunk, _minutesHandDestRects[i]);
-		}
+	_drawSurface.create(_clockData->screenPosition.width(), _clockData->screenPosition.height(), g_nancy->_graphicsManager->getInputPixelFormat());
+	moveTo(_clockData->screenPosition);
 
-		Common::Rect gargoyleEyesSrcRect;
-		Common::Rect gargoyleEyesDestRect;
+	_gargoyleEyes._drawSurface.create(object0, _clockData->gargoyleEyesSrc);
+	_gargoyleEyes.moveTo(_clockData->gargoyleEyesDest);
+	_gargoyleEyes.setVisible(false);
 
-		readRect(*chunk, gargoyleEyesSrcRect);
-		readRect(*chunk, gargoyleEyesDestRect);
-		_gargoyleEyes._drawSurface.create(object0, gargoyleEyesSrcRect);
-		_gargoyleEyes.moveTo(gargoyleEyesDestRect);
-		_gargoyleEyes.setVisible(false);
+	_gargoyleEyes.setTransparent(true);
+	_globe.setTransparent(true);
+	GraphicsManager::loadSurfacePalette(_drawSurface, "OBJECT0");
+	setTransparent(true);
 
-		_gargoyleEyes.setTransparent(true);
-		_globe.setTransparent(true);
-		GraphicsManager::loadSurfacePalette(_drawSurface, "OBJECT0");
-		setTransparent(true);
-	}
+	_globe.init();
 }
 
 void Clock::registerGraphics() {
@@ -124,39 +96,26 @@ void Clock::drawClockHands() {
 	}
 	uint minutesHand = _playerTime.getMinutes() / 15;
 
-	Common::Rect hoursDest = _hoursHandDestRects[hours];
-	Common::Rect minutesDest = _minutesHandDestRects[minutesHand];
+	Common::Rect hoursDest = _clockData->hoursHandDests[hours];
+	Common::Rect minutesDest = _clockData->minutesHandDests[minutesHand];
 
 	hoursDest.translate(-_screenPosition.left, -_screenPosition.top);
 	minutesDest.translate(-_screenPosition.left, -_screenPosition.top);
 
 	_drawSurface.clear(g_nancy->_graphicsManager->getTransColor());
-	_drawSurface.blitFrom(object0, _hoursHandSrcRects[hours], hoursDest);
-	_drawSurface.blitFrom(object0, _minutesHandSrcRects[minutesHand], minutesDest);
+	_drawSurface.blitFrom(object0, _clockData->hoursHandSrcs[hours], hoursDest);
+	_drawSurface.blitFrom(object0, _clockData->minutesHandSrcs[minutesHand], minutesDest);
 }
 
 void Clock::ClockGlobe::init() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("CLOK");
+	_srcRects = _owner->_clockData->animSrcs;
+	moveTo(_owner->_clockData->screenPosition);
 
-	if (chunk) {
-		chunk->seek(0);
-		_srcRects.resize(8);
-		for (uint i = 0; i < 8; ++i) {
-			readRect(*chunk, _srcRects[i]);
-		}
-
-		chunk->seek(0x180);
-		Common::Rect screenDest;
-		readRect(*chunk, screenDest);
-		moveTo(screenDest);
+	_timeToKeepOpen = _owner->_clockData->timeToKeepOpen;
+	_frameTime = _owner->_clockData->frameTime;
 
-		chunk->seek(0x2B0);
-		_timeToKeepOpen = chunk->readUint32LE();
-		_frameTime = chunk->readUint16LE();
-
-		_alwaysHighlightCursor = true;
-		_hotspot = _screenPosition;
-	}
+	_alwaysHighlightCursor = true;
+	_hotspot = _screenPosition;
 }
 
 void Clock::ClockGlobe::updateGraphics() {
diff --git a/engines/nancy/ui/clock.h b/engines/nancy/ui/clock.h
index 2041b7e5ebb..fbae366076a 100644
--- a/engines/nancy/ui/clock.h
+++ b/engines/nancy/ui/clock.h
@@ -63,15 +63,10 @@ protected:
 		uint32 _timeToKeepOpen;
 	};
 
+	CLOK *_clockData;
 	RenderObject _gargoyleEyes;
 	ClockGlobe _globe;
 
-	Common::Array<Common::Rect> _globeSrcRects;
-	Common::Array<Common::Rect> _hoursHandSrcRects;
-	Common::Array<Common::Rect> _minutesHandSrcRects;
-	Common::Array<Common::Rect> _hoursHandDestRects;
-	Common::Array<Common::Rect> _minutesHandDestRects;
-
 	Time _playerTime;
 };
 


Commit: 323b65c0234203b0bf57ca71359a6f430341ff26
    https://github.com/scummvm/scummvm/commit/323b65c0234203b0bf57ca71359a6f430341ff26
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:44+03:00

Commit Message:
NANCY: Implement struct for SPUZ chunk

Changed paths:
    engines/nancy/action/sliderpuzzle.cpp
    engines/nancy/action/sliderpuzzle.h
    engines/nancy/enginedata.cpp
    engines/nancy/enginedata.h
    engines/nancy/nancy.cpp
    engines/nancy/nancy.h


diff --git a/engines/nancy/action/sliderpuzzle.cpp b/engines/nancy/action/sliderpuzzle.cpp
index 164c0a74ec6..208ddc7e698 100644
--- a/engines/nancy/action/sliderpuzzle.cpp
+++ b/engines/nancy/action/sliderpuzzle.cpp
@@ -43,6 +43,9 @@ void SliderPuzzle::init() {
 }
 
 void SliderPuzzle::readData(Common::SeekableReadStream &stream) {
+	_spuzData = g_nancy->_sliderPuzzleData;
+	assert(_spuzData);
+
 	readFilename(stream, _imageName);
 
 	_width = stream.readUint16LE();
@@ -116,17 +119,13 @@ void SliderPuzzle::execute() {
 		init();
 		registerGraphics();
 		if (!NancySceneState._sliderPuzzleState.playerHasTriedPuzzle) {
-			Common::SeekableReadStream *spuz = g_nancy->getBootChunkStream("SPUZ");
 			NancySceneState._sliderPuzzleState.playerTileOrder.clear();
-			spuz->seek(NancySceneState.getDifficulty() * 0x48);
+			NancySceneState._sliderPuzzleState.playerTileOrder.resize(_height);
 			for (uint y = 0; y < _height; ++y) {
-				NancySceneState._sliderPuzzleState.playerTileOrder.push_back(Common::Array<int16>());
-
+				NancySceneState._sliderPuzzleState.playerTileOrder[y].resize(_width);
 				for (uint x = 0; x < _width; ++x) {
-					NancySceneState._sliderPuzzleState.playerTileOrder.back().push_back(spuz->readSint16LE());
+					NancySceneState._sliderPuzzleState.playerTileOrder[y][x] = _spuzData->tileOrder[NancySceneState.getDifficulty()][y * 6 + x];
 				}
-
-				spuz->skip((6 - _width) * 2);
 			}
 
 			NancySceneState._sliderPuzzleState.playerHasTriedPuzzle = true;
diff --git a/engines/nancy/action/sliderpuzzle.h b/engines/nancy/action/sliderpuzzle.h
index b6731ef1ca6..ffd64f8e653 100644
--- a/engines/nancy/action/sliderpuzzle.h
+++ b/engines/nancy/action/sliderpuzzle.h
@@ -31,6 +31,8 @@ class Serializer;
 }
 
 namespace Nancy {
+
+struct SPUZ;
 namespace Action {
 
 class SliderPuzzle: public ActionRecord, public RenderObject {
@@ -46,6 +48,8 @@ public:
 	void handleInput(NancyInput &input) override;
 	void onPause(bool pause) override;
 
+	SPUZ *_spuzData = nullptr;
+
 	Common::String _imageName; // 0x00
 	uint16 _width = 0; // 0xA
 	uint16 _height = 0; // 0xC
diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index edec590f143..3bb4cf4fea9 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -323,6 +323,22 @@ HINT::HINT(Common::SeekableReadStream *chunkStream) {
 	delete chunkStream;
 }
 
+SPUZ::SPUZ(Common::SeekableReadStream *chunkStream) {
+	assert(chunkStream);
+
+	chunkStream->seek(0);
+	tileOrder.resize(3);
+
+	for (uint i = 0; i < 3; ++i) {
+		tileOrder[i].resize(36);
+		for (uint j = 0; j < 36; ++j) {
+			tileOrder[i][j] = chunkStream->readSint16LE();
+		}
+	}
+	
+	delete chunkStream;
+}
+
 CLOK::CLOK(Common::SeekableReadStream *chunkStream) {
 	assert(chunkStream);
 
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index 9c35438f1ef..9d1705f172b 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -162,6 +162,12 @@ struct HINT {
 	Common::Array<uint16> numHints;
 };
 
+struct SPUZ {
+	SPUZ(Common::SeekableReadStream *chunkStream);
+
+	Common::Array<Common::Array<int16>> tileOrder;
+};
+
 struct CLOK {
 	CLOK(Common::SeekableReadStream *chunkStream);
 
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index a9fa3637827..02fd4dca277 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -77,6 +77,7 @@ NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) :
 	_helpData = nullptr;
 	_creditsData = nullptr;
 	_hintData = nullptr;
+	_sliderPuzzleData = nullptr;
 	_clockData = nullptr;
 }
 
@@ -97,6 +98,7 @@ NancyEngine::~NancyEngine() {
 	delete _helpData;
 	delete _creditsData;
 	delete _hintData;
+	delete _sliderPuzzleData;
 	delete _clockData;
 }
 
@@ -378,6 +380,11 @@ void NancyEngine::bootGameEngine() {
 		_hintData = new HINT(chunkStream);
 	}
 
+	chunkStream = boot->getChunkStream("SPUZ");
+	if (chunkStream) {
+		_sliderPuzzleData = new SPUZ(chunkStream);
+	}
+
 	chunkStream = boot->getChunkStream("CLOK");
 	if (chunkStream) {
 		_clockData = new CLOK(chunkStream);
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index b0c299b231e..8787088f511 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -123,6 +123,7 @@ public:
 	HELP *_helpData;
 	CRED *_creditsData;
 	HINT *_hintData;
+	SPUZ *_sliderPuzzleData;
 	CLOK *_clockData;
 
 	Common::HashMap<Common::String, ImageChunk> _imageChunks;


Commit: 525d2383fb3d7931ae077d78b080137cc1a8ba3e
    https://github.com/scummvm/scummvm/commit/525d2383fb3d7931ae077d78b080137cc1a8ba3e
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:45+03:00

Commit Message:
NANCY: Change loading of common sounds

loadCommonSounds() now takes the BOOT iff as an argument,
removing the need to store the sound chunks in memory.

Changed paths:
    engines/nancy/nancy.cpp
    engines/nancy/sound.cpp
    engines/nancy/sound.h


diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 02fd4dca277..1b8c8ddc52b 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -390,6 +390,8 @@ void NancyEngine::bootGameEngine() {
 		_clockData = new CLOK(chunkStream);
 	}
 
+	_sound->loadCommonSounds(boot);
+
 	// Load all data chunks found in BOOT. These get used in a lot of places
 	// across the engine, so we always keep them in memory
 	Common::Array<Common::String> bootChunkNames;
@@ -399,8 +401,6 @@ void NancyEngine::bootGameEngine() {
 		addBootChunk(n, boot->getChunkStream(n));
 	}
 
-	_sound->loadCommonSounds();
-
 	delete boot;
 }
 
diff --git a/engines/nancy/sound.cpp b/engines/nancy/sound.cpp
index ea70d503183..7cbdc794dc0 100644
--- a/engines/nancy/sound.cpp
+++ b/engines/nancy/sound.cpp
@@ -28,6 +28,7 @@
 
 #include "engines/nancy/nancy.h"
 #include "engines/nancy/sound.h"
+#include "engines/nancy/iff.h"
 
 #include "engines/nancy/state/scene.h"
 #include "engines/nancy/state/map.h"
@@ -252,7 +253,7 @@ SoundManager::SoundManager() {
 	initSoundChannels();
 }
 
-void SoundManager::loadCommonSounds() {
+void SoundManager::loadCommonSounds(IFF *boot) {
 	// Persistent sounds that are used across the engine. These originally get loaded inside Logo
 	Common::String chunkNames[] = {
 		"CANT", "CURT", "GLOB", "SLID", "BULS", "BUDE", "BUOK", "TH1", "TH2",
@@ -260,22 +261,26 @@ void SoundManager::loadCommonSounds() {
 
 	Common::SeekableReadStream *chunk = nullptr;
 	for (auto const &s : chunkNames) {
-		chunk = g_nancy->getBootChunkStream(s);
+		chunk = boot->getChunkStream(s);
 		if (chunk) {
 			SoundDescription &desc = _commonSounds.getOrCreateVal(s);
 			desc.read(*chunk, SoundDescription::kNormal);
 			g_nancy->_sound->loadSound(desc);
 			_channels[desc.channelID].isPersistent = true;
+
+			delete chunk;
 		}
 	}
 
 	// Menu sound is stored differently
-	chunk = g_nancy->getBootChunkStream("MSND"); // channel 28
+	chunk = boot->getChunkStream("MSND"); // channel 28
 	if (chunk) {
 		SoundDescription &desc = _commonSounds.getOrCreateVal("MSND");
 		desc.read(*chunk, SoundDescription::kMenu);
 		g_nancy->_sound->loadSound(desc);
 		_channels[desc.channelID].isPersistent = true;
+
+		delete chunk;
 	}
 }
 
diff --git a/engines/nancy/sound.h b/engines/nancy/sound.h
index 5242210c941..3e491f56443 100644
--- a/engines/nancy/sound.h
+++ b/engines/nancy/sound.h
@@ -36,6 +36,8 @@ class SeekableAudioStream;
 
 namespace Nancy {
 
+class IFF;
+
 class NancyEngine;
 
 class SoundManager {
@@ -43,7 +45,7 @@ public:
 	SoundManager();
 	~SoundManager();
 
-	void loadCommonSounds();
+	void loadCommonSounds(IFF *boot);
 
 	// Load a sound into a channel without starting it
 	void loadSound(const SoundDescription &description, bool panning = false);


Commit: bb613925c3d230f1d3990c8692f2d2ad280f85b2
    https://github.com/scummvm/scummvm/commit/bb613925c3d230f1d3990c8692f2d2ad280f85b2
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:45+03:00

Commit Message:
NANCY: Stop storing BOOT chunks in memory

Removed the facilities for storing and getting the raw chunks inside BOOT.
The data found inside them is now loaded into the structs defined in
enginedata.h. This removes the need for multiple classes to know about
the layout of every game's version of a particular chunk.

Changed paths:
    engines/nancy/nancy.cpp
    engines/nancy/nancy.h
    engines/nancy/state/mainmenu.cpp


diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 1b8c8ddc52b..ebb051a3a7a 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -82,7 +82,6 @@ NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) :
 }
 
 NancyEngine::~NancyEngine() {
-	clearBootChunks();
 	delete _randomSource;
 
 	delete _graphicsManager;
@@ -346,7 +345,6 @@ void NancyEngine::bootGameEngine() {
 	// Setup mixer
 	syncSoundSettings();
 
-	clearBootChunks();
 	IFF *boot = new IFF("boot");
 	if (!boot->load())
 		error("Failed to load boot script");
@@ -392,15 +390,6 @@ void NancyEngine::bootGameEngine() {
 
 	_sound->loadCommonSounds(boot);
 
-	// Load all data chunks found in BOOT. These get used in a lot of places
-	// across the engine, so we always keep them in memory
-	Common::Array<Common::String> bootChunkNames;
-	boot->list(bootChunkNames);
-
-	for (auto const &n : bootChunkNames) {
-		addBootChunk(n, boot->getChunkStream(n));
-	}
-
 	delete boot;
 }
 
@@ -423,28 +412,6 @@ State::State *NancyEngine::getStateObject(NancyState::NancyState state) const {
 	}
 }
 
-bool NancyEngine::addBootChunk(const Common::String &name, Common::SeekableReadStream *stream) {
-	if (!stream)
-		return false;
-	_bootChunks[name] = stream;
-	return true;
-}
-
-Common::SeekableReadStream *NancyEngine::getBootChunkStream(const Common::String &name) const {
-	if (_bootChunks.contains(name)) {
-		return _bootChunks[name];
-	} else {
-		return nullptr;
-	}
-}
-
-void NancyEngine::clearBootChunks() {
-	for (auto const& i : _bootChunks) {
-		delete i._value;
-	}
-	_bootChunks.clear();
-}
-
 void NancyEngine::preloadCals(const IFF &boot) {
 	const byte *buf;
 	uint size;
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index 8787088f511..4c803f11651 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -100,9 +100,6 @@ public:
 	NancyState::NancyState getState() { return _gameFlow.curState; }
 	void setToPreviousState();
 
-	// Chunks found in BOOT get extracted and cached at startup, this function lets other classes access them
-	Common::SeekableReadStream *getBootChunkStream(const Common::String &name) const;
-
 	void setMouseEnabled(bool enabled);
 
 	// Managers
@@ -142,9 +139,6 @@ private:
 
 	State::State *getStateObject(NancyState::NancyState state) const;
 
-	bool addBootChunk(const Common::String &name, Common::SeekableReadStream *stream);
-	void clearBootChunks();
-
 	void preloadCals(const IFF &boot);
 
 	void readDatFile();
@@ -161,8 +155,6 @@ private:
 	OSystem *_system;
 
 	const NancyGameDescription *_gameDescription;
-
-	Common::HashMap<Common::String, Common::SeekableReadStream *> _bootChunks;
 };
 
 extern NancyEngine *g_nancy;
diff --git a/engines/nancy/state/mainmenu.cpp b/engines/nancy/state/mainmenu.cpp
index 101afcf57d0..3f05ab59461 100644
--- a/engines/nancy/state/mainmenu.cpp
+++ b/engines/nancy/state/mainmenu.cpp
@@ -54,7 +54,7 @@ void MainMenu::onStateExit() {
 }
 
 void MainMenu::init() {
-	Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("MENU");
+	/*Common::SeekableReadStream *chunk = g_nancy->getBootChunkStream("MENU");
 	chunk->seek(0);
 
 	Common::String imageName;
@@ -91,7 +91,7 @@ void MainMenu::init() {
 		rect.bottom = chunk->readSint16LE();
 	}
 
-	_buttonDown.registerGraphics();
+	_buttonDown.registerGraphics();*/
 
 	_state = kRun;
 }


Commit: 856f6f89e9ca0619943e2af8ef79e9898e5f0644
    https://github.com/scummvm/scummvm/commit/856f6f89e9ca0619943e2af8ef79e9898e5f0644
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:46+03:00

Commit Message:
NANCY: Add data reading utility functions

Changed paths:
    engines/nancy/action/primaryvideo.cpp
    engines/nancy/enginedata.cpp
    engines/nancy/util.cpp
    engines/nancy/util.h


diff --git a/engines/nancy/action/primaryvideo.cpp b/engines/nancy/action/primaryvideo.cpp
index 0f0af4415be..606ed7426fa 100644
--- a/engines/nancy/action/primaryvideo.cpp
+++ b/engines/nancy/action/primaryvideo.cpp
@@ -170,10 +170,7 @@ void PlayPrimaryVideoChan0::readData(Common::SeekableReadStream &stream) {
 	ser.setVersion(g_nancy->getGameType());
 
 	readFilename(stream, _videoName);
-
-	if (ser.getVersion() == kGameTypeVampire) {
-		readFilename(stream, _paletteName);
-	}
+	readFilename(ser, _paletteName, kGameTypeVampire, kGameTypeVampire);
 
 	ser.skip(2);
 	ser.syncAsUint16LE(_videoFormat);
diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index 3bb4cf4fea9..16017771fcb 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -108,16 +108,14 @@ INV::INV(Common::SeekableReadStream *chunkStream) {
 	s.skip(0xC0);
 
 	uint numFrames = g_nancy->getStaticData().numCurtainAnimationFrames;
-	curtainAnimationSrcs.resize(numFrames * 2);
-	for (uint i = 0; i < numFrames * 2; ++i) {
-		readRect(*chunkStream, curtainAnimationSrcs[i]);
-	}
 
-	readRect(*chunkStream, inventoryScreenPosition);
+	readRectArray(s, curtainAnimationSrcs, numFrames * 2);
+
+	readRect(s, inventoryScreenPosition);
 	s.syncAsUint16LE(curtainsFrameTime);
 
-	readFilename(*chunkStream, inventoryBoxIconsImageName);
-	readFilename(*chunkStream, inventoryCursorsImageName);
+	readFilename(s, inventoryBoxIconsImageName);
+	readFilename(s, inventoryCursorsImageName);
 
 	s.skip(0x18);
 	byte itemName[20];
@@ -132,7 +130,7 @@ INV::INV(Common::SeekableReadStream *chunkStream) {
 		itemName[itemNameLength - 1] = '\0';
 		item.name = (char *)itemName;
 		s.syncAsUint16LE(item.keepItem);
-		readRect(*chunkStream, item.sourceRect);
+		readRect(s, item.sourceRect);
 	}
 
 	delete chunkStream;
@@ -187,17 +185,8 @@ MAP::MAP(Common::SeekableReadStream *chunkStream) {
 	uint numLocations = s.getVersion() == kGameTypeVampire ? 7 : 4;
 	uint numMaps = s.getVersion() == kGameTypeVampire ? 4 : 2;
 
-	mapNames.resize(numMaps);
-	for (uint i = 0; i < numMaps; ++i) {
-		readFilename(*chunkStream, mapNames[i]);
-	}
-
-	if (s.getVersion() == kGameTypeVampire) {
-		mapPaletteNames.resize(numMaps);
-		for (uint i = 0; i < numMaps; ++i) {
-			readFilename(*chunkStream, mapPaletteNames[i]);
-		}
-	}
+	readFilenameArray(s, mapNames, numMaps);
+	readFilenameArray(s, mapPaletteNames, numMaps, kGameTypeVampire, kGameTypeVampire);
 
 	s.skip(4);
 
@@ -208,34 +197,24 @@ MAP::MAP(Common::SeekableReadStream *chunkStream) {
 
 	s.skip(0x20);
 
-	if (s.getVersion() == kGameTypeVampire) {
-		s.syncAsUint16LE(globeFrameTime);
-
-		globeSrcs.resize(8);
-		for (uint i = 0; i < 8; ++i) {
-			readRect(*chunkStream, globeSrcs[i]);
-		}
+	s.syncAsUint16LE(globeFrameTime, kGameTypeVampire, kGameTypeVampire);
+	readRectArray(s, globeSrcs, 8, kGameTypeVampire, kGameTypeVampire);
+	readRect(s, globeDest, kGameTypeVampire, kGameTypeVampire);
 
-		readRect(*chunkStream, globeDest);
-	}
-
-	if (s.getVersion() == kGameTypeNancy1) {
-		s.skip(2);
-		readRect(*chunkStream, buttonSrc);
-		readRect(*chunkStream, buttonDest);
-	}
+	s.skip(2, kGameTypeNancy1, kGameTypeNancy1);
+	readRect(s, buttonSrc, kGameTypeNancy1, kGameTypeNancy1);
+	readRect(s, buttonDest, kGameTypeNancy1, kGameTypeNancy1);
 
 	locations.resize(numLocations);
+
 	for (uint i = 0; i < numLocations; ++i) {
 		readRect(*chunkStream, locations[i].labelSrc);
 	}
 
-	readRect(*chunkStream, closedLabelSrc);
+	readRect(s, closedLabelSrc);
 
-	if (s.getVersion() == kGameTypeVampire) {
-		readRect(*chunkStream, globeGargoyleSrc);
-		readRect(*chunkStream, globeGargoyleDest);
-	}
+	readRect(s, globeGargoyleSrc, kGameTypeVampire, kGameTypeVampire);
+	readRect(s, globeGargoyleDest, kGameTypeVampire, kGameTypeVampire);
 
 	char buf[30];
 
@@ -346,32 +325,15 @@ CLOK::CLOK(Common::SeekableReadStream *chunkStream) {
 	Common::Serializer s(chunkStream, nullptr);
 	s.setVersion(g_nancy->getGameType());
 
-	animSrcs.resize(8);
-	for (uint i = 0; i < 8; ++i) {
-		readRect(*chunkStream, animSrcs[i]);
-	}
-
-	hoursHandSrcs.resize(12);
-	for (uint i = 0; i < 12; ++i) {
-		readRect(*chunkStream, hoursHandSrcs[i]);
-	}
-
-	minutesHandSrcs.resize(4);
-	for (uint i = 0; i < 4; ++i) {
-		readRect(*chunkStream, minutesHandSrcs[i]);
-	}
+	readRectArray(s, animSrcs, 8);
 
-	readRect(*chunkStream, screenPosition);
+	readRectArray(s, hoursHandSrcs, 12);
+	readRectArray(s, minutesHandSrcs, 4);
 
-	hoursHandDests.resize(12);
-	for (uint i = 0; i < 12; ++i) {
-		readRect(*chunkStream, hoursHandDests[i]);
-	}
+	readRect(s, screenPosition);
 
-	minutesHandDests.resize(4);
-	for (uint i = 0; i < 4; ++i) {
-		readRect(*chunkStream, minutesHandDests[i]);
-	}
+	readRectArray(s, hoursHandDests, 12);
+	readRectArray(s, minutesHandDests, 4);
 
 	readRect(*chunkStream, gargoyleEyesSrc);
 	readRect(*chunkStream, gargoyleEyesDest);
diff --git a/engines/nancy/util.cpp b/engines/nancy/util.cpp
index d0ab94eaba2..e13cdfd64b8 100644
--- a/engines/nancy/util.cpp
+++ b/engines/nancy/util.cpp
@@ -36,6 +36,48 @@ void readRect(Common::SeekableReadStream &stream, Common::Rect &inRect) {
 	}
 }
 
+void readRect(Common::Serializer &stream, Common::Rect &inRect, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+	Common::Serializer::Version version = stream.getVersion();
+	if (version >= minVersion && version <= maxVersion) {
+		stream.syncAsUint32LE(inRect.left);
+		stream.syncAsUint32LE(inRect.top);
+		stream.syncAsUint32LE(inRect.right);
+		stream.syncAsUint32LE(inRect.bottom);
+
+		// TVD's rects are non-inclusive
+		if (version > kGameTypeVampire) {
+			++inRect.right;
+			++inRect.bottom;
+		}
+	}
+}
+
+void readRectArray(Common::SeekableReadStream &stream, Common::Array<Common::Rect> &inArray, uint num) {
+	inArray.resize(num);
+	for (Common::Rect &rect : inArray) {
+		readRect(stream, rect);
+	}
+}
+
+void readRectArray(Common::Serializer &stream, Common::Array<Common::Rect> &inArray, uint num, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+	Common::Serializer::Version version = stream.getVersion();
+	if (version >= minVersion && version <= maxVersion) {
+		inArray.resize(num);
+		for (Common::Rect &rect : inArray) {
+			stream.syncAsUint32LE(rect.left);
+			stream.syncAsUint32LE(rect.top);
+			stream.syncAsUint32LE(rect.right);
+			stream.syncAsUint32LE(rect.bottom);
+
+			// TVD's rects are non-inclusive
+			if (version > kGameTypeVampire) {
+				++rect.right;
+				++rect.bottom;
+			}
+		}
+	}
+}
+
 // Reads an 8-character filename from a 10-character source
 void readFilename(Common::SeekableReadStream &stream, Common::String &inString) {
 	char buf[10];
@@ -44,4 +86,35 @@ void readFilename(Common::SeekableReadStream &stream, Common::String &inString)
 	inString = buf;
 }
 
+// Reads an 8-character filename from a 10-character source
+void readFilename(Common::Serializer &stream, Common::String &inString, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+	Common::Serializer::Version version = stream.getVersion();
+	if (version >= minVersion && version <= maxVersion) {
+		char buf[10];
+		stream.syncBytes((byte *)buf, 10);
+		buf[9] = '\0';
+		inString = buf;
+	}
+}
+
+void readFilenameArray(Common::SeekableReadStream &stream, Common::Array<Common::String> &inArray, uint num) {
+	inArray.resize(num);
+	for (Common::String &str : inArray) {
+		readFilename(stream, str);
+	}
+}
+
+void readFilenameArray(Common::Serializer &stream, Common::Array<Common::String> &inArray, uint num, Common::Serializer::Version minVersion, Common::Serializer::Version maxVersion) {
+	Common::Serializer::Version version = stream.getVersion();
+	if (version >= minVersion && version <= maxVersion) {
+		inArray.resize(num);
+		char buf[10];
+		for (Common::String &str : inArray) {
+			stream.syncBytes((byte *)buf, 10);
+			buf[9] = '\0';
+			str = buf;
+		}
+	}
+}
+
 } // End of namespace Nancy
diff --git a/engines/nancy/util.h b/engines/nancy/util.h
index 4400a8158e1..8b226932150 100644
--- a/engines/nancy/util.h
+++ b/engines/nancy/util.h
@@ -22,12 +22,19 @@
 #define NANCY_UTIL_H
 
 #include "common/rect.h"
-#include "common/stream.h"
+#include "common/serializer.h"
 
 namespace Nancy {
 
 void readRect(Common::SeekableReadStream &stream, Common::Rect &inRect);
+void readRect(Common::Serializer &stream, Common::Rect &inRect, Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = Common::Serializer::kLastVersion);
+void readRectArray(Common::SeekableReadStream &stream, Common::Array<Common::Rect> &inArray, uint num);
+void readRectArray(Common::Serializer &stream, Common::Array<Common::Rect> &inArray, uint num, Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = Common::Serializer::kLastVersion);
+
 void readFilename(Common::SeekableReadStream &stream, Common::String &inString);
+void readFilename(Common::Serializer &stream, Common::String &inString, Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = Common::Serializer::kLastVersion);
+void readFilenameArray(Common::SeekableReadStream &stream, Common::Array<Common::String> &inArray, uint num);
+void readFilenameArray(Common::Serializer &stream, Common::Array<Common::String> &inArray, uint num, Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = Common::Serializer::kLastVersion);
 
 } // End of namespace Nancy
 


Commit: e2109499bd09e46a629ae300be15861d36a5db8c
    https://github.com/scummvm/scummvm/commit/e2109499bd09e46a629ae300be15861d36a5db8c
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-03-30T20:21:46+03:00

Commit Message:
NANCY: Fix missing underscore in class member name

Changed paths:
    engines/nancy/state/map.cpp
    engines/nancy/state/map.h


diff --git a/engines/nancy/state/map.cpp b/engines/nancy/state/map.cpp
index fee4034797a..de8c8034f3d 100644
--- a/engines/nancy/state/map.cpp
+++ b/engines/nancy/state/map.cpp
@@ -54,8 +54,8 @@ Map::Map() : _state(kInit),
 			_label(7),
 			_closedLabel(7),
 			_background(0) {
-	mapData = g_nancy->_mapData;
-	assert(mapData);
+	_mapData = g_nancy->_mapData;
+	assert(_mapData);
 }
 
 void Map::process() {
@@ -82,7 +82,7 @@ void Map::onStateExit() {
 }
 
 const SoundDescription &Map::getSound() {
-	return mapData->sounds[_mapID];
+	return _mapData->sounds[_mapID];
 }
 
 void Map::load() {
@@ -108,7 +108,7 @@ void Map::setLabel(int labelID) {
 		_closedLabel.setVisible(false);
 	} else {
 		_label.moveTo(_locationLabelDests[labelID]);
-		_label._drawSurface.create(g_nancy->_graphicsManager->_object0, mapData->locations[labelID].labelSrc);
+		_label._drawSurface.create(g_nancy->_graphicsManager->_object0, _mapData->locations[labelID].labelSrc);
 		_label.setVisible(true);
 		_label.setTransparent(true);
 
@@ -164,13 +164,13 @@ void TVDMap::init() {
 	_globe.init();
 
 	Common::Rect textboxScreenPosition = g_nancy->_bootSummary->textboxScreenPosition;
-	_closedLabel._drawSurface.create(g_nancy->_graphicsManager->_object0, mapData->closedLabelSrc);
+	_closedLabel._drawSurface.create(g_nancy->_graphicsManager->_object0, _mapData->closedLabelSrc);
 
 	Common::Rect closedScreenRect;
-	closedScreenRect.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - mapData->closedLabelSrc.width()) / 2);
-	closedScreenRect.right = closedScreenRect.left + mapData->closedLabelSrc.width();
+	closedScreenRect.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - _mapData->closedLabelSrc.width()) / 2);
+	closedScreenRect.right = closedScreenRect.left + _mapData->closedLabelSrc.width();
 	closedScreenRect.bottom = textboxScreenPosition.bottom - 10;
-	closedScreenRect.top = closedScreenRect.bottom - mapData->closedLabelSrc.height();
+	closedScreenRect.top = closedScreenRect.bottom - _mapData->closedLabelSrc.height();
 
 	_closedLabel.moveTo(closedScreenRect);
 	_closedLabel.setTransparent(true);
@@ -179,10 +179,10 @@ void TVDMap::init() {
 	_locationLabelDests.resize(7);
 
 	for (uint i = 0; i < 7; ++i) {
-		_locationLabelDests[i].left = textboxScreenPosition.left + ((textboxScreenPosition.width() - mapData->locations[i].labelSrc.width()) / 2);
-		_locationLabelDests[i].right = _locationLabelDests[i].left + mapData->locations[i].labelSrc.width();
-		_locationLabelDests[i].bottom = closedScreenRect.bottom - ((closedScreenRect.bottom - mapData->locations[i].labelSrc.height() - textboxScreenPosition.top) / 2) - 10;
-		_locationLabelDests[i].top = _locationLabelDests[i].bottom - mapData->locations[i].labelSrc.height();
+		_locationLabelDests[i].left = textboxScreenPosition.left + ((textboxScreenPosition.width() - _mapData->locations[i].labelSrc.width()) / 2);
+		_locationLabelDests[i].right = _locationLabelDests[i].left + _mapData->locations[i].labelSrc.width();
+		_locationLabelDests[i].bottom = closedScreenRect.bottom - ((closedScreenRect.bottom - _mapData->locations[i].labelSrc.height() - textboxScreenPosition.top) / 2) - 10;
+		_locationLabelDests[i].top = _locationLabelDests[i].bottom - _mapData->locations[i].labelSrc.height();
 	}
 
 	_state = kLoad;
@@ -207,7 +207,7 @@ void TVDMap::load() {
 		}
 	}
 
-	_viewport.loadVideo(mapData->mapNames[_mapID], mapData->mapPaletteNames[_mapID]);
+	_viewport.loadVideo(_mapData->mapNames[_mapID], _mapData->mapPaletteNames[_mapID]);
 
 	g_nancy->_cursorManager->setCursorItemID(-1);
 
@@ -227,7 +227,7 @@ void TVDMap::load() {
 
 void TVDMap::onStateExit() {
 	if (_pickedLocationID != -1) {
-		NancySceneState.changeScene(mapData->locations[_pickedLocationID].scenes[NancySceneState.getPlayerTOD() == kPlayerDay ? 0 : 1]);
+		NancySceneState.changeScene(_mapData->locations[_pickedLocationID].scenes[NancySceneState.getPlayerTOD() == kPlayerDay ? 0 : 1]);
 
 		g_nancy->_sound->playSound("BUOK");
 	} else {
@@ -251,7 +251,7 @@ void TVDMap::run() {
 		_globe.handleInput(input);
 
 		for (uint i = 0; i < 7; ++i) {
-			if (_viewport.convertToScreen(mapData->locations[i].hotspot).contains(input.mousePos)) {
+			if (_viewport.convertToScreen(_mapData->locations[i].hotspot).contains(input.mousePos)) {
 				setLabel(i);
 
 				if (_activeLocations[i]){
@@ -277,13 +277,13 @@ void TVDMap::registerGraphics() {
 }
 
 void TVDMap::MapGlobe::init() {
-	moveTo(_owner->mapData->globeDest);
+	moveTo(_owner->_mapData->globeDest);
 
-	_frameTime = _owner->mapData->globeFrameTime;
-	_srcRects = _owner->mapData->globeSrcs;
+	_frameTime = _owner->_mapData->globeFrameTime;
+	_srcRects = _owner->_mapData->globeSrcs;
 
-	_gargoyleEyes._drawSurface.create(g_nancy->_graphicsManager->_object0, _owner->mapData->globeGargoyleSrc);
-	_gargoyleEyes.moveTo(_owner->mapData->globeGargoyleDest);
+	_gargoyleEyes._drawSurface.create(g_nancy->_graphicsManager->_object0, _owner->_mapData->globeGargoyleSrc);
+	_gargoyleEyes.moveTo(_owner->_mapData->globeGargoyleDest);
 	_gargoyleEyes.setTransparent(true);
 	_gargoyleEyes.setVisible(false);
 
@@ -308,7 +308,7 @@ void TVDMap::MapGlobe::onTrigger() {
 		_gargoyleEyes.setVisible(true);
 		_owner->_viewport.setVisible(true);
 		_owner->_viewport.playVideo();
-		g_system->warpMouse(_owner->mapData->cursorPosition.x, _owner->mapData->cursorPosition.y);
+		g_system->warpMouse(_owner->_mapData->cursorPosition.x, _owner->_mapData->cursorPosition.y);
 		g_nancy->setMouseEnabled(true);
 	} else {
 		_owner->_state = kExit;
@@ -327,13 +327,13 @@ void Nancy1Map::init() {
 	_label.init();
 
 	Common::Rect textboxScreenPosition = NancySceneState.getTextbox().getScreenPosition();
-	_closedLabel._drawSurface.create(g_nancy->_graphicsManager->_object0, mapData->closedLabelSrc);
+	_closedLabel._drawSurface.create(g_nancy->_graphicsManager->_object0, _mapData->closedLabelSrc);
 
 	Common::Rect closedScreenRect;
-	closedScreenRect.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - mapData->closedLabelSrc.width()) / 2);
-	closedScreenRect.right = closedScreenRect.left + mapData->closedLabelSrc.width() - 1;
+	closedScreenRect.left = textboxScreenPosition.left + ((textboxScreenPosition.width() - _mapData->closedLabelSrc.width()) / 2);
+	closedScreenRect.right = closedScreenRect.left + _mapData->closedLabelSrc.width() - 1;
 	closedScreenRect.bottom = textboxScreenPosition.bottom - 11;
-	closedScreenRect.top = closedScreenRect.bottom - mapData->closedLabelSrc.height() + 1;
+	closedScreenRect.top = closedScreenRect.bottom - _mapData->closedLabelSrc.height() + 1;
 
 	_closedLabel.moveTo(closedScreenRect);
 
@@ -341,13 +341,13 @@ void Nancy1Map::init() {
 	_locationLabelDests.resize(4);
 
 	for (uint i = 0; i < 4; ++i) {
-		_locationLabelDests[i].left = textboxScreenPosition.left + ((textboxScreenPosition.width() - mapData->locations[i].labelSrc.width()) / 2);
-		_locationLabelDests[i].right = _locationLabelDests[i].left + mapData->locations[i].labelSrc.width() - 1;
-		_locationLabelDests[i].bottom = closedScreenRect.bottom - ((closedScreenRect.bottom - mapData->locations[i].labelSrc.height() - textboxScreenPosition.top) / 2) - 11;
-		_locationLabelDests[i].top = _locationLabelDests[i].bottom - mapData->locations[i].labelSrc.height() + 1;
+		_locationLabelDests[i].left = textboxScreenPosition.left + ((textboxScreenPosition.width() - _mapData->locations[i].labelSrc.width()) / 2);
+		_locationLabelDests[i].right = _locationLabelDests[i].left + _mapData->locations[i].labelSrc.width() - 1;
+		_locationLabelDests[i].bottom = closedScreenRect.bottom - ((closedScreenRect.bottom - _mapData->locations[i].labelSrc.height() - textboxScreenPosition.top) / 2) - 11;
+		_locationLabelDests[i].top = _locationLabelDests[i].bottom - _mapData->locations[i].labelSrc.height() + 1;
 	}
 
-	_button = new UI::Button(9, g_nancy->_graphicsManager->_object0, mapData->buttonSrc, mapData->buttonDest);
+	_button = new UI::Button(9, g_nancy->_graphicsManager->_object0, _mapData->buttonSrc, _mapData->buttonDest);
 	_button->init();
 	_button->setVisible(true);
 
@@ -367,11 +367,11 @@ void Nancy1Map::load() {
 		_mapID = 0;		// Day
 	}
 
-	_viewport.loadVideo(mapData->mapNames[_mapID]);
+	_viewport.loadVideo(_mapData->mapNames[_mapID]);
 
 	setLabel(-1);
 	g_nancy->_cursorManager->setCursorItemID(-1);
-	g_system->warpMouse(mapData->cursorPosition.x, mapData->cursorPosition.y);
+	g_system->warpMouse(_mapData->cursorPosition.x, _mapData->cursorPosition.y);
 
 	if (!g_nancy->_sound->isSoundPlaying(getSound())) {
 		g_nancy->_sound->loadSound(getSound());
@@ -399,7 +399,7 @@ void Nancy1Map::run() {
 	}
 
 	for (uint i = 0; i < 4; ++i) {
-		if (_viewport.convertToScreen(mapData->locations[i].hotspot).contains(input.mousePos)) {
+		if (_viewport.convertToScreen(_mapData->locations[i].hotspot).contains(input.mousePos)) {
 			setLabel(i);
 
 			if (_activeLocations[i]){
@@ -423,7 +423,7 @@ void Nancy1Map::registerGraphics() {
 
 void Nancy1Map::onStateExit() {
 	if (_pickedLocationID != -1) {
-		NancySceneState.changeScene(mapData->locations[_pickedLocationID].scenes[_mapID]);
+		NancySceneState.changeScene(_mapData->locations[_pickedLocationID].scenes[_mapID]);
 
 		g_nancy->_sound->playSound("BUOK");
 	}
diff --git a/engines/nancy/state/map.h b/engines/nancy/state/map.h
index 6313dd58134..63207a25f3d 100644
--- a/engines/nancy/state/map.h
+++ b/engines/nancy/state/map.h
@@ -77,7 +77,7 @@ protected:
 
 	void setLabel(int labelID);
 
-	MAP *mapData;
+	MAP *_mapData;
 
 	MapViewport _viewport;
 	RenderObject _label;




More information about the Scummvm-git-logs mailing list