[Scummvm-git-logs] scummvm master -> b18ea3907332333834ed5afc5ad88fa9d6a15a5e
bluegr
noreply at scummvm.org
Wed Jul 29 06:05:03 UTC 2026
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
b920158649 NANCY: NANCY10: Close active popups when auto-opening a new one
bd0c9859db NANCY: NANCY10: Fix slide arrow cursors used in CollisionPuzzle types
b18ea39073 NANCY: NANCY10: Fix cellphone UI issues in no signal mode
Commit: b9201586493df4d3d96c9f76ff745b43939ab792
https://github.com/scummvm/scummvm/commit/b9201586493df4d3d96c9f76ff745b43939ab792
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-29T09:04:49+03:00
Commit Message:
NANCY: NANCY10: Close active popups when auto-opening a new one
Fixes lingering open popups when answering a call from the cellphone,
e.g. when a death scene starts.
Fix #17031
Changed paths:
engines/nancy/action/miscrecords.cpp
engines/nancy/state/scene.cpp
engines/nancy/state/scene.h
diff --git a/engines/nancy/action/miscrecords.cpp b/engines/nancy/action/miscrecords.cpp
index 614f32f7bbb..036e130bb69 100644
--- a/engines/nancy/action/miscrecords.cpp
+++ b/engines/nancy/action/miscrecords.cpp
@@ -243,6 +243,11 @@ void ControlUIItems::execute() {
// phone, _startScene (when set) is the scene to jump to once it opens,
// which places a call that starts a conversation there.
if (_autoOpenOrBadgeSound == 1) {
+ // Only one popup shows at a time. If the player left one open (e.g. the
+ // inventory), close it before this AR auto-opens its target, so the
+ // game-over incoming call doesn't stack the phone over another popup.
+ NancySceneState.closeActivePopups();
+
switch (_uiButton) {
case kUITypeInventory:
NancySceneState.getInventoryPopup().open();
diff --git a/engines/nancy/state/scene.cpp b/engines/nancy/state/scene.cpp
index ce44d36c172..40f82f276fb 100644
--- a/engines/nancy/state/scene.cpp
+++ b/engines/nancy/state/scene.cpp
@@ -1525,6 +1525,13 @@ Common::Rect Scene::activePopupConfinement() const {
return Common::Rect();
}
+void Scene::closeActivePopups() {
+ if (_conversationPopup.isVisible()) _conversationPopup.close();
+ if (_inventoryPopup.isOpen()) _inventoryPopup.close();
+ if (_notebookPopup.isVisible()) _notebookPopup.close();
+ if (_cellPhonePopup.isVisible()) _cellPhonePopup.close();
+}
+
void Scene::handleInput() {
// While a UI prep scene is running the player shouldn't be able to interact
// with the (hidden, videoless) prep scenes. Swallow all input until the
diff --git a/engines/nancy/state/scene.h b/engines/nancy/state/scene.h
index 11d6e67e412..29cd250b325 100644
--- a/engines/nancy/state/scene.h
+++ b/engines/nancy/state/scene.h
@@ -249,6 +249,10 @@ public:
State getState() const { return _state; }
void setState(State state) { _state = state; }
+ // Close every open Nancy 10+ popup. Used before a script auto-opens one
+ // (e.g. the incoming game-over call) so two popups can't stack.
+ void closeActivePopups();
+
struct Timers {
Time pushedPlayTime;
Time lastTotalTime;
Commit: bd0c9859db907d94589ec57de0168a4c2f46d720
https://github.com/scummvm/scummvm/commit/bd0c9859db907d94589ec57de0168a4c2f46d720
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-29T09:04:51+03:00
Commit Message:
NANCY: NANCY10: Fix slide arrow cursors used in CollisionPuzzle types
Fix #17023
Changed paths:
engines/nancy/action/puzzle/collisionpuzzle.cpp
engines/nancy/cursor.cpp
engines/nancy/cursor.h
diff --git a/engines/nancy/action/puzzle/collisionpuzzle.cpp b/engines/nancy/action/puzzle/collisionpuzzle.cpp
index 967e5ed99dc..053e9b8ba95 100644
--- a/engines/nancy/action/puzzle/collisionpuzzle.cpp
+++ b/engines/nancy/action/puzzle/collisionpuzzle.cpp
@@ -668,6 +668,15 @@ void CollisionPuzzle::handleInput(NancyInput &input) {
return;
}
+ // Nancy 10 gave both puzzle variants dedicated slide-arrow cursors (system cursor types 23-26);
+ // earlier games reuse the generic scene-movement arrows.
+ const bool useSlideCursors =
+ g_nancy->getGameType() >= kGameTypeNancy10 && g_nancy->getGameType() <= kGameTypeNancy12;
+ const CursorManager::CursorType leftCursor = useSlideCursors ? CursorManager::kNewPuzzleSlideLeft : CursorManager::kMoveLeft;
+ const CursorManager::CursorType rightCursor = useSlideCursors ? CursorManager::kNewPuzzleSlideRight : CursorManager::kMoveRight;
+ const CursorManager::CursorType upCursor = useSlideCursors ? CursorManager::kNewPuzzleSlideUp : CursorManager::kMoveUp;
+ const CursorManager::CursorType downCursor = useSlideCursors ? CursorManager::kNewPuzzleSlideDown : CursorManager::kMoveDown;
+
for (uint i = 0; i < _pieces.size(); ++i) {
Common::Point checkPos;
Common::Rect left, right, up, down;
@@ -706,7 +715,7 @@ void CollisionPuzzle::handleInput(NancyInput &input) {
if (left.contains(input.mousePos)) {
checkPos = movePiece(i, kWallLeft);
if (checkPos != _pieces[i]._gridPos) {
- g_nancy->_cursor->setCursorType(CursorManager::kMoveLeft);
+ g_nancy->_cursor->setCursorType(leftCursor);
if (input.input & NancyInput::kLeftMouseButtonUp) {
_lastPosition = _pieces[i]._gridPos;
@@ -724,7 +733,7 @@ void CollisionPuzzle::handleInput(NancyInput &input) {
if (right.contains(input.mousePos)) {
checkPos = movePiece(i, kWallRight);
if (checkPos != _pieces[i]._gridPos) {
- g_nancy->_cursor->setCursorType(CursorManager::kMoveRight);
+ g_nancy->_cursor->setCursorType(rightCursor);
if (input.input & NancyInput::kLeftMouseButtonUp) {
_lastPosition = _pieces[i]._gridPos;
@@ -742,7 +751,7 @@ void CollisionPuzzle::handleInput(NancyInput &input) {
if (up.contains(input.mousePos)) {
checkPos = movePiece(i, kWallUp);
if (checkPos != _pieces[i]._gridPos) {
- g_nancy->_cursor->setCursorType(CursorManager::kMoveUp);
+ g_nancy->_cursor->setCursorType(upCursor);
if (input.input & NancyInput::kLeftMouseButtonUp) {
_lastPosition = _pieces[i]._gridPos;
@@ -760,7 +769,7 @@ void CollisionPuzzle::handleInput(NancyInput &input) {
if (down.contains(input.mousePos)) {
checkPos = movePiece(i, kWallDown);
if (checkPos != _pieces[i]._gridPos) {
- g_nancy->_cursor->setCursorType(CursorManager::kMoveDown);
+ g_nancy->_cursor->setCursorType(downCursor);
if (input.input & NancyInput::kLeftMouseButtonUp) {
_lastPosition = _pieces[i]._gridPos;
diff --git a/engines/nancy/cursor.cpp b/engines/nancy/cursor.cpp
index a5e8e410896..e628451c762 100644
--- a/engines/nancy/cursor.cpp
+++ b/engines/nancy/cursor.cpp
@@ -183,6 +183,10 @@ uint CursorManager::resolveNancy10CursorID(CursorType type, int16 itemID, bool s
case kInvertedRotateLeft: return kNewInvertedRotateLeft;
case kDragHand: return kNewDragHand;
case kPuzzleArrow: return kNewPuzzleArrow;
+ case kNewPuzzleSlideUp: return kNewPuzzleSlideUp;
+ case kNewPuzzleSlideDown: return kNewPuzzleSlideDown;
+ case kNewPuzzleSlideLeft: return kNewPuzzleSlideLeft;
+ case kNewPuzzleSlideRight: return kNewPuzzleSlideRight;
case kDropHand: return kNewDropHand;
default:
return kNewNormal;
diff --git a/engines/nancy/cursor.h b/engines/nancy/cursor.h
index a0d54a49131..5f00f938b29 100644
--- a/engines/nancy/cursor.h
+++ b/engines/nancy/cursor.h
@@ -91,6 +91,10 @@ public:
kNewUseHand = 36, // Type 18 â Hand used while using items
kNewDragHand = 38, // Type 19 â Hand used while dragging puzzle pieces (e.g. SortPuzzle pickup action sets this)
kNewPuzzleArrow = 45, // Type 22 hotspot â Arrow cursor shown when hovering a clickable puzzle hotspot
+ kNewPuzzleSlideUp = 47, // Type 23 hotspot â Slide-arrow shown over a movable tile in CollisionPuzzle/TileMovePuzzle
+ kNewPuzzleSlideDown = 49, // Type 24 hotspot
+ kNewPuzzleSlideLeft = 51, // Type 25 hotspot
+ kNewPuzzleSlideRight = 53, // Type 26 hotspot
kNewDropHand = 64, // Type 32 â Hand shown when a held piece is dropped (briefly set on the drop action)
// Cursor types in Nancy13 and newer games. Nancy13 rebuilt the CURS
Commit: b18ea3907332333834ed5afc5ad88fa9d6a15a5e
https://github.com/scummvm/scummvm/commit/b18ea3907332333834ed5afc5ad88fa9d6a15a5e
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-29T09:04:54+03:00
Commit Message:
NANCY: NANCY10: Fix cellphone UI issues in no signal mode
In no signal mode:
- The Internet browser menu should not be visible
- Position the "No signal" text correctly on screen
- Hide the help button
- The dir and dialing buttons should be disabled
- Also, fix an issue with the original: also disable the dir and
dialing buttons from the web screen, to disallow placing calls in
no signal mode
Fix #17028
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 6b9614b9291..2436a588ce0 100644
--- a/engines/nancy/ui/cellphonepopup.cpp
+++ b/engines/nancy/ui/cellphonepopup.cpp
@@ -542,8 +542,9 @@ void CellPhonePopup::drawChrome() {
drawCloseButton(_closeButtonHovered);
// The help "?" button lives on the dialer face only. The original hides
// it once a call is being placed (the connecting / "We're sorry" screens)
- // and on every sub-screen that shows its own heading.
- if (_screenState == kWelcome || _screenState == kDialing) {
+ // and on every sub-screen that shows its own heading. With no signal the
+ // online help is unreachable, so the button is gone entirely.
+ if ((_screenState == kWelcome || _screenState == kDialing) && !_noSignal) {
drawHelpButton(_helpButtonHovered ? 1 : 0);
}
_needsRedraw = true;
@@ -683,7 +684,11 @@ void CellPhonePopup::drawScreenContent() {
drawHubButton(kN13SubViewPics);
} else {
drawHubButton(kSubEmail);
- drawHubButton(kSubWeb);
+ // No cellular signal locks the phone to "Old Email Only", so the
+ // Internet Browser option is removed from the hub.
+ if (!_noSignal) {
+ drawHubButton(kSubWeb);
+ }
}
break;
}
@@ -943,8 +948,13 @@ void CellPhonePopup::drawStatusLabels() {
return;
}
- const int x = _uiclData->statusTextX - _screenPosition.left;
- const int yBase = _uiclData->statusTextY - _screenPosition.top;
+ // The status labels sit one pixel right of the dialed-number baseline.
+ const int x = _uiclData->statusTextX + 1 - _screenPosition.left;
+ // statusTextY + offset is the text baseline in the original, which draws
+ // upward from it; ScummVM's drawString anchors at the top of the line
+ // (baseline = y + getFontHeight()), so subtract the font height to land the
+ // block where the original centers it on the LCD.
+ const int yBase = _uiclData->statusTextY - _screenPosition.top - font->getFontHeight();
const int kLineYOffsets[UICL::kNumStatusLabels] = { -10, 20, 50 };
for (uint i = 0; i < UICL::kNumStatusLabels; ++i) {
@@ -1687,6 +1697,14 @@ void CellPhonePopup::enterScreenState(ScreenState newState) {
drawScreenContent();
}
+bool CellPhonePopup::isDialKeyActive(uint slot) const {
+ if (_noSignal && (_screenState == kWelcome || _screenState == kDialing ||
+ _screenState == kOnlineHub)) {
+ return slot == 13;
+ }
+ return true;
+}
+
void CellPhonePopup::cancelCall() {
if (!_callSound.name.empty()) {
g_nancy->_sound->stopSound(_callSound);
@@ -2248,7 +2266,7 @@ void CellPhonePopup::handleInput(NancyInput &input) {
// Green-arrow highlight for the captioned "> HELP" and "< BACK" / HOME
// buttons: swap to the pressed sprite while the cursor is over them.
- const bool helpVisible = (_screenState == kWelcome || _screenState == kDialing);
+ const bool helpVisible = (_screenState == kWelcome || _screenState == kDialing) && !_noSignal;
const bool overHelp = helpVisible &&
!_uiclData->helpButton.destRect.isEmpty() &&
_uiclData->helpButton.destRect.contains(chunkMouse);
@@ -2280,7 +2298,7 @@ void CellPhonePopup::handleInput(NancyInput &input) {
(input.input & (NancyInput::kLeftMouseButtonDown | NancyInput::kLeftMouseButtonHeld)) &&
!(input.input & NancyInput::kLeftMouseButtonUp)) {
for (uint i = 0; i < UICL::kNumDialPadSlots; ++i) {
- if (_uiclData->dialPadSlots[i].destRect.contains(chunkMouse)) {
+ if (_uiclData->dialPadSlots[i].destRect.contains(chunkMouse) && isDialKeyActive(i)) {
newPressed = (int)i;
break;
}
@@ -2293,7 +2311,7 @@ void CellPhonePopup::handleInput(NancyInput &input) {
// Help "?" button: opens the help page in the content view. Hidden
// (and unclickable) on sub-screens that already show their own heading.
- if (!isSubScreenState() &&
+ if (!isSubScreenState() && !_noSignal &&
!_uiclData->helpButton.destRect.isEmpty() && !_uiclData->helpTextKey.empty() &&
!(_screenState == kContentView && _contentKey == _uiclData->helpTextKey) &&
_uiclData->helpButton.destRect.contains(chunkMouse)) {
@@ -2386,10 +2404,13 @@ void CellPhonePopup::handleInput(NancyInput &input) {
// Highlight whichever option button the cursor is over.
const bool n13Hub = g_nancy->getGameType() >= kGameTypeNancy13;
+ // No signal removes the Internet Browser option (the Nancy 13 "view
+ // pictures" option in the same slot is not signal-gated).
+ const bool webDisabled = _noSignal && !n13Hub;
const int emailSlot = n13Hub ? kN13SubEmail : kSubEmail;
const int webSlot = n13Hub ? kN13SubViewPics : kSubWeb;
const int newHubHover = emailR.contains(popupMouse) ? emailSlot
- : webR.contains(popupMouse) ? webSlot : -1;
+ : (!webDisabled && webR.contains(popupMouse)) ? webSlot : -1;
if (newHubHover != _hoveredHubButton) {
_hoveredHubButton = newHubHover;
drawScreenContent();
@@ -2404,7 +2425,7 @@ void CellPhonePopup::handleInput(NancyInput &input) {
input.eatMouseInput();
return;
}
- } else if (webR.contains(popupMouse)) {
+ } else if (!webDisabled && webR.contains(popupMouse)) {
g_nancy->_cursor->setCursorType(CursorManager::kHotspotArrow);
if (input.input & NancyInput::kLeftMouseButtonUp) {
_directoryScroll = 0;
@@ -2761,7 +2782,8 @@ void CellPhonePopup::handleInput(NancyInput &input) {
// Call/talk button. Checked before the dial-pad loop so an overlapping
// slot can't eat it. The Talk key is dial-pad slot 12. Only live while the
// keypad is on screen (skipped in the zoomed web / email / browser views).
- if (keypadVisible && _uiclData->dialPadSlots[12].destRect.contains(chunkMouse)) {
+ if (keypadVisible && isDialKeyActive(12) &&
+ _uiclData->dialPadSlots[12].destRect.contains(chunkMouse)) {
g_nancy->_cursor->setCursorType(CursorManager::kHotspotArrow);
if (input.input & NancyInput::kLeftMouseButtonUp) {
@@ -2822,7 +2844,7 @@ void CellPhonePopup::handleInput(NancyInput &input) {
if (keypadVisible) {
for (uint i = 0; i < UICL::kNumDialPadSlots; ++i) {
const UICL::DialPadSlot &slot = _uiclData->dialPadSlots[i];
- if (slot.destRect.contains(chunkMouse)) {
+ if (slot.destRect.contains(chunkMouse) && isDialKeyActive(i)) {
newHovered = (int)i;
break;
}
diff --git a/engines/nancy/ui/cellphonepopup.h b/engines/nancy/ui/cellphonepopup.h
index c3395fc6130..3c9003533d1 100644
--- a/engines/nancy/ui/cellphonepopup.h
+++ b/engines/nancy/ui/cellphonepopup.h
@@ -220,6 +220,12 @@ private:
void resetDialPad();
void enterScreenState(ScreenState newState);
+ // With no signal the phone locks to "Old Email Only": on the welcome,
+ // dialing and online-hub screens every keypad key is dead except Menu
+ // (slot 13), which still reaches the e-mail list. Digits, *, #, Talk, Dir
+ // and the Help "?" go inert. The directory keeps its keys so the reachable
+ // e-mail path still works.
+ bool isDialKeyActive(uint slot) const;
// True while a player-placed call is ringing / waiting for pickup, so the
// connecting strip shows a Back button (subButtons[0]) that cancels it.
// Incoming calls have no Back button.
More information about the Scummvm-git-logs
mailing list