[Scummvm-git-logs] scummvm master -> f40fdd132e55b0959fc7afcb62232996ad92ceee
bluegr
noreply at scummvm.org
Sun Sep 20 15:53:00 UTC 2026
This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
33375061a2 NANCY: Allow more types of videos to be skipped with the escape key
ba5f0a3b76 NANCY: NANCY10-15: Fix the cellphone e-mail list and zoomed screens
1120653960 NANCY: NANCY15: Handle new INV chunk format for the game inventory
850c5af490 NANCY: Don't let button sounds swallow input in dial/phone records
f40fdd132e NANCY: Fix missing hotspot cursor for script-set cursor type 0
Commit: 33375061a208f78bdc76973340626fb55643eb48
https://github.com/scummvm/scummvm/commit/33375061a208f78bdc76973340626fb55643eb48
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-20T16:21:23+03:00
Commit Message:
NANCY: Allow more types of videos to be skipped with the escape key
Changed paths:
engines/nancy/action/secondarymovie.cpp
engines/nancy/action/secondarymovie.h
diff --git a/engines/nancy/action/secondarymovie.cpp b/engines/nancy/action/secondarymovie.cpp
index 78b243d1302..b9e0e7e3d70 100644
--- a/engines/nancy/action/secondarymovie.cpp
+++ b/engines/nancy/action/secondarymovie.cpp
@@ -1306,8 +1306,28 @@ void PlaySecondaryMovie::execute() {
}
}
+bool PlaySecondaryMovie::isSkippable() {
+ // Interactive videos (AR 47) wait for the player to click their hotspots,
+ // so they must play out in full.
+ if (isRandom() || _movieType == kInteractiveMovie || _state != kRun) {
+ return false;
+ }
+
+ // Movies that hide the player cursor are cinematics by definition.
+ if (_playerCursorAllowed == kNoPlayerCursorAllowed) {
+ return true;
+ }
+
+ // Some records (Nancy14's AR 44 in particular) leave the cursor enabled
+ // while still playing a cutscene over the whole viewport. Those count as
+ // cinematics as well, as long as they are not looping forever - an endless
+ // loop is an ambient animation the player isn't waiting on.
+ return _numLoops != 0 &&
+ Common::Rect(_decoder.getWidth(), _decoder.getHeight()) == NancySceneState.getViewport().getBounds();
+}
+
void PlaySecondaryMovie::skip() {
- if (isRandom() || _state != kRun || _playerCursorAllowed != kNoPlayerCursorAllowed) {
+ if (!isSkippable()) {
return;
}
diff --git a/engines/nancy/action/secondarymovie.h b/engines/nancy/action/secondarymovie.h
index ce1a125f066..a7719e7842f 100644
--- a/engines/nancy/action/secondarymovie.h
+++ b/engines/nancy/action/secondarymovie.h
@@ -120,8 +120,8 @@ public:
bool getIsFinished() const { return _isFinished; }
// Enhancement: jump a cinematic straight to its end, as if it had finished
- // playing on its own. Only movies that hide the player cursor are skipped;
- // the rest are background animations the player isn't waiting on.
+ // playing on its own. Only cinematics are skipped; background animations
+ // the player isn't waiting on keep playing.
void skip();
Common::Path _videoName;
@@ -184,6 +184,10 @@ public:
bool isRandom() const { return _movieType == kRandomMovie; }
+ // Whether skip() applies: a movie the player is waiting through, either
+ // because it hides the cursor or because it covers the whole viewport.
+ bool isSkippable();
+
// Random-movie state (only populated for kRandomMovie).
// "RandomMovie" picks any sequence; otherwise it names the starting one.
Common::String _startingSequenceName;
Commit: ba5f0a3b762db07a269e824f8caf11bd77cb7d3e
https://github.com/scummvm/scummvm/commit/ba5f0a3b762db07a269e824f8caf11bd77cb7d3e
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-20T16:26:53+03:00
Commit Message:
NANCY: NANCY10-15: Fix the cellphone e-mail list and zoomed screens
- Fix drawing of the envelope icone in the e-mail screens
- Skip inbox rows whose subject key has no AUTOTEXT entry
- Derive the keypad-less chrome rectangle used by the e-mail, browser
and search screens when it disagrees with the size of the normal
layout. Nancy15 enlarged the phone graphic without updating
fullEmptyScreenSrc
Changed paths:
engines/nancy/ui/cellphonepopup.cpp
engines/nancy/ui/cellphonepopup.h
diff --git a/engines/nancy/ui/cellphonepopup.cpp b/engines/nancy/ui/cellphonepopup.cpp
index ad46d4be08e..81d53451128 100644
--- a/engines/nancy/ui/cellphonepopup.cpp
+++ b/engines/nancy/ui/cellphonepopup.cpp
@@ -533,15 +533,28 @@ void CellPhonePopup::updateGraphics() {
// Drawing
// --------------------------------------------------------------------
+// The keypad-less chrome variant, stored to the right of the normal one in the
+// same image and used by the browser, list and e-mail screens.
+Common::Rect CellPhonePopup::zoomedChromeSrc() const {
+ const Common::Rect &normal = _uiclData->header.normalSrcRect;
+ const Common::Rect &full = _uiclData->fullEmptyScreenSrc;
+
+ // Nancy15 enlarged the phone graphic without updating fullEmptyScreenSrc,
+ // leaving it ten pixels off. Both layouts are the same size, so derive the
+ // rect whenever the chunk disagrees with the normal one.
+ if (!full.isEmpty() && (full.width() != normal.width() || full.height() != normal.height())) {
+ Common::Rect derived = normal;
+ derived.translate((int16)(normal.width() + 2), 0);
+ return derived;
+ }
+
+ return full.isEmpty() ? normal : full;
+}
+
void CellPhonePopup::drawChrome() {
- // The chrome image holds two layouts side-by-side: the normal
- // phone-with-keypad and a zoomed-in "full screen" variant with the
- // keypad hidden. fullEmptyScreenSrc (chunk+0x10b5) points at the
- // latter; the original swaps to it for browser/list/email-content
- // modes so the LCD can extend down into the keypad area.
- const Common::Rect &chromeSrc =
- isZoomedChromeState() && !isHelpContentView() && !_uiclData->fullEmptyScreenSrc.isEmpty()
- ? _uiclData->fullEmptyScreenSrc
+ const Common::Rect chromeSrc =
+ isZoomedChromeState() && !isHelpContentView()
+ ? zoomedChromeSrc()
: _uiclData->header.normalSrcRect;
_drawSurface.blitFrom(_overlayImage, chromeSrc, Common::Point(0, 0));
drawCloseButton(_closeButtonHovered);
@@ -996,11 +1009,19 @@ Common::Array<uint> CellPhonePopup::listVisibleIndices() const {
out.push_back(i);
}
} else if (_screenState == kEmailList) {
- // "Old Email Only" (no-signal) hides messages not yet read.
+ const CVTX *autotext = (const CVTX *)g_nancy->getEngineData("AUTOTEXT");
for (uint i = 0; i < cellData->emailMessages.size(); ++i) {
- if (!_noSignal || cellData->emailMessages[i].read) {
- out.push_back(i);
+ // "Old Email Only" (no-signal) hides messages not yet read.
+ if (_noSignal && !cellData->emailMessages[i].read) {
+ continue;
+ }
+ // A subject with no text drops the whole row, letting the next
+ // message move up. Nancy15 reuses Nancy14's UICL chunk, whose
+ // initial e-mail has no text in Nancy15.
+ if (!autotext || !autotext->texts.contains(cellData->emailMessages[i].key)) {
+ continue;
}
+ out.push_back(i);
}
}
return out;
@@ -1045,10 +1066,10 @@ void CellPhonePopup::drawLinkList() {
? _uiclData->emailIconSelected
: _uiclData->emailIconUnread;
if (!icon.isEmpty()) {
- const int iconX = MAX(0, rowRect.left - icon.width() - 2);
+ // The icon opens the row, the subject follows it.
_drawSurface.blitFrom(_spritesImage, icon,
- Common::Point(iconX, rowRect.top));
- textX = MAX(textX, iconX + icon.width() + 2);
+ Common::Point(rowRect.left, rowRect.top));
+ textX = rowRect.left + icon.width();
}
}
diff --git a/engines/nancy/ui/cellphonepopup.h b/engines/nancy/ui/cellphonepopup.h
index 6f818634779..a0b97b067e4 100644
--- a/engines/nancy/ui/cellphonepopup.h
+++ b/engines/nancy/ui/cellphonepopup.h
@@ -112,6 +112,7 @@ private:
kMessageScreen = 17 // a transient message tile (SENT / DELETED / FULL)
};
+ Common::Rect zoomedChromeSrc() const;
void drawChrome();
void drawScreenContent();
void drawStatusIcons(bool includeSignal = true);
Commit: 11206539603f9b2dc256cb2ebff137e8e866d949
https://github.com/scummvm/scummvm/commit/11206539603f9b2dc256cb2ebff137e8e866d949
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-20T18:28:54+03:00
Commit Message:
NANCY: NANCY15: Handle new INV chunk format for the game inventory
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 024b51df01a..46926373ac9 100644
--- a/engines/nancy/enginedata.cpp
+++ b/engines/nancy/enginedata.cpp
@@ -161,6 +161,11 @@ PCAL::PCAL(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
}
INV::INV(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
+ if (g_nancy->getGameType() >= kGameTypeNancy15) {
+ readNancy15(*chunkStream);
+ return;
+ }
+
Common::Serializer s(chunkStream, nullptr);
s.setVersion(g_nancy->getGameType());
@@ -266,6 +271,39 @@ INV::INV(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
}
}
+// Nancy15 cut the inventory chunk down: the per-item "can't" sounds and captions
+// moved into the per-character PUIV bank, the item count is now stored in the
+// chunk itself, and the highlighted icon rect is no longer written out - every
+// item's highlighted icon sits at the same offset from its normal one.
+void INV::readNancy15(Common::SeekableReadStream &stream) {
+ captionAutoClearTime = stream.readUint16LE();
+ readFilename(stream, inventoryBoxIconsImageName);
+
+ int32 highlightOffsetX = stream.readSint32LE();
+ int32 highlightOffsetY = stream.readSint32LE();
+
+ uint16 numItems = stream.readUint16LE();
+ itemDescriptions.resize(numItems);
+
+ char textBuf[49];
+
+ for (uint i = 0; i < numItems; ++i) {
+ ItemDescription &item = itemDescriptions[i];
+
+ stream.read(textBuf, 48);
+ textBuf[48] = '\0';
+ item.name = textBuf;
+
+ item.keepItem = (byte)stream.readUint16LE();
+ item.sceneID = stream.readUint16LE();
+ item.sceneSoundFlag = stream.readUint16LE();
+
+ readRect(stream, item.sourceRect);
+ item.highlightedSourceRect = item.sourceRect;
+ item.highlightedSourceRect.translate(highlightOffsetX, highlightOffsetY);
+ }
+}
+
TBOX::TBOX(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
bool isVampire = g_nancy->getGameType() == kGameTypeVampire;
diff --git a/engines/nancy/enginedata.h b/engines/nancy/enginedata.h
index da26eef7920..ca92e71864f 100644
--- a/engines/nancy/enginedata.h
+++ b/engines/nancy/enginedata.h
@@ -148,6 +148,7 @@ struct INV : public EngineData {
};
INV(Common::SeekableReadStream *chunkStream);
+ void readNancy15(Common::SeekableReadStream &stream);
Common::Rect scrollbarSrcBounds;
Common::Point scrollbarDefaultPos;
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 994397e3700..f72a16662ca 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -651,6 +651,16 @@ void NancyEngine::bootGameEngine() {
LOAD_BOOT(VIEW)
LOAD_BOOT(PCAL)
LOAD_BOOT(INV)
+
+ if (getGameType() >= kGameTypeNancy15) {
+ // Nancy15 stores the number of inventory items in the INV chunk, so the
+ // hardcoded count is only a fallback for the chunks read before this one
+ const INV *invData = (const INV *)getEngineData("INV");
+ if (invData && invData->itemDescriptions.size()) {
+ _staticData.numItems = invData->itemDescriptions.size();
+ }
+ }
+
LOAD_BOOT(TBOX)
LOAD_BOOT(HELP)
LOAD_BOOT(CRED)
Commit: 850c5af490be7c6786f709ef7caca9a8f173400e
https://github.com/scummvm/scummvm/commit/850c5af490be7c6786f709ef7caca9a8f173400e
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-20T18:33:03+03:00
Commit Message:
NANCY: Don't let button sounds swallow input in dial/phone records
RotatingLockPuzzle dropped clicks that arrived while its click sound was
playing; the original turns the dial on every click and replays the sound.
The phone directory display was blitted after the button sound instead of
on the press. Buttons with no sound name no longer play or wait for one.
Fix #16726
Changed paths:
engines/nancy/action/puzzle/rotatinglockpuzzle.cpp
engines/nancy/action/puzzle/telephone.cpp
diff --git a/engines/nancy/action/puzzle/rotatinglockpuzzle.cpp b/engines/nancy/action/puzzle/rotatinglockpuzzle.cpp
index d305ef2c410..5b9498dfb34 100644
--- a/engines/nancy/action/puzzle/rotatinglockpuzzle.cpp
+++ b/engines/nancy/action/puzzle/rotatinglockpuzzle.cpp
@@ -251,7 +251,10 @@ void RotatingLockPuzzle::handleInput(NancyInput &input) {
// The dial cursors use the idle (non-highlighted) sprite variant
g_nancy->_cursor->setCursorType(_upCursorType, true, false);
- if (!g_nancy->_sound->isSoundPlaying(_clickSound) && input.input & NancyInput::kLeftMouseButtonUp) {
+ // The dials accept clicks as fast as they come in; the click sound
+ // restarts with every one
+ if (input.input & NancyInput::kLeftMouseButtonUp) {
+ g_nancy->_sound->loadSound(_clickSound, nullptr, true);
g_nancy->_sound->playSound(_clickSound);
int n = _currentSequence[i] + 1;
@@ -269,7 +272,8 @@ void RotatingLockPuzzle::handleInput(NancyInput &input) {
if (NancySceneState.getViewport().convertViewportToScreen(_downHotspots[i]).contains(input.mousePos)) {
g_nancy->_cursor->setCursorType(_downCursorType, true, false);
- if (!g_nancy->_sound->isSoundPlaying(_clickSound) && input.input & NancyInput::kLeftMouseButtonUp) {
+ if (input.input & NancyInput::kLeftMouseButtonUp) {
+ g_nancy->_sound->loadSound(_clickSound, nullptr, true);
g_nancy->_sound->playSound(_clickSound);
int n = (int)_currentSequence[i] - 1;
diff --git a/engines/nancy/action/puzzle/telephone.cpp b/engines/nancy/action/puzzle/telephone.cpp
index f44efbf7b6d..60349ec7127 100644
--- a/engines/nancy/action/puzzle/telephone.cpp
+++ b/engines/nancy/action/puzzle/telephone.cpp
@@ -576,11 +576,21 @@ void Telephone::handleInput(NancyInput &input) {
_displayedDirectory += dirEntryDelta;
} while (_displayedDirectory != start);
+
+ // The display follows the button press immediately, and does not
+ // wait for the button sound to finish
+ if (_isShowingDirectory) {
+ _drawSurface.blitFrom(_image, _calls[_displayedDirectory].displaySrc, _displayDest);
+ }
}
_genericButtonSound.name = _buttonSoundNames[buttonNr];
- g_nancy->_sound->loadSound(_genericButtonSound);
- g_nancy->_sound->playSound(_genericButtonSound);
+
+ // Buttons without a sound do not hold up the keypad
+ if (!_genericButtonSound.name.empty() && _genericButtonSound.name != "NO SOUND") {
+ g_nancy->_sound->loadSound(_genericButtonSound);
+ g_nancy->_sound->playSound(_genericButtonSound);
+ }
_drawSurface.blitFrom(_image, _srcRects[buttonNr], _destRects[buttonNr]);
_needsRedraw = true;
Commit: f40fdd132e55b0959fc7afcb62232996ad92ceee
https://github.com/scummvm/scummvm/commit/f40fdd132e55b0959fc7afcb62232996ad92ceee
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-20T18:51:41+03:00
Commit Message:
NANCY: Fix missing hotspot cursor for script-set cursor type 0
CursorManager::setCursor() skipped re-resolving the cursor when the
requested type matched the current one. Since the idle cursor is also
kNormal (type 0), hotspots asking for script cursor type 0 (e.g. record 6
of nancy10 scene 2306, the kitchen cake area) never switched to the
highlighted eyeglass. The setFromScript and hotspotVariant flags now take
part in that comparison, as the same type resolves to a different slot
depending on them.
Fix #16908
Changed paths:
engines/nancy/cursor.cpp
engines/nancy/cursor.h
diff --git a/engines/nancy/cursor.cpp b/engines/nancy/cursor.cpp
index b60aebca272..246009c6731 100644
--- a/engines/nancy/cursor.cpp
+++ b/engines/nancy/cursor.cpp
@@ -34,6 +34,8 @@ CursorManager::CursorManager() :
_isInitialized(false),
_curItemID(-1),
_curCursorType(kNormal),
+ _curSetFromScript(false),
+ _curHotspotVariant(true),
_curCursorID(0),
_lastCursorID(10000), // nonsense default value to ensure cursor is drawn the first time
_hasItem(false),
@@ -263,11 +265,17 @@ void CursorManager::setCursor(CursorType type, int16 itemID, bool setFromScript,
const GameType gameType = g_nancy->getGameType();
- if (type == _curCursorType && itemID == _curItemID)
+ // A script-set cursor resolves to a different slot than the same type set by
+ // the engine (e.g. type 0 picks the highlighted eyeglass instead of the plain
+ // one), so both flags take part in the comparison below
+ if (type == _curCursorType && itemID == _curItemID &&
+ setFromScript == _curSetFromScript && hotspotVariant == _curHotspotVariant)
return;
_curCursorType = type;
_curItemID = itemID;
+ _curSetFromScript = setFromScript;
+ _curHotspotVariant = hotspotVariant;
_hasItem = false;
if (gameType >= kGameTypeNancy13) {
diff --git a/engines/nancy/cursor.h b/engines/nancy/cursor.h
index 6b1aca444e2..1605a8e8e93 100644
--- a/engines/nancy/cursor.h
+++ b/engines/nancy/cursor.h
@@ -188,6 +188,8 @@ private:
Common::Point _warpedMousePos;
CursorType _curCursorType;
+ bool _curSetFromScript;
+ bool _curHotspotVariant;
int16 _curItemID;
uint _curCursorID;
uint _lastCursorID;
More information about the Scummvm-git-logs
mailing list