[Scummvm-git-logs] scummvm master -> 8ab1cfafb42ced6a6f4238a4624847cb34687f5d

bluegr noreply at scummvm.org
Sun Oct 25 01:35:48 UTC 2026


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

Summary:
04e834dea4 NANCY: NANCY16: Draw only the scrolling text lines that fit in their rect
b6c1dc73d7 NANCY: NANCY16: Keep NDUI text on one line when it isn't wrapped
811b7664ee NANCY: NANCY16: Show scrolling text over the scene and only while active
8ab1cfafb4 NANCY: NANCY17: Give a viewed item back when its stream ends


Commit: 04e834dea4f93ba16bafa6022a416a0e96ac4dc3
    https://github.com/scummvm/scummvm/commit/04e834dea4f93ba16bafa6022a416a0e96ac4dc3
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-10-25T03:33:07+03:00

Commit Message:
NANCY: NANCY16: Draw only the scrolling text lines that fit in their rect

Like the original, a line that doesn't fit whole in the rect isn't
drawn; Nancy17's grave quiz showed its answer before it was given

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


diff --git a/engines/nancy/action/autotextscroll.cpp b/engines/nancy/action/autotextscroll.cpp
index 3f62093a7ce..ea0966d7fcf 100644
--- a/engines/nancy/action/autotextscroll.cpp
+++ b/engines/nancy/action/autotextscroll.cpp
@@ -21,6 +21,7 @@
 
 #include "engines/nancy/nancy.h"
 #include "engines/nancy/graphics.h"
+#include "engines/nancy/font.h"
 #include "engines/nancy/enginedata.h"
 #include "engines/nancy/util.h"
 
