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

fracturehill noreply at scummvm.org
Thu Feb 8 22:13:11 UTC 2024


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

Summary:
0b8e43f65f NANCY: Implement jornal-editing action records
b51cb98d42 NANCY: Read MARK chunk
80d351969d NANCY: Implement TextScroll and AutotextEntryList
ff39bce6ea NANCY: Implement drawing Autotext marks


Commit: 0b8e43f65f8ee470fb8bc281dab1ea96638fd3c9
    https://github.com/scummvm/scummvm/commit/0b8e43f65f8ee470fb8bc281dab1ea96638fd3c9
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-08T23:12:14+01:00

Commit Message:
NANCY: Implement jornal-editing action records

Implemented the AddListEntry, DeleteListEntry, and
MarkListEntry action records. These are responsible for
modifying the list of autotext strings for each autotext
surface. Also, the JournalData struct now includes data
for entry marking. The last change breaks compatibility
with nancy6+ saves.

Changed paths:
    engines/nancy/action/arfactory.cpp
    engines/nancy/action/autotext.cpp
    engines/nancy/action/datarecords.cpp
    engines/nancy/action/datarecords.h
    engines/nancy/puzzledata.cpp
    engines/nancy/puzzledata.h


diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 185a11f5feb..4a972ac9b52 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -181,6 +181,12 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 		return new TableIndexPlaySound();
 	case 67:
 		return new TableIndexSetValueHS();
+	case 71:
+		return new ModifyListEntry(ModifyListEntry::kAdd);
+	case 72:
+		return new ModifyListEntry(ModifyListEntry::kDelete);
+	case 73:
+		return new ModifyListEntry(ModifyListEntry::kMark);
 	case 75:
 		return new TextBoxWrite();
 	case 76:
diff --git a/engines/nancy/action/autotext.cpp b/engines/nancy/action/autotext.cpp
index bacf644ab3a..83429ea203b 100644
--- a/engines/nancy/action/autotext.cpp
+++ b/engines/nancy/action/autotext.cpp
@@ -89,7 +89,8 @@ void Autotext::execute() {
 		Common::String stringToPush;
 		auto &entriesForSurface = journalData->journalEntries[_surfaceID];
 		bool foundThisKey = false;
-		for (auto &stringID : entriesForSurface) {
+		for (auto &entry : entriesForSurface) {
+			Common::String &stringID = entry.stringID;
 			stringToPush += autotext->texts[stringID];
 			if (stringID == _textKey) {
 				foundThisKey = true;
@@ -100,11 +101,11 @@ void Autotext::execute() {
 			// Key inside this Autotext instance wasn't found inside existing list, push it back and add it to string to draw
 			if (!isLIFO) {
 				// Push at end
-				entriesForSurface.push_back(_textKey);
+				entriesForSurface.push_back(JournalData::Entry(_textKey));
 				stringToPush += autotext->texts[_textKey];
 			} else {
 				// Insert at front
-				entriesForSurface.insert_at(0, _textKey);
+				entriesForSurface.insert_at(0, JournalData::Entry(_textKey));
 				stringToPush = autotext->texts[_textKey] + stringToPush;
 			}
 		}
diff --git a/engines/nancy/action/datarecords.cpp b/engines/nancy/action/datarecords.cpp
index 641ec2ff534..13468bcafff 100644
--- a/engines/nancy/action/datarecords.cpp
+++ b/engines/nancy/action/datarecords.cpp
@@ -402,5 +402,62 @@ void DifficultyLevel::execute() {
 	_isDone = true;
 }
 
+void ModifyListEntry::readData(Common::SeekableReadStream &stream) {
+	_surfaceID = stream.readUint16LE();
+	readFilename(stream, _stringID);
+	_mark = stream.readUint16LE();
+}
+
+void ModifyListEntry::execute() {
+	JournalData *journalData = (Nancy::JournalData *)NancySceneState.getPuzzleData(Nancy::JournalData::getTag());
+	assert(journalData);
+
+	Common::Array<JournalData::Entry> &array = journalData->journalEntries[_surfaceID];
+
+	JournalData::Entry *found = nullptr;
+	for (uint i = 0; i < array.size(); ++i) {
+		if (array[i].stringID == _stringID) {
+			found = &array[i];
+			break;
+		}
+	}
+
+	switch (_type) {
+	case kAdd:
+		if (!found) {
+			array.push_back(JournalData::Entry(_stringID, _mark));
+		}
+
+		break;
+	case kDelete:
+		if (found) {
+			array.erase(found);
+		}
+
+		break;
+	case kMark:
+		if (found) {
+			found->mark = _mark;
+		}
+
+		break;
+	}
+
+	finishExecution();
+}
+
+Common::String ModifyListEntry::getRecordTypeName() const {
+	switch (_type) {
+	case kAdd:
+		return "AddListEntry";
+	case kDelete:
+		return "DeleteListEntry";
+	case kMark:
+		return "MarkListEntry";
+	}
+
+	return "";
+}
+
 } // End of namespace Action
 } // End of namespace Nancy
diff --git a/engines/nancy/action/datarecords.h b/engines/nancy/action/datarecords.h
index 7848423be1e..972faff6f73 100644
--- a/engines/nancy/action/datarecords.h
+++ b/engines/nancy/action/datarecords.h
@@ -147,6 +147,26 @@ protected:
 	Common::String getRecordTypeName() const override { return "DifficultyLevel"; }
 };
 
+class ModifyListEntry : public ActionRecord {
+public:
+	enum Type { kAdd, kDelete, kMark };
+
+	ModifyListEntry(Type type) : _type(type) {}
+	virtual ~ModifyListEntry() {}
+
+	void readData(Common::SeekableReadStream &stream) override;
+	void execute() override;
+
+	Type _type;
+
+	uint16 _surfaceID = 0;
+	Common::String _stringID;
+	uint16 _mark = 0;
+
+protected:
+	Common::String getRecordTypeName() const override;
+};
+
 } // End of namespace Action
 } // End of namespace Nancy
 
