[Scummvm-git-logs] scummvm master -> 9e90b84e1f326c88f377d52ccfee07f7635ab4d1
bluegr
noreply at scummvm.org
Mon Jul 13 02:06:29 UTC 2026
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
458babd447 NANCY: Remove unused parameter of exportCif()
8c4d1e293c NANCY: NANCY6: Treat invalid mark tokens as newline
855fbb88f9 NANCY: NANCY6: Check only the last key presses in OrderingPuzzle
ae97cc0053 NANCY: NANCY12: Add safeguards for unimplemented conditional dialogues
7861004392 NANCY: NANCY12: Use the mouse for controlling the car in DrivingPuzzle
9e90b84e1f NANCY: NANCY10: Partial fix for textbox padding
Commit: 458babd447b2a604d165ea92296097f0b3544215
https://github.com/scummvm/scummvm/commit/458babd447b2a604d165ea92296097f0b3544215
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-13T05:06:14+03:00
Commit Message:
NANCY: Remove unused parameter of exportCif()
Changed paths:
engines/nancy/console.cpp
engines/nancy/resource.cpp
engines/nancy/resource.h
diff --git a/engines/nancy/console.cpp b/engines/nancy/console.cpp
index fe3019ce90a..b7b2e9ae01d 100644
--- a/engines/nancy/console.cpp
+++ b/engines/nancy/console.cpp
@@ -154,13 +154,13 @@ void NancyConsole::postEnter() {
}
bool NancyConsole::Cmd_cifExport(int argc, const char **argv) {
- if (argc < 2 || argc > 3) {
+ if (argc != 2) {
debugPrintf("Exports the specified resource to .cif file\n");
- debugPrintf("Usage: %s <name> [cal]\n", argv[0]);
+ debugPrintf("Usage: %s <name>\n", argv[0]);
return true;
}
- if (!g_nancy->_resource->exportCif((argc == 2 ? "" : argv[2]), argv[1]))
+ if (!g_nancy->_resource->exportCif(argv[1]))
debugPrintf("Failed to export '%s'\n", argv[1]);
return true;
diff --git a/engines/nancy/resource.cpp b/engines/nancy/resource.cpp
index 7c2bdedf21d..a25e5291871 100644
--- a/engines/nancy/resource.cpp
+++ b/engines/nancy/resource.cpp
@@ -315,7 +315,7 @@ void ResourceManager::list(const Common::String &treeName, Common::Array<Common:
}
}
-bool ResourceManager::exportCif(const Common::String &treeName, const Common::Path &name) {
+bool ResourceManager::exportCif(const Common::Path &name) {
if (!SearchMan.hasFile(name)) {
return false;
}
diff --git a/engines/nancy/resource.h b/engines/nancy/resource.h
index 3db7e6bf5ae..1c2d3a75ce3 100644
--- a/engines/nancy/resource.h
+++ b/engines/nancy/resource.h
@@ -59,7 +59,7 @@ public:
void list(const Common::String &treeName, Common::Array<Common::Path> &outList, CifInfo::ResType type) const;
// Exports a single resource as a standalone .cif file
- bool exportCif(const Common::String &treeName, const Common::Path &name);
+ bool exportCif(const Common::Path &name);
// Exports a collection of resources as a ciftree
bool exportCifTree(const Common::String &treeName, const Common::Array<Common::Path> &names);
Commit: 8c4d1e293c21e980a2c0855923d880067accf9d6
https://github.com/scummvm/scummvm/commit/8c4d1e293c21e980a2c0855923d880067accf9d6
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-13T05:06:15+03:00
Commit Message:
NANCY: NANCY6: Treat invalid mark tokens as newline
Mark tokens were used in Nancy 8 and newer games. In earlier games (for
example, in a stray mark token found in Nancy6), they're rendered as
newline.
Fix #16935
Changed paths:
engines/nancy/misc/hypertext.cpp
diff --git a/engines/nancy/misc/hypertext.cpp b/engines/nancy/misc/hypertext.cpp
index cd77a5133f4..f24d0d858ca 100644
--- a/engines/nancy/misc/hypertext.cpp
+++ b/engines/nancy/misc/hypertext.cpp
@@ -204,17 +204,18 @@ void HypertextParser::drawAllText(const Common::Rect &textBounds, uint leftOffse
case '3':
case '4':
case '5':
- // Mark token for Nancy 8 and later games. no-op for earlier games
- if (g_nancy->getGameType() <= kGameTypeNancy7) {
- continue;
- }
-
if (curToken.size() != 1) {
break;
}
- metaInfo.push({MetaInfo::kMark, numNonSpaceChars, (byte)(curToken[0] - '1')});
- hasMark = true;
+ // Mark token for Nancy 8 and later games. Treated as newline in earlier games
+ if (g_nancy->getGameType() <= kGameTypeNancy7) {
+ currentLine += '\n';
+ newlineTokens.push(numNonSpaceChars);
+ } else {
+ metaInfo.push({MetaInfo::kMark, numNonSpaceChars, (byte)(curToken[0] - '1')});
+ hasMark = true;
+ }
continue;
default:
break;
Commit: 855fbb88f9a0bd2da2aafef0a1d77e6052f7cd5e
https://github.com/scummvm/scummvm/commit/855fbb88f9a0bd2da2aafef0a1d77e6052f7cd5e
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-13T05:06:16+03:00
Commit Message:
NANCY: NANCY6: Check only the last key presses in OrderingPuzzle
Fix #16935
Changed paths:
engines/nancy/action/puzzle/orderingpuzzle.cpp
diff --git a/engines/nancy/action/puzzle/orderingpuzzle.cpp b/engines/nancy/action/puzzle/orderingpuzzle.cpp
index 21eea76a44f..d130dd186d5 100644
--- a/engines/nancy/action/puzzle/orderingpuzzle.cpp
+++ b/engines/nancy/action/puzzle/orderingpuzzle.cpp
@@ -460,6 +460,15 @@ void OrderingPuzzle::execute() {
bool solved = true;
if (_puzzleType != kPiano) {
+ // The pre-nancy7 keypad whose buttons pop back up is a rolling entry pad: only the
+ // most recent presses count, so the correct code opens the lock even if wrong digits
+ // were entered first. Keep just the last few presses so the check below matches a
+ // sliding window (same approach as the piano puzzle below).
+ if (_puzzleType == kKeypad && !_itemsStayDown && g_nancy->getGameType() <= kGameTypeNancy6 &&
+ _clickedSequence.size() > _correctSequence.size() && !_correctSequence.empty()) {
+ _clickedSequence.erase(&_clickedSequence[0], &_clickedSequence[_clickedSequence.size() - _correctSequence.size()]);
+ }
+
if (_clickedSequence.size() >= _correctSequence.size()) {
bool equal = true;
if (_checkOrder) {
Commit: ae97cc0053952cff20981ff1a1f22cb9fa9d6ca5
https://github.com/scummvm/scummvm/commit/ae97cc0053952cff20981ff1a1f22cb9fa9d6ca5
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-13T05:06:17+03:00
Commit Message:
NANCY: NANCY12: Add safeguards for unimplemented conditional dialogues
This will allow the game to continue without crashing, for now
Changed paths:
engines/nancy/action/conversation.cpp
diff --git a/engines/nancy/action/conversation.cpp b/engines/nancy/action/conversation.cpp
index 46a6fbd8971..b3adda572e9 100644
--- a/engines/nancy/action/conversation.cpp
+++ b/engines/nancy/action/conversation.cpp
@@ -442,6 +442,13 @@ void ConversationSound::execute() {
}
void ConversationSound::addConditionalDialogue() {
+ if (g_nancy->getGameType() >= kGameTypeNancy12) {
+ // TODO: Nancy12+ moved the per-character conditional dialogue out
+ // of the executable and into separate data files.
+ warning("Conditional dialogue for character %d is not implemented in Nancy12+", _conditionalResponseCharacterID);
+ return;
+ }
+
// We adjust the base label for Nancy 11 event flags, which can be
// larger than 1000.
int16 baseLabel = g_nancy->getGameType() >= kGameTypeNancy11 ? 1000 : 0;
@@ -512,6 +519,13 @@ void ConversationSound::addConditionalDialogue() {
}
void ConversationSound::addGoodbye() {
+ if (g_nancy->getGameType() >= kGameTypeNancy12) {
+ // TODO: Nancy12+ moved the per-character goodbye dialogue out
+ // of the executable and into separate data files.
+ warning("Goodbye dialogue for character %d is not implemented in Nancy12+", _goodbyeResponseCharacterID);
+ return;
+ }
+
// We adjust the base label for Nancy 11 event flags, which can be
// larger than 1000.
int16 baseLabel = g_nancy->getGameType() >= kGameTypeNancy11 ? 1000 : 0;
Commit: 786100439213fd772e4533fd4915b9bcb45c3d58
https://github.com/scummvm/scummvm/commit/786100439213fd772e4533fd4915b9bcb45c3d58
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-13T05:06:18+03:00
Commit Message:
NANCY: NANCY12: Use the mouse for controlling the car in DrivingPuzzle
Changed paths:
engines/nancy/action/puzzle/drivingpuzzle.cpp
engines/nancy/action/puzzle/drivingpuzzle.h
diff --git a/engines/nancy/action/puzzle/drivingpuzzle.cpp b/engines/nancy/action/puzzle/drivingpuzzle.cpp
index e45fdfd6362..7d99c38a672 100644
--- a/engines/nancy/action/puzzle/drivingpuzzle.cpp
+++ b/engines/nancy/action/puzzle/drivingpuzzle.cpp
@@ -177,7 +177,7 @@ void DrivingPuzzle::playSoundBlock(const RandomSoundBlock &block) {
SoundDescription desc;
desc.name = name;
desc.channelID = block.channel;
- desc.numLoops = block.numLoops > 0 ? block.numLoops : 1;
+ desc.numLoops = block.numLoops; // 0 == loop forever (the engine ambience)
desc.volume = block.volume;
g_nancy->_sound->loadSound(desc);
@@ -235,15 +235,19 @@ uint DrivingPuzzle::frameIndexForHeading(double heading, uint frameCount) const
return idx % frameCount;
}
-void DrivingPuzzle::drawScene() {
- int w = _drawSurface.w;
- int h = _drawSurface.h;
-
+Common::Point DrivingPuzzle::cameraOffset() const {
// Car-centered camera, clamped to the map bounds.
- int camX = CLIP<int>((int)(_carX + 0.5) - w / 2, 0, MAX(0, _image.w - w));
- int camY = CLIP<int>((int)(_carY + 0.5) - h / 2, 0, MAX(0, _image.h - h));
+ int camX = CLIP<int>((int)(_carX + 0.5) - _drawSurface.w / 2, 0, MAX(0, _image.w - _drawSurface.w));
+ int camY = CLIP<int>((int)(_carY + 0.5) - _drawSurface.h / 2, 0, MAX(0, _image.h - _drawSurface.h));
+ return Common::Point(camX, camY);
+}
+
+void DrivingPuzzle::drawScene() {
+ Common::Point cam = cameraOffset();
+ int camX = cam.x;
+ int camY = cam.y;
- _drawSurface.blitFrom(_image, Common::Rect(camX, camY, camX + w, camY + h), Common::Point(0, 0));
+ _drawSurface.blitFrom(_image, Common::Rect(camX, camY, camX + _drawSurface.w, camY + _drawSurface.h), Common::Point(0, 0));
// The chaser car (kChase), drawn under the player car.
if (_variant == kChase && !_frameRects2.empty() && _chaseCarImage.w > 0) {
@@ -300,29 +304,17 @@ void DrivingPuzzle::updateChaser() {
// (_chaseParams) and the "chaser left the viewport" loss branch are not simulated.
}
-// Per-frame car physics. The acceleration divisors (1.0/0.4) and 0.02 timestep are
-// exact; the steering rate and velocity decay are playability stand-ins.
-void DrivingPuzzle::updatePhysics(const NancyInput &input) {
+// Per-frame car physics. Throttle is +1 (forward), -1 (reverse) or 0 (coast); the car
+// already faces the cursor (steering happens in handleInput). The acceleration divisors
+// (1.0/0.4) and 0.02 timestep are exact; the velocity decay is a playability stand-in.
+void DrivingPuzzle::updatePhysics(int throttle) {
const double timeStep = 0.02;
- const double steerRate = 0.05;
const double decay = 0.98;
const double forwardCap = MAX(0.0, _speedCap);
- if (input.input & NancyInput::kMoveLeft) {
- _carHeading += steerRate;
- }
- if (input.input & NancyInput::kMoveRight) {
- _carHeading -= steerRate;
- }
- if (_carHeading < 0.0) {
- _carHeading += 2.0 * M_PI;
- } else if (_carHeading >= 2.0 * M_PI) {
- _carHeading -= 2.0 * M_PI;
- }
-
- if (input.input & NancyInput::kMoveUp) {
+ if (throttle > 0) {
_carVelocity += (forwardCap / 1.0) * timeStep;
- } else if (input.input & NancyInput::kMoveDown) {
+ } else if (throttle < 0) {
_carVelocity -= ((double)_forwardSpeed / 0.4) * timeStep;
} else {
_carVelocity *= decay;
@@ -391,6 +383,7 @@ void DrivingPuzzle::execute() {
case kRun:
break;
case kActionTrigger:
+ g_nancy->_sound->stopSound(_soundBlocks[2].channel); // stop the engine ambience
if (_triggeredDest >= 0 && _triggeredDest < (int)_destinations.size()) {
const DestinationZone &dest = _destinations[_triggeredDest];
if (dest.eventFlag != -1) {
@@ -411,12 +404,35 @@ void DrivingPuzzle::handleInput(NancyInput &input) {
return;
}
- // Drive continuously so momentum, steering and the chaser animate every frame.
+ // Throttle with the mouse buttons: left drives forward, right reverses.
+ int throttle = 0;
+ if (input.input & NancyInput::kLeftMouseButtonHeld) {
+ throttle = 1;
+ } else if (input.input & NancyInput::kRightMouseButtonHeld) {
+ throttle = -1;
+ }
+
+ // Steer the car to face the cursor while driving (its distance is irrelevant).
+ if (throttle != 0) {
+ Common::Point cam = cameraOffset();
+ Common::Rect mouseVp = NancySceneState.getViewport().convertScreenToViewport(
+ Common::Rect(input.mousePos.x, input.mousePos.y, input.mousePos.x + 1, input.mousePos.y + 1));
+ double dx = (double)mouseVp.left - (_carX - cam.x);
+ double dy = (double)mouseVp.top - (_carY - cam.y);
+ if (dx != 0.0 || dy != 0.0) {
+ _carHeading = atan2(-dy, dx);
+ if (_carHeading < 0.0) {
+ _carHeading += 2.0 * M_PI;
+ }
+ }
+ }
+
+ // Drive continuously so momentum and the chaser animate every frame.
if (_variant == kChase) {
updateChaser();
}
- updatePhysics(input);
+ updatePhysics(throttle);
if (_state == kRun) {
drawScene();
diff --git a/engines/nancy/action/puzzle/drivingpuzzle.h b/engines/nancy/action/puzzle/drivingpuzzle.h
index 074514128ba..7571d82592d 100644
--- a/engines/nancy/action/puzzle/drivingpuzzle.h
+++ b/engines/nancy/action/puzzle/drivingpuzzle.h
@@ -43,14 +43,18 @@ namespace Action {
// destination scene id and the transition effect), type 0x14 zones are boundaries,
// and the remaining subtypes are decorations and driving hazards.
//
+// Controls: the car steers to face the cursor (distance is irrelevant); the left mouse
+// button drives forward (accelerating while held) and the right button reverses.
+//
// TODO (need runtime tuning):
// - Fuel: burn the gas-gauge UI resource (index _frictionIndex) while driving; it
// currently stays at its seeded value. The DT_RESOURCE dependency that reads it is
// handled in ActionManager::processDependency.
-// - Steering: approximated with the arrow keys (the game uses click-to-steer).
+// - Hazards: potholes (type 0x17) should damage the car (more the faster it is hit,
+// building to a flat tire) and mud puddles should be penalised; both are ignored.
// - Collision: only the type 0x14 boundary rects block the car (no per-pixel mask).
// - kChase: no second-path switch or "chaser left the viewport" loss branch.
-// - Overlay / hazard zone subtypes (0x0d/0x0e/0x0f/0x05/0x03/0x17) are ignored.
+// - The decorative overlay zone subtypes (0x0d and friends) are ignored.
class DrivingPuzzle : public RenderActionRecord {
public:
enum Variant { kDriving = 0, kChase };
@@ -122,9 +126,12 @@ protected:
// Plays one (randomly chosen) entry of a random-sound block.
void playSoundBlock(const RandomSoundBlock &block);
- // Advances the car's heading/velocity/position for one frame from the current
- // movement input.
- void updatePhysics(const NancyInput &input);
+ // Advances the car's velocity/position for one frame. Throttle is +1 forward, -1
+ // reverse, 0 coast; the heading is set separately (steering toward the cursor).
+ void updatePhysics(int throttle);
+
+ // Top-left of the car-centered camera window into the map, clamped to its bounds.
+ Common::Point cameraOffset() const;
// Advances the chaser along its recorded path (kChase) and slows the player's
// speed cap the closer the chaser gets.
Commit: 9e90b84e1f326c88f377d52ccfee07f7635ab4d1
https://github.com/scummvm/scummvm/commit/9e90b84e1f326c88f377d52ccfee07f7635ab4d1
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-07-13T05:06:19+03:00
Commit Message:
NANCY: NANCY10: Partial fix for textbox padding
Improved text position in ScrollTextBox. Still need to fix the extra
padding on the left.
Partially fixes #16890
Changed paths:
engines/nancy/ui/scrolltextbox.cpp
diff --git a/engines/nancy/ui/scrolltextbox.cpp b/engines/nancy/ui/scrolltextbox.cpp
index 08ccfe21be7..45960a84d06 100644
--- a/engines/nancy/ui/scrolltextbox.cpp
+++ b/engines/nancy/ui/scrolltextbox.cpp
@@ -161,7 +161,7 @@ void ScrollTextBox::drawContent() {
// Fixed two-line strip at the top of the overlay. Drop the chrome's
// bottom margin so it's just tall enough for two lines.
const Font *font = g_nancy->_graphics->getFont(fontID);
- const int lineStep = font->getFontHeight() + font->getFontHeight() / 9;
+ const int lineStep = font->getLineHeight() + font->getLineHeight() / 9;
const int twoLineContent = _tboxData->scrollbarDefaultPos.y + 2 * lineStep;
const int miniHeight = MIN(viewport.top + MAX(contentHeight, twoLineContent), fullHeight);
boxRect = Common::Rect(_fullPopupRect.left, _fullPopupRect.top,
@@ -173,6 +173,7 @@ void ScrollTextBox::drawContent() {
_drawSurface.create(boxRect.width(), boxRect.height(), g_nancy->_graphics->getInputPixelFormat());
int textLeft = viewport.left;
+ int textTop = viewport.top;
if (_expanded) {
setTransparent(false);
drawBackground();
@@ -181,15 +182,21 @@ void ScrollTextBox::drawContent() {
// and pull the text left into the unused scrollbar gap.
setTransparent(true);
_drawSurface.clear(transColor);
+ // Nudge the first line down one pixel so its top padding matches the
+ // original's mini strip.
+ textTop += 1;
const UISliderRecord &sl = _header->slider;
if (_header->sliderEnabled && !sl.destRect.isEmpty()) {
- textLeft = toPopupLocal(sl.destRect, sl.destUsesGameFrameOffset != 0).left;
+ // Align the glyphs to the scrollbar's left edge, dropping the
+ // line-start inset that is baked into the text surface (the mini
+ // strip reclaims the whole gutter).
+ textLeft = toPopupLocal(sl.destRect, sl.destUsesGameFrameOffset != 0).left - _tboxData->lineStartXCursor;
}
}
_drawSurface.blitFrom(_fullSurface,
Common::Rect(0, scrollY, _fullSurface.w, scrollY + visibleTextHeight),
- Common::Point(textLeft, viewport.top));
+ Common::Point(textLeft, textTop));
if (_expanded) {
drawScrollbar(_scrollbarDragging ? kUIButtonPressed : (_scrollbarHovered ? kUIButtonHover : kUIButtonIdle));
More information about the Scummvm-git-logs
mailing list