@@ -151,16 +152,32 @@ void AutotextScroll::update(int32 ticks) {
 void AutotextScroll::redraw() {
 	_drawSurface.clear(_drawSurface.getTransparentColor());
 
+	// A line is drawn only when all of it fits in the rect, whose bottom edge it
+	// can't use; e.g. the name in scene 4580 of Nancy17 is in a rect too small
+	// for it, and doesn't show
+	const Font *font = g_nancy->_graphics->getFont(_fontID);
+	const Common::Rect clip(_bounds.left, _bounds.top, _bounds.right, _bounds.bottom - 1);
+
 	for (const ScrollingText *text : _texts) {
-		Common::Rect dest(_bounds.left, _bounds.top - text->offset, _bounds.left + text->image.w, _bounds.top - text->offset + text->image.h);
-		Common::Rect visible = dest.findIntersectingRect(_bounds);
-		if (visible.isEmpty()) {
-			continue;
-		}
+		const int lineHeight = font ? MAX<int>(font->getFontHeight(), 1) : text->image.h;
+		const int top = _bounds.top - text->offset;
+
+		for (int y = 0; y < text->image.h; y += lineHeight) {
+			if (top + y < clip.top || top + y + lineHeight > clip.bottom) {
+				continue;
+			}
 
-		Common::Rect src = visible;
-		src.translate(-dest.left, -dest.top);
-		_drawSurface.blitFrom(text->image, src, visible.origin());
+			Common::Rect line(_bounds.left, top + y, _bounds.left + text->image.w, top + MIN<int>(y + lineHeight, text->image.h));
+
+			Common::Rect visible = line.findIntersectingRect(clip);
+			if (visible.isEmpty()) {
+				continue;
+			}
+
+			Common::Rect src = visible;
+			src.translate(-_bounds.left, -top);
+			_drawSurface.blitFrom(text->image, src, visible.origin());
+		}
 	}
 
 	_needsRedraw = true;


Commit: b6c1dc73d70f5a95d65e4541cf0fb63a338c33ee
    https://github.com/scummvm/scummvm/commit/b6c1dc73d70f5a95d65e4541cf0fb63a338c33ee
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-10-25T03:34:14+03:00

Commit Message:
NANCY: NANCY16: Keep NDUI text on one line when it isn't wrapped

Text with word wrap off was still wrapped to the width of its rect;
a long name in Nancy17's cell phone list got cut in half

Changed paths:
    engines/nancy/ui/ndui/element.cpp


diff --git a/engines/nancy/ui/ndui/element.cpp b/engines/nancy/ui/ndui/element.cpp
index 94d5d9fcd33..3bd2e9daedb 100644
--- a/engines/nancy/ui/ndui/element.cpp
+++ b/engines/nancy/ui/ndui/element.cpp
@@ -37,6 +37,9 @@ namespace NDUI {
 static const uint32 kDefaultColor = 0xFFFFFFFF;
 static const uint32 kDefaultDisabledColor = 0xC8808080;
 
+// How wide a line of text that doesn't get wrapped can be laid out
+static const int kSingleLineWidth = 1024;
+
 // Lays out text, with its markup, in the font and color of an element
 class ElementText : public Misc::HypertextParser {
 public:
@@ -65,6 +68,21 @@ public:
 		return _fullSurface;
 	}
 
+	// How wide the text drawn by render() is
+	int getDrawnWidth() const {
+		for (int x = _fullSurface.w - 1; x >= 0; --x) {
+			for (int y = 0; y < _fullSurface.h; ++y) {
+				byte a, r, g, b;
+				_fullSurface.format.colorToARGB(_fullSurface.getPixel(x, y), a, r, g, b);
+				if (a) {
+					return x + 1;
+				}
+			}
+		}
+
+		return 0;
+	}
+
 	// The number of lines the text gets wrapped into
 	uint countLines(const Common::String &text, int width, uint fontID) {
 		_fullSurface.create(width, 1, g_nancy->_graphics->getTransparentPixelFormat());
@@ -209,13 +227,24 @@ void Element::drawText(Graphics::ManagedSurface &surface, const Common::String &
 		return;
 	}
 
+	// Text kept on a single line is laid out as wide as it gets, and then aligned
+	// in the rect
 	ElementText layout;
-	const Graphics::ManagedSurface &rendered = layout.render(text, dest.width(), dest.height(), (uint)fontID,
-		colorChannelToByte(color[1]), colorChannelToByte(color[2]), colorChannelToByte(color[3]), _horizontalAlignment, state);
+	const Graphics::ManagedSurface &rendered = layout.render(text, _wordWrap ? dest.width() : kSingleLineWidth, dest.height(), (uint)fontID,
+		colorChannelToByte(color[1]), colorChannelToByte(color[2]), colorChannelToByte(color[3]),
+		_wordWrap ? _horizontalAlignment : (int32)ElementText::kAlignLeft, state);
 
-	// Only text kept on a single line gets aligned vertically
+	int left = dest.left;
+	int width = rendered.w;
 	int top = dest.top;
 	if (!_wordWrap) {
+		width = layout.getDrawnWidth();
+		if (_horizontalAlignment == ElementText::kAlignCenter) {
+			left += (dest.width() - width) / 2;
+		} else if (_horizontalAlignment == ElementText::kAlignRight) {
+			left = dest.right - width;
+		}
+
 		int lineHeight = getFontHeight();
 		if (_verticalAlignment == kAlignVCenter) {
 			top += (dest.height() - lineHeight) / 2;
@@ -234,8 +263,8 @@ void Element::drawText(Graphics::ManagedSurface &surface, const Common::String &
 				continue;
 			}
 
-			for (int x = 0; x < rendered.w; ++x) {
-				int destX = dest.left + x + offset;
+			for (int x = 0; x < width; ++x) {
+				int destX = left + x + offset;
 				if (destX < 0 || destX >= surface.w) {
 					continue;
 				}


Commit: 811b7664eec23271d67fdd60794db778ec3fc5a8
    https://github.com/scummvm/scummvm/commit/811b7664eec23271d67fdd60794db778ec3fc5a8
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-10-25T03:22:35+02:00

Commit Message:
NANCY: NANCY16: Show scrolling text over the scene and only while active

- The text went under the scene's overlays, e.g. the index cards in
  Nancy17's scene 2660. These are now shown correctly
- A record whose dependencies stop holding leaves the screen, instead
  of leaving its text behind

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


diff --git a/engines/nancy/action/autotextscroll.cpp b/engines/nancy/action/autotextscroll.cpp
index ea0966d7fcf..9e463e10962 100644
--- a/engines/nancy/action/autotextscroll.cpp
+++ b/engines/nancy/action/autotextscroll.cpp
@@ -149,6 +149,14 @@ void AutotextScroll::update(int32 ticks) {
 	}
 }
 
+// The text is gone while the record's dependencies don't hold, e.g. the index
+// card in scene 2660 of Nancy17 has a record for every page
+void AutotextScroll::updateGraphics() {
+	if (isVisible() != _isActive) {
+		setVisible(_isActive);
+	}
+}
+
 void AutotextScroll::redraw() {
 	_drawSurface.clear(_drawSurface.getTransparentColor());
 
diff --git a/engines/nancy/action/autotextscroll.h b/engines/nancy/action/autotextscroll.h
index 8348667daae..c52716f2d77 100644
--- a/engines/nancy/action/autotextscroll.h
+++ b/engines/nancy/action/autotextscroll.h
@@ -33,10 +33,12 @@ namespace Action {
 // Once they have all scrolled out of view, an event flag gets set.
 class AutotextScroll : public RenderActionRecord {
 public:
-	AutotextScroll(bool hasDrawingOrder = false) : RenderActionRecord(7), _hasDrawingOrder(hasDrawingOrder) {}
+	// The text goes over the overlays of the scene, e.g. Nancy17's index cards
+	AutotextScroll(bool hasDrawingOrder = false) : RenderActionRecord(15), _hasDrawingOrder(hasDrawingOrder) {}
 	virtual ~AutotextScroll();
 
 	void init() override;
+	void updateGraphics() override;
 
 	void readData(Common::SeekableReadStream &stream) override;
 	void execute() override;


Commit: 8ab1cfafb42ced6a6f4238a4624847cb34687f5d
    https://github.com/scummvm/scummvm/commit/8ab1cfafb42ced6a6f4238a4624847cb34687f5d
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-10-25T03:27:01+02:00

Commit Message:
NANCY: NANCY17: Give a viewed item back when its stream ends

The item's scene only ends the stream; like the original, the
engine puts the item back then. This caused the "Short Stories" book to
be lost after reading it, which kept scene 2660's librarian clue from
playing

Changed paths:
    engines/nancy/state/scenestream.cpp


diff --git a/engines/nancy/state/scenestream.cpp b/engines/nancy/state/scenestream.cpp
index f93e04acda4..53e46b25bd2 100644
--- a/engines/nancy/state/scenestream.cpp
+++ b/engines/nancy/state/scenestream.cpp
@@ -32,6 +32,7 @@
 #include "engines/nancy/state/scenestream.h"
 
 #include "engines/nancy/ui/viewport.h"
+#include "engines/nancy/ui/ndui/button.h"
 
 #ifdef ENABLE_NANCY_V4
 #include "engines/nancy/script/records.h"
@@ -541,6 +542,23 @@ Common::String SceneStreamManager::getSceneName(const Common::String &name) cons
 	return stream ? stream->getSceneName() : Common::String();
 }
 
+// Nancy17 takes an item out of the inventory while its scene is up, in a stream
+// named after it. The item's scene doesn't put it back: the stream ending does.
+static void returnViewedItem(const Common::String &streamName) {
+	const INVD *items = GetEngineData(INVD);
+	if (!items || g_nancy->getGameType() >= kGameTypeNancy19) {
+		return;
+	}
+
+	for (const INVD::Item &item : items->items) {
+		if (item.kind == UI::NDUI::InvButton::kItemView &&
+				streamName.equalsIgnoreCase(UI::NDUI::InvButton::getStreamName(item.name))) {
+			NancySceneState.addItemToInventory(item.id);
+			return;
+		}
+	}
+}
+
 void SceneStreamManager::process() {
 	if (_streams.empty()) {
 		NancySceneState.processMainStream();
@@ -567,6 +585,7 @@ void SceneStreamManager::process() {
 	for (uint i = 0; i < _streams.size(); ) {
 		if (_streams[i] && _streams[i]->isEnded()) {
 			_streams[i]->endScene();
+			returnViewedItem(_streams[i]->getName());
 			delete _streams[i];
 			_streams.remove_at(i);
 		} else {




More information about the Scummvm-git-logs mailing list