diff --git a/engines/nancy/puzzledata.cpp b/engines/nancy/puzzledata.cpp
index 310968f73ac..08b39d7681f 100644
--- a/engines/nancy/puzzledata.cpp
+++ b/engines/nancy/puzzledata.cpp
@@ -126,9 +126,9 @@ void JournalData::synchronize(Common::Serializer &ser) {
 			ser.syncAsUint16LE(numStrings);
 			auto &entry = journalEntries[id];
 			for (uint j = 0; j < numStrings; ++j) {
-				Common::String l;
-				ser.syncString(l);
-				entry.push_back(l);
+				entry.push_back(Entry());
+				ser.syncString(entry.back().stringID);
+				ser.syncAsUint16LE(entry.back().mark);
 			}
 		}
 	} else {
@@ -138,7 +138,8 @@ void JournalData::synchronize(Common::Serializer &ser) {
 			uint16 numStrings = a._value.size();
 			ser.syncAsUint16LE(numStrings);
 			for (uint i = 0; i < numStrings; ++i) {
-				ser.syncString(a._value[i]);
+				ser.syncString(a._value[i].stringID);
+				ser.syncAsUint16LE(a._value[i].mark);
 			}
 		}
 	}
diff --git a/engines/nancy/puzzledata.h b/engines/nancy/puzzledata.h
index 039117e2905..9aa3b9a3725 100644
--- a/engines/nancy/puzzledata.h
+++ b/engines/nancy/puzzledata.h
@@ -111,10 +111,17 @@ struct JournalData : public PuzzleData {
 	JournalData() {}
 	virtual ~JournalData() {}
 
+	struct Entry {
+		Entry(const Common::String &s = Common::String(), int16 m = 0) : stringID(s), mark(m) {}
+
+		Common::String stringID;
+		uint16 mark = 0;
+	};
+
 	static constexpr uint32 getTag() { return MKTAG('J', 'O', 'U', 'R'); }
 	virtual void synchronize(Common::Serializer &ser);
 
-	Common::HashMap<uint16, Common::Array<Common::String>> journalEntries;
+	Common::HashMap<uint16, Common::Array<Entry>> journalEntries;
 };
 
 // Contains variables that can be read and modified through action records.


Commit: b51cb98d4247106a9745ff5858a863c197b8f6f5
    https://github.com/scummvm/scummvm/commit/b51cb98d4247106a9745ff5858a863c197b8f6f5
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-08T23:12:14+01:00

Commit Message:
NANCY: Read MARK chunk

Added a struct corresponding to the MARK boot chunk,
which contains the source rects for the autotext markings
introduced in nancy8 (and used in the journal).

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


diff --git a/engines/nancy/enginedata.cpp b/engines/nancy/enginedata.cpp
index 21c3d212ee5..0f3114e5b0b 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -809,4 +809,8 @@ TABL::TABL(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
 	chunkStream->skip((20 - numEntries) * 1000);
 }
 
+MARK::MARK(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
+	readRectArray(*chunkStream, _markSrcs, 5);
+}
+
 } // End of namespace Nancy
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index 57f7a203c0e..627a7ba0e61 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -489,6 +489,12 @@ struct TABL : public EngineData {
 	Common::Array<Common::String> strings;
 };
 
+struct MARK : public EngineData {
+	MARK(Common::SeekableReadStream *chunkStream);
+
+	Common::Array<Common::Rect> _markSrcs;
+};
+
 } // End of namespace Nancy
 
 #endif // NANCY_ENGINEDATA_H
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index af0074afc6b..283711ff744 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -454,6 +454,7 @@ void NancyEngine::bootGameEngine() {
 	LOAD_BOOT(RCPR)
 	LOAD_BOOT(RCLB)
 	LOAD_BOOT(TABL)
+	LOAD_BOOT(MARK)
 
 	if (g_nancy->getGameType() <= kGameTypeNancy7) {
 		LOAD_BOOT(LOAD)


Commit: 80d351969dd4d0061948252bce4cbcc406e762e6
    https://github.com/scummvm/scummvm/commit/80d351969dd4d0061948252bce4cbcc406e762e6
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-08T23:12:14+01:00

Commit Message:
NANCY: Implement TextScroll and AutotextEntryList

Added support for the record types that replaced the bare
Autotext, and combined it with a PeepholePuzzle. This
necessitates some ugly, diamond-shaped multiple
inheritance, but the original engine's solution of replacing
the current record with a different type one at runtime
is even uglier. Also, made changes to Autotext to correctly
support LIFO ordering.

Changed paths:
    engines/nancy/action/actionmanager.cpp
    engines/nancy/action/actionrecord.h
    engines/nancy/action/arfactory.cpp
    engines/nancy/action/autotext.cpp
    engines/nancy/action/autotext.h
    engines/nancy/action/puzzle/peepholepuzzle.cpp
    engines/nancy/action/puzzle/peepholepuzzle.h
    engines/nancy/commontypes.h


diff --git a/engines/nancy/action/actionmanager.cpp b/engines/nancy/action/actionmanager.cpp
index 3ef59039dac..67ece7a8d07 100644
--- a/engines/nancy/action/actionmanager.cpp
+++ b/engines/nancy/action/actionmanager.cpp
@@ -647,9 +647,9 @@ void ActionManager::synchronizeMovieWithSound() {
 		byte type = _activatedRecordsThisFrame[i]->_type;
 		// Rely on _type for cheaper type check
 		if (type == 53) {
-			movie = (PlaySecondaryMovie *)_activatedRecordsThisFrame[i];
+			movie = dynamic_cast<PlaySecondaryMovie *>(_activatedRecordsThisFrame[i]);
 		} else if (type == 150 || type == 151 || type == 157) {
-			sound = (PlaySound *)_activatedRecordsThisFrame[i];
+			sound = dynamic_cast<PlaySound *>(_activatedRecordsThisFrame[i]);
 		}
 
 		if (movie && sound) {
diff --git a/engines/nancy/action/actionrecord.h b/engines/nancy/action/actionrecord.h
index 076befa7247..7cb72f8da14 100644
--- a/engines/nancy/action/actionrecord.h
+++ b/engines/nancy/action/actionrecord.h
@@ -146,7 +146,7 @@ public:
 };
 
 // Base class for visual ActionRecords
-class RenderActionRecord : public ActionRecord, public RenderObject {
+class RenderActionRecord : public virtual ActionRecord, public RenderObject {
 public:
 	RenderActionRecord(uint zOrder) : RenderObject(zOrder) {}
 	virtual ~RenderActionRecord() {}
diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 4a972ac9b52..403898feb5e 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -181,6 +181,10 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
 		return new TableIndexPlaySound();
 	case 67:
 		return new TableIndexSetValueHS();
+	case 68:
+		return new TextScroll(false);
+	case 70:
+		return new TextScroll(true); // AutotextEntryList
 	case 71:
 		return new ModifyListEntry(ModifyListEntry::kAdd);
 	case 72:
diff --git a/engines/nancy/action/autotext.cpp b/engines/nancy/action/autotext.cpp
index 83429ea203b..c6f4c7deb8a 100644
--- a/engines/nancy/action/autotext.cpp
+++ b/engines/nancy/action/autotext.cpp
@@ -54,9 +54,12 @@ void Autotext::readData(Common::SeekableReadStream &stream) {
 
 		setImageName(imageName);
 	}
-
 	stream.skip((5 - numImages) * (2 + 16));
 
+	readExtraData(stream);
+}
+
+void Autotext::readExtraData(Common::SeekableReadStream &stream) {
 	_useAutotextChunk = stream.readByte();
 	readFilename(stream, _textKey);
 
@@ -81,9 +84,12 @@ void Autotext::execute() {
 		const CVTX *autotext = (const CVTX *)g_nancy->getEngineData("AUTOTEXT");
 		assert(autotext);
 
-		bool isLIFO = (g_nancy->getGameType() == kGameTypeNancy7) && _surfaceID > 5; // This is nancy7-specific, later games implement LIFO in a different way
-		if (isLIFO) {
-			_surfaceID -= 3;
+		if (g_nancy->getGameType() == kGameTypeNancy7) {
+			// In nancy7 ONLY, ids 6, 7 & 8 mean LIFO ordering for a suface
+			if (_surfaceID > 5) {
+				_order = kListLIFO;
+				_surfaceID -= 3;
+			}
 		}
 
 		Common::String stringToPush;
@@ -91,23 +97,33 @@ void Autotext::execute() {
 		bool foundThisKey = false;
 		for (auto &entry : entriesForSurface) {
 			Common::String &stringID = entry.stringID;
-			stringToPush += autotext->texts[stringID];
-			if (stringID == _textKey) {
+
+			if (_order == kListFIFO) {
+				// Add to end of string
+				stringToPush += autotext->texts[stringID];
+			} else {
+				// Add to front of string
+				stringToPush = autotext->texts[stringID] + stringToPush;
+			}
+			
+			if (!_textKey.empty() && stringID == _textKey) {
 				foundThisKey = true;
 			}
 		}
 
-		if (!foundThisKey) {
+		// A text key may not be present in the data (see AutotextEntryList), so do not attempt to add to the list then
+		if (!foundThisKey && !_textKey.empty()) {
 			// Key inside this Autotext instance wasn't found inside existing list, push it back and add it to string to draw
-			if (!isLIFO) {
-				// Push at end
-				entriesForSurface.push_back(JournalData::Entry(_textKey));
+			if (_order == kListFIFO) {
+				// Add to end of string
 				stringToPush += autotext->texts[_textKey];
 			} else {
-				// Insert at front
-				entriesForSurface.insert_at(0, JournalData::Entry(_textKey));
+				// Add to front of string
 				stringToPush = autotext->texts[_textKey] + stringToPush;
 			}
+
+			// Entry is always added to end; on-screen ordering happens when reading list
+			entriesForSurface.push_back(JournalData::Entry(_textKey));
 		}
 
 		addTextLine(stringToPush);
diff --git a/engines/nancy/action/autotext.h b/engines/nancy/action/autotext.h
index 95684d4d5c0..c7375752c6a 100644
--- a/engines/nancy/action/autotext.h
+++ b/engines/nancy/action/autotext.h
@@ -33,7 +33,7 @@ namespace Action {
 // after a scene change, or for permanent storage (used in nancy's journal)
 // Does not own or display any image data; it draws to a surface inside
 // GraphicsManager, which other ActionRecords (Overlay and PeepholePuzzle) can use.
-class Autotext : public ActionRecord, public Misc::HypertextParser {
+class Autotext : public virtual ActionRecord, public Misc::HypertextParser {
 public:
 	Autotext() {}
 	virtual ~Autotext() {}
@@ -44,6 +44,8 @@ public:
 protected:
 	Common::String getRecordTypeName() const override { return "Autotext"; }
 
+	virtual void readExtraData(Common::SeekableReadStream &stream);
+
 	uint16 _transparency = kPlayOverlayPlain;
 	uint16 _surfaceID = 0;
 	uint16 _fontID = 0;
@@ -54,10 +56,13 @@ protected:
 
 	bool _useAutotextChunk = false;
 
-	// Only one of these is valid
+	// Only one of these can be valid
 	Common::String _textKey;
 	Common::String _embeddedText;
 
+	uint16 _order = kListFIFO;
+	bool _shouldDrawMarks = false; // currently unused
+
 	Graphics::ManagedSurface _image;
 };
 
diff --git a/engines/nancy/action/puzzle/peepholepuzzle.cpp b/engines/nancy/action/puzzle/peepholepuzzle.cpp
index 864d991674c..f04aa2c8ab3 100644
--- a/engines/nancy/action/puzzle/peepholepuzzle.cpp
+++ b/engines/nancy/action/puzzle/peepholepuzzle.cpp
@@ -55,7 +55,7 @@ void PeepholePuzzle::init() {
 
 	_currentSrc = _startSrc;
 
-	setTransparent(true);
+	setTransparent(_transparency == kPlayOverlayTransparent);
 	_drawSurface.clear(_drawSurface.getTransparentColor());
 	setVisible(true);
 
@@ -289,5 +289,48 @@ void PeepholePuzzle::checkButtons() {
 	}
 }
 
+void TextScroll::init() {
+	Autotext::execute();
+	_isDone = false; // Set to true by Autotext
+
+	// Supply the correct names to the resource manager
+	if (_surfaceID < 3) {
+		_innerImageName = Common::String::format("USE_AUTOTEXT%u", _surfaceID + 1);
+	} else {
+		_innerImageName = Common::String::format("USE_AUTOLIST%u", _surfaceID - 2);
+	}
+
+	// Make sure the initial bounds match the surface's
+	_innerBounds = _fullSurface.getBounds();
+
+	PeepholePuzzle::init();
+}
+
+void TextScroll::readData(Common::SeekableReadStream &stream) {
+	Autotext::readData(stream);
+
+	PeepholePuzzle::_transparency = Autotext::_transparency;
+}
+
+void TextScroll::readExtraData(Common::SeekableReadStream &stream) {
+	_order = stream.readUint16LE();
+	_shouldDrawMarks = stream.readByte();
+
+	readFilename(stream, _buttonsImageName);
+
+	readRect(stream, _startSrc);
+	readRect(stream, _dest);
+
+	readRectArray(stream, _buttonDests, 4);
+	readRectArray(stream, _buttonSrcs, 4);
+	readRectArray(stream, _buttonDisabledSrcs, 4);
+
+	_pixelsToScroll = stream.readByte();
+
+	if (!_isEntryList) {
+		Autotext::readExtraData(stream);
+	}
+}
+
 } // End of namespace Action
 } // End of namespace Nancy
diff --git a/engines/nancy/action/puzzle/peepholepuzzle.h b/engines/nancy/action/puzzle/peepholepuzzle.h
index f4ef770a51f..53d818b02fa 100644
--- a/engines/nancy/action/puzzle/peepholepuzzle.h
+++ b/engines/nancy/action/puzzle/peepholepuzzle.h
@@ -22,7 +22,7 @@
 #ifndef NANCY_ACTION_PEEPHOLEPUZZLE_H
 #define NANCY_ACTION_PEEPHOLEPUZZLE_H
 
-#include "engines/nancy/action/actionrecord.h"
+#include "engines/nancy/action/autotext.h"
 
 namespace Nancy {
 namespace Action {
@@ -75,6 +75,26 @@ protected:
 	Common::Array<bool> _disabledButtons = Common::Array<bool>(4, false);
 };
 
+// Combines the Peephole with the Autotext used to supply its text data
+// Implementing this with diamond-shaped multiple inheritance is bad,
+// but so is the original design, where a Peephole is constructed
+// on the fly and replaces the TextScroll/AutotextEntryList
+class TextScroll : public Autotext, public PeepholePuzzle {
+public:
+	TextScroll(bool isEntryList) : _isEntryList(isEntryList) {}
+
+	void init() override;
+	void execute() override { PeepholePuzzle::execute(); }
+
+	void readData(Common::SeekableReadStream &stream) override;
+
+protected:
+	Common::String getRecordTypeName() const override { return _isEntryList ? "AutotextEntryList" : "TextScroll"; }
+	void readExtraData(Common::SeekableReadStream &stream) override;
+
+	bool _isEntryList;
+};
+
 } // End of namespace Action
 } // End of namespace Nancy
 
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index 7463b5ec66c..1b783a6c775 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -120,6 +120,10 @@ static const byte kDecrementTableValue				= 2;
 static const uint16 kNoTableIndex					= 99;
 static const int16 kNoTableValue					= 9999;
 
+// Autotext ordering info
+static const uint16 kListLIFO						= 0;
+static const uint16 kListFIFO						= 1;
+
 // 3D sound rotation
 static const byte kRotateAroundX					= 0;
 static const byte kRotateAroundY					= 1;


Commit: ff39bce6ea34a5e588adb2c2efa1b660d63133c9
    https://github.com/scummvm/scummvm/commit/ff39bce6ea34a5e588adb2c2efa1b660d63133c9
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-08T23:12:33+01:00

Commit Message:
NANCY: Implement drawing Autotext marks

Marks are the special symbols introduced in nancy8,
and are used in the task list to mark done/not done tasks
using a checkmark graphic.

Changed paths:
    engines/nancy/action/autotext.cpp
    engines/nancy/misc/hypertext.cpp
    engines/nancy/misc/hypertext.h


diff --git a/engines/nancy/action/autotext.cpp b/engines/nancy/action/autotext.cpp
index c6f4c7deb8a..aad4f5c0984 100644
--- a/engines/nancy/action/autotext.cpp
+++ b/engines/nancy/action/autotext.cpp
@@ -97,13 +97,14 @@ void Autotext::execute() {
 		bool foundThisKey = false;
 		for (auto &entry : entriesForSurface) {
 			Common::String &stringID = entry.stringID;
+			Common::String markString = entry.mark ? Common::String::format("<%u>", entry.mark) : "";
 
 			if (_order == kListFIFO) {
 				// Add to end of string
-				stringToPush += autotext->texts[stringID];
+				stringToPush += (markString + autotext->texts[stringID]);
 			} else {
 				// Add to front of string
-				stringToPush = autotext->texts[stringID] + stringToPush;
+				stringToPush = markString + autotext->texts[stringID] + stringToPush;
 			}
 			
 			if (!_textKey.empty() && stringID == _textKey) {
diff --git a/engines/nancy/misc/hypertext.cpp b/engines/nancy/misc/hypertext.cpp
index 9db0385cefe..bcd97a82ed2 100644
--- a/engines/nancy/misc/hypertext.cpp
+++ b/engines/nancy/misc/hypertext.cpp
@@ -29,10 +29,12 @@
 namespace Nancy {
 namespace Misc {
 
-struct ColorFontChange {
-	bool isFont;
+struct MetaInfo {
+	enum Type { kColor, kFont, kMark };
+
+	Type type;
 	uint numChars;
-	byte colorOrFontID;
+	byte index;
 };
 
 void HypertextParser::initSurfaces(uint width, uint height, const Graphics::PixelFormat &format, uint32 backgroundColor, uint32 highlightBackgroundColor) {
@@ -75,7 +77,7 @@ void HypertextParser::drawAllText(const Common::Rect &textBounds, uint leftOffse
 		Common::String currentLine;
 		bool hasHotspot = false;
 		Rect hotspot;
-		Common::Queue<ColorFontChange> colorTextChanges;
+		Common::Queue<MetaInfo> metaInfo;
 		Common::Queue<uint16> newlineTokens;
 		newlineTokens.push(0);
 		int curFontID = fontID;
@@ -148,7 +150,7 @@ void HypertextParser::drawAllText(const Common::Rect &textBounds, uint leftOffse
 						break;
 					}
 					
-					colorTextChanges.push({false, numNonSpaceChars, (byte)(curToken[1] - 48)});
+					metaInfo.push({MetaInfo::kColor, numNonSpaceChars, (byte)(curToken[1] - '0')});
 					continue;
 				case 'f' :
 					// Font token
@@ -157,7 +159,18 @@ void HypertextParser::drawAllText(const Common::Rect &textBounds, uint leftOffse
 						break;
 					}
 
-					colorTextChanges.push({true, numNonSpaceChars, (byte)(curToken[1] - 48)});
+					metaInfo.push({MetaInfo::kFont, numNonSpaceChars, (byte)(curToken[1] - '0')});
+					continue;
+				case '1':
+				case '2':
+				case '3':
+				case '4':
+				case '5':
+					if (curToken.size() != 1) {
+						break;
+					}
+
+					metaInfo.push({MetaInfo::kMark, numNonSpaceChars, (byte)(curToken[0] - '1')});
 					continue;
 				default:
 					break;
@@ -258,20 +271,48 @@ void HypertextParser::drawAllText(const Common::Rect &textBounds, uint leftOffse
 			while (!line.empty()) {
 				Common::String subLine;
 
-				while (colorTextChanges.size() && totalCharsDrawn >= colorTextChanges.front().numChars) {
-					// We have a color/font change token at begginning of (what's left of) the current line
-					ColorFontChange change = colorTextChanges.pop();
-					if (change.isFont) {
-						curFontID = change.colorOrFontID;
+				while (metaInfo.size() && totalCharsDrawn >= metaInfo.front().numChars) {
+					// We have a color/font change token, or a mark at begginning of (what's left of) the current line
+					MetaInfo change = metaInfo.pop();
+					switch (change.type) {
+					case MetaInfo::kFont:
+						curFontID = change.index;
 						font = g_nancy->_graphicsManager->getFont(curFontID);
-					} else {
-						colorID = change.colorOrFontID;
+						break;
+					case MetaInfo::kColor:
+						colorID = change.index;
+						break;
+					case MetaInfo::kMark: {
+						auto *mark = GetEngineData(MARK);
+						assert(mark);
+
+						if (lineNumber == 0) {
+							// A mark on the first line pushes up all text
+							if (textBounds.top - _imageVerticalOffset > 3) {
+								_imageVerticalOffset -= 3;
+							} else {
+								_imageVerticalOffset = -textBounds.top;
+							}
+						}
+
+						Common::Rect markSrc = mark->_markSrcs[change.index];
+						Common::Rect markDest = markSrc;
+						markDest.moveTo(textBounds.left + horizontalOffset + (newLineStart ? 0 : leftOffsetNonNewline) + 1,
+							lineNumber == 0 ? 
+								textBounds.top - ((font->getFontHeight() + 1) / 2) + _imageVerticalOffset + 4 :
+								textBounds.top + _numDrawnLines * font->getFontHeight() + _imageVerticalOffset - 4);
+
+						// For now we do not check if we need to go to new line; neither does the original
+						_fullSurface.blitFrom(g_nancy->_graphicsManager->_object0, markSrc, markDest);
+
+						horizontalOffset += markDest.width() + 2;
+					}
 					}
 				}
 
-				if (colorTextChanges.size() && totalCharsDrawn < colorTextChanges.front().numChars && colorTextChanges.front().numChars < (totalCharsDrawn + line.size())) {
+				if (metaInfo.size() && totalCharsDrawn < metaInfo.front().numChars && metaInfo.front().numChars < (totalCharsDrawn + line.size())) {
 					// There's a token inside the current line, so split off the part before it
-					subLine = line.substr(0, colorTextChanges.front().numChars - totalCharsDrawn);
+					subLine = line.substr(0, metaInfo.front().numChars - totalCharsDrawn);
 					line = line.substr(subLine.size());
 				}
 
diff --git a/engines/nancy/misc/hypertext.h b/engines/nancy/misc/hypertext.h
index 67459881ed8..3e683ea8560 100644
--- a/engines/nancy/misc/hypertext.h
+++ b/engines/nancy/misc/hypertext.h
@@ -59,7 +59,7 @@ protected:
 	uint32 _backgroundColor;
 	uint32 _highlightBackgroundColor;
 	uint _defaultTextColor;
-	uint _imageVerticalOffset;
+	int _imageVerticalOffset;
 
 	Common::Array<Common::String> _textLines;
 	Common::Array<Common::Rect> _hotspots;




More information about the Scummvm-git-logs mailing list