[Scummvm-git-logs] scummvm master -> 566aed00f3d8aefec314008e0744e8977e1ef837
bluegr
noreply at scummvm.org
Fri Sep 11 05:56:27 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:
baf8a6ac72 NANCY: NANCY14: Implement foreground masks for in-game secondary movies
a9f8e182ca NANCY: NANCY14: Fixes for conversation subtitles
4a0f687bcb NANCY: Remove the unneeded GF_COMPRESSED flag
8d230b12fe NANCY: NANCY14: Fix making phone calls
5b32023837 NANCY: NANCY10: Fix making calls using numbers
566aed00f3 NANCY: NANCY1-9: Cellphone fixes
Commit: baf8a6ac72d51a35aa6dc5561cad3c2c6d4d2ab3
https://github.com/scummvm/scummvm/commit/baf8a6ac72d51a35aa6dc5561cad3c2c6d4d2ab3
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-11T08:56:06+03:00
Commit Message:
NANCY: NANCY14: Implement foreground masks for in-game secondary movies
Now, the table is drawn correctly in front of Dieter von Schwesterkrank
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 c9defb662bb..2c78e7a7159 100644
--- a/engines/nancy/action/secondarymovie.cpp
+++ b/engines/nancy/action/secondarymovie.cpp
@@ -23,6 +23,7 @@
#include "engines/nancy/graphics.h"
#include "engines/nancy/input.h"
#include "engines/nancy/nancy.h"
+#include "engines/nancy/resource.h"
#include "engines/nancy/sound.h"
#include "engines/nancy/util.h"
#include "engines/nancy/video.h"
@@ -244,8 +245,8 @@ void PlaySecondaryMovie::readRandomMovieData(Common::Serializer &ser, Common::Se
// The header grew to mirror the non-random AR (videoFormat / visibility / cursor
// / sceneID / frameID, plus two currently unmapped u16s and a per-movie volume
// byte). The sequence records are unchanged. The tail is a blt-descriptor list
-// for the main movie, then the recognition ("secondary") movie's name and its
-// own blt-descriptor list, in place of Nancy13's secondaryMovie record + hotspot
+// for the main movie, then the name of a foreground mask image and its own
+// blt-descriptor list, in place of Nancy13's secondaryMovie record + hotspot
// list.
void PlaySecondaryMovie::readRandomMovieDataNancy14(Common::Serializer &ser, Common::SeekableReadStream &stream) {
readFilename(ser, _startingSequenceName);
@@ -276,15 +277,14 @@ void PlaySecondaryMovie::readRandomMovieDataNancy14(Common::Serializer &ser, Com
_videoDescs[i].readData(stream);
}
- // Recognition ("secondary") movie: its name followed by its own blt
- // descriptors. The descriptors are consumed to keep the stream aligned
- // (no home in the struct yet).
- readFilename(ser, _secondaryMovie.name);
- uint16 numSecondaryDescs = 0;
- ser.syncAsUint16LE(numSecondaryDescs);
- for (uint i = 0; i < numSecondaryDescs; ++i) {
- SecondaryVideoDescription unused;
- unused.readData(stream);
+ // Foreground mask: the name of an image, followed by the blt descriptors
+ // that place it over the movie for each background frame.
+ readFilename(ser, _maskName);
+ uint16 numMaskDescs = 0;
+ ser.syncAsUint16LE(numMaskDescs);
+ _maskDescs.resize(numMaskDescs);
+ for (uint i = 0; i < numMaskDescs; ++i) {
+ _maskDescs[i].readData(stream);
}
applyStartingRandomSequence();
@@ -454,6 +454,7 @@ int PlaySecondaryMovie::beginRandomPause(const RandomSequence &seq) {
_randomPauseEndTime = g_system->getMillis() + (uint32)MAX<int32>(0, pauseMs);
_randomChainState = kRandomPaused;
setVisible(false);
+ _mask.setVisible(false);
_decoder.pauseVideo(true);
return -1;
}
@@ -845,11 +846,43 @@ void PlaySecondaryMovie::init() {
resolveSentinelFrames();
}
+ if (!_maskName.empty() && _maskImage.empty()) {
+ g_nancy->_resource->loadImage(_maskName, _maskImage);
+ _mask.setVisible(false);
+ _mask.init();
+ }
+
_screenPosition = _drawSurface.getBounds();
RenderObject::init();
}
+void PlaySecondaryMovie::registerGraphics() {
+ if (!_maskImage.empty()) {
+ _mask.registerGraphics();
+ }
+
+ RenderActionRecord::registerGraphics();
+}
+
+void PlaySecondaryMovie::updateMask(int viewportFrame) {
+ if (_maskImage.empty()) {
+ return;
+ }
+
+ for (const SecondaryVideoDescription &desc : _maskDescs) {
+ if (desc.frameID == viewportFrame) {
+ _mask._drawSurface.create(_maskImage, desc.srcRect);
+ _mask.setTransparent(true);
+ _mask.moveTo(desc.destRect);
+ _mask.setVisible(_isVisible);
+ return;
+ }
+ }
+
+ _mask.setVisible(false);
+}
+
void PlaySecondaryMovie::onPause(bool pause) {
_decoder.pauseVideo(pause);
RenderActionRecord::onPause(pause);
@@ -972,6 +1005,8 @@ void PlaySecondaryMovie::execute() {
setVisible(false);
_hasHotspot = false;
}
+
+ updateMask(newFrame);
}
// We update the decoder here instead of in updateGraphics() to avoid an
diff --git a/engines/nancy/action/secondarymovie.h b/engines/nancy/action/secondarymovie.h
index 6ac166051f8..d9cb365d71b 100644
--- a/engines/nancy/action/secondarymovie.h
+++ b/engines/nancy/action/secondarymovie.h
@@ -95,6 +95,7 @@ public:
void init() override;
void onPause(bool pause) override;
+ void registerGraphics() override;
void readData(Common::SeekableReadStream &stream) override;
void execute() override;
@@ -176,6 +177,18 @@ public:
// character's recognition animation, played while the mouse hovers it.
RandomSequence _secondaryMovie;
+ // Nancy14 replaced that slot with a foreground mask: a still image blitted
+ // over the movie, so scenery standing in front of the character (a table,
+ // a counter) covers the lower part of it.
+ class ForegroundMask : public RenderObject {
+ public:
+ ForegroundMask() : RenderObject(9) {}
+ bool isViewportRelative() const override { return true; }
+ };
+
+ Common::Path _maskName;
+ Common::Array<SecondaryVideoDescription> _maskDescs;
+
// Nancy13 talkable characters: the scene to open when the character is
// clicked (its conversation). kNoScene means the character isn't clickable.
uint16 _talkSceneID = kNoScene;
@@ -305,7 +318,13 @@ protected:
// against the loaded decoder's frame count. Random sequences only.
void resolveSentinelFrames();
+ // Show the foreground mask blit belonging to the given background frame,
+ // or hide it when the record doesn't describe one for that frame.
+ void updateMask(int viewportFrame);
+
Graphics::ManagedSurface _fullFrame;
+ Graphics::ManagedSurface _maskImage;
+ ForegroundMask _mask;
int _curViewportFrame = -1;
bool _isFinished = false;
};
Commit: a9f8e182ca179ff9ff6b7af43f24545905a0e833
https://github.com/scummvm/scummvm/commit/a9f8e182ca179ff9ff6b7af43f24545905a0e833
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-11T08:56:08+03:00
Commit Message:
NANCY: NANCY14: Fixes for conversation subtitles
- Captions are placed in either the CONVO for conversations or AUTOTEXT
for sound records. Lookup both
- Show captions for group concatenated text (new in Nancy14)
- Don't erase the textbox text for sounds with empty captions
Changed paths:
engines/nancy/action/conversation.cpp
engines/nancy/action/soundrecords.cpp
engines/nancy/action/soundrecords.h
diff --git a/engines/nancy/action/conversation.cpp b/engines/nancy/action/conversation.cpp
index 8e238e99177..19faca812af 100644
--- a/engines/nancy/action/conversation.cpp
+++ b/engines/nancy/action/conversation.cpp
@@ -172,6 +172,13 @@ void ConversationSound::readTerseData(Common::SeekableReadStream &stream) {
}
}
+// Conversation captions live in the CONVO text chunk, but Nancy14 keeps a few of
+// them in AUTOTEXT instead. A key that CONVO does have, but maps to no text, is a
+// deliberately silent line, so only fall back when the key is missing altogether.
+static Common::String resolveConversationText(const Common::String &key) {
+ return resolveSubtitleText(key, resolveSubtitleText(key), "CONVO");
+}
+
void ConversationSound::readDataNancy13(Common::SeekableReadStream &stream) {
readFilename(stream, _sound.name);
_sound.channelID = 12; // hardcoded, as in the terse variants
@@ -200,16 +207,14 @@ void ConversationSound::readDataNancy13(Common::SeekableReadStream &stream) {
_sceneChange.frameID = stream.readUint16LE();
_sceneChange.continueSceneSound = kContinueSceneSound;
- // Caption and response texts are external, keyed by sound name in CONVO.
+ // Caption and response texts are external, keyed by sound name.
// Each part of a concatenated line has its own caption; they make up one
// exchange, so they are shown together.
- const CVTX *convo = (const CVTX *)g_nancy->getEngineData("CONVO");
- assert(convo);
if (_concatSounds.empty()) {
- _text = convo->texts.getValOrDefault(_sound.name, "");
+ _text = resolveConversationText(_sound.name);
} else {
for (uint i = 0; i < _concatSounds.size(); ++i) {
- _text += convo->texts.getValOrDefault(_concatSounds[i], "");
+ _text += resolveConversationText(_concatSounds[i]);
}
}
@@ -221,7 +226,7 @@ void ConversationSound::readDataNancy13(Common::SeekableReadStream &stream) {
response.sceneChange.sceneID = stream.readUint16LE();
response.sceneChange.continueSceneSound = kContinueSceneSound;
response.conditionFlags.read(stream);
- response.text = convo->texts.getValOrDefault(response.soundName, "");
+ response.text = resolveConversationText(response.soundName);
}
uint16 numFlagsStructs = stream.readUint16LE();
diff --git a/engines/nancy/action/soundrecords.cpp b/engines/nancy/action/soundrecords.cpp
index 7e28108a140..f637369226f 100644
--- a/engines/nancy/action/soundrecords.cpp
+++ b/engines/nancy/action/soundrecords.cpp
@@ -49,6 +49,25 @@ static uint selectRandomSound(Common::Array<Common::String> &soundNames) {
return g_nancy->_randomSource->getRandomNumber(soundNames.size() - 1);
}
+// Some entries hold nothing but markup: "silence", which scenes play as a
+// placeholder, is just "<n>". Showing one would clear the textbox and put a
+// blank line in it, wiping whatever caption is up.
+static bool hasVisibleText(const Common::String &text) {
+ bool inToken = false;
+
+ for (uint i = 0; i < text.size(); ++i) {
+ if (text[i] == '<') {
+ inToken = true;
+ } else if (text[i] == '>') {
+ inToken = false;
+ } else if (!inToken && !Common::isSpace(text[i])) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
// Nancy13+ subtitles are no longer stored inside the sound record. Instead, the
// engine looks the played sound's name up in the CVTX text chunks when the sound
// starts and, if a matching entry exists, shows it in the game textbox. The
@@ -61,14 +80,17 @@ static Common::String resolveSoundSubtitle(const Common::String &soundName) {
const CVTX *autotext = (const CVTX *)g_nancy->getEngineData("AUTOTEXT");
if (autotext) {
Common::String text = autotext->texts.getValOrDefault(soundName, "");
- if (!text.empty()) {
+ if (hasVisibleText(text)) {
return text;
}
}
const CVTX *convo = (const CVTX *)g_nancy->getEngineData("CONVO");
if (convo) {
- return convo->texts.getValOrDefault(soundName, "");
+ Common::String text = convo->texts.getValOrDefault(soundName, "");
+ if (hasVisibleText(text)) {
+ return text;
+ }
}
return Common::String();
@@ -545,7 +567,7 @@ void ConcatMultiSound::readData(Common::SeekableReadStream &stream) {
_sound.numLoops = (uint16)stream.readSint32LE(); // stored as an int32 on disk
_sound.volume = stream.readUint16LE();
_exitSceneID = stream.readSint16LE();
- _field35 = stream.readByte();
+ _subtitleMode = stream.readByte();
// MultiSound: one shared set of flag pairs.
if (!perGroupFlags()) {
@@ -560,6 +582,32 @@ void ConcatMultiSound::readData(Common::SeekableReadStream &stream) {
_sound.name = "NO SOUND";
}
+void ConcatMultiSound::showGroupSubtitle() {
+ if (_subtitleMode == kSubtitleModeNone) {
+ return;
+ }
+
+ // A group is captioned as a single block: the text of each of its sounds, in
+ // playback order, with a line break after every sound whose flag is set.
+ // Sounds with no text of their own contribute nothing.
+ Common::String text;
+ for (const SequencedSound &sound : _groups[_currentGroup].sounds) {
+ Common::String part = resolveSoundSubtitle(sound.name);
+ if (part.empty()) {
+ continue;
+ }
+
+ text += part;
+ if (sound.flag) {
+ text += "<n>";
+ }
+ }
+
+ if (!text.empty()) {
+ showSubtitle(text + "<e>");
+ }
+}
+
void ConcatMultiSound::startCurrentSound() {
SoundGroup &group = _groups[_currentGroup];
SequencedSound &sound = group.sounds[_currentSound];
@@ -571,6 +619,11 @@ void ConcatMultiSound::startCurrentSound() {
}
}
+ // The whole group is subtitled at once, as its first sound starts.
+ if (_currentSound == 0) {
+ showGroupSubtitle();
+ }
+
_sound.name = sound.name;
if (!_sound.name.empty() && _sound.name != "NO SOUND") {
g_nancy->_sound->loadSound(_sound);
diff --git a/engines/nancy/action/soundrecords.h b/engines/nancy/action/soundrecords.h
index 51ee7332152..513dd4f67c3 100644
--- a/engines/nancy/action/soundrecords.h
+++ b/engines/nancy/action/soundrecords.h
@@ -283,7 +283,7 @@ public:
protected:
struct SequencedSound {
Common::String name;
- byte flag = 0;
+ byte flag = 0; // when set, this sound's subtitle ends its line
int16 delay = 0; // seconds to hold after the sound starts
};
@@ -292,16 +292,22 @@ protected:
Common::Array<FlagDescription> flags; // ConcatSound only
};
+ // Selects how a group's subtitle is presented. The original picks between two
+ // textbox surfaces, which are the same textbox here, so only the value that
+ // suppresses the subtitle entirely is acted on.
+ static const byte kSubtitleModeNone = 3;
+
// Flags stored per group (ConcatSound) or as one shared set (MultiSound).
virtual bool perGroupFlags() const = 0;
+ void showGroupSubtitle();
void startCurrentSound();
Common::Array<SoundGroup> _groups;
Common::Array<FlagDescription> _sharedFlags; // MultiSound only
SoundDescription _sound;
int16 _exitSceneID = kNoScene;
- byte _field35 = 0;
+ byte _subtitleMode = 0;
// Runtime state
uint _currentGroup = 0;
Commit: 4a0f687bcbcc87c4cc3ef04c95f9ba1444ba57af
https://github.com/scummvm/scummvm/commit/4a0f687bcbcc87c4cc3ef04c95f9ba1444ba57af
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-11T08:56:10+03:00
Commit Message:
NANCY: Remove the unneeded GF_COMPRESSED flag
Check for files compressed inside CAB files through the common
InstallShield code instead.
Fix #17156
Changed paths:
engines/nancy/detection.h
engines/nancy/detection_tables.h
engines/nancy/nancy.cpp
engines/nancy/nancy.h
diff --git a/engines/nancy/detection.h b/engines/nancy/detection.h
index 1f954665307..a7977106844 100644
--- a/engines/nancy/detection.h
+++ b/engines/nancy/detection.h
@@ -66,10 +66,6 @@ enum GameType {
// Mystery of the Seven Keys was made with Unity
};
-enum NancyGameFlags {
- GF_COMPRESSED = 1 << 0
-};
-
struct NancyGameDescription {
AD_GAME_DESCRIPTION_HELPERS(desc);
diff --git a/engines/nancy/detection_tables.h b/engines/nancy/detection_tables.h
index 810faf74f40..bce2f1d18dd 100644
--- a/engines/nancy/detection_tables.h
+++ b/engines/nancy/detection_tables.h
@@ -119,7 +119,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY_GUIOPTIONS
},
kGameTypeNancy1
@@ -158,7 +158,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY2_GUIOPTIONS
},
kGameTypeNancy2
@@ -197,7 +197,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY_GUIOPTIONS
},
kGameTypeNancy3
@@ -214,7 +214,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY_GUIOPTIONS
},
kGameTypeNancy3
@@ -242,7 +242,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY_GUIOPTIONS
},
kGameTypeNancy3
@@ -281,7 +281,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY_GUIOPTIONS
},
kGameTypeNancy4
@@ -298,7 +298,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY_GUIOPTIONS
},
kGameTypeNancy4
@@ -315,7 +315,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY_GUIOPTIONS
},
kGameTypeNancy4
@@ -344,7 +344,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY_GUIOPTIONS
},
kGameTypeNancy4
@@ -372,7 +372,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY5_GUIOPTIONS
},
kGameTypeNancy5
@@ -389,7 +389,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY5_GUIOPTIONS
},
kGameTypeNancy5
@@ -406,7 +406,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY5_GUIOPTIONS
},
kGameTypeNancy5
@@ -435,7 +435,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY5_GUIOPTIONS
},
kGameTypeNancy5
@@ -467,7 +467,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY6_7_GUIOPTIONS
},
kGameTypeNancy6
@@ -484,7 +484,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY6_7_GUIOPTIONS
},
kGameTypeNancy6
@@ -501,7 +501,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY6_7_GUIOPTIONS
},
kGameTypeNancy6
@@ -529,7 +529,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY6_7_GUIOPTIONS
},
kGameTypeNancy6
@@ -557,7 +557,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY6_7_GUIOPTIONS
},
kGameTypeNancy7
@@ -574,7 +574,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY6_7_GUIOPTIONS
},
kGameTypeNancy7
@@ -602,7 +602,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY6_7_GUIOPTIONS
},
kGameTypeNancy7
@@ -630,7 +630,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY8_GUIOPTIONS
},
kGameTypeNancy8
@@ -658,7 +658,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::RU_RUS,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY8_GUIOPTIONS
},
kGameTypeNancy8
@@ -690,7 +690,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_DROPPLATFORM,
NANCY8_GUIOPTIONS
},
kGameTypeNancy9
@@ -737,7 +737,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_TESTING | ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_TESTING | ADGF_DROPPLATFORM,
NANCY8_GUIOPTIONS
},
kGameTypeNancy10
@@ -754,7 +754,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_TESTING | ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_TESTING | ADGF_DROPPLATFORM,
NANCY8_GUIOPTIONS
},
kGameTypeNancy10
@@ -770,7 +770,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_TESTING | ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_TESTING | ADGF_DROPPLATFORM,
NANCY8_GUIOPTIONS
},
kGameTypeNancy10
@@ -817,7 +817,7 @@ static const NancyGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformWindows,
- ADGF_TESTING | ADGF_DROPPLATFORM | GF_COMPRESSED,
+ ADGF_TESTING | ADGF_DROPPLATFORM,
NANCY8_GUIOPTIONS
},
kGameTypeNancy11
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 085b449a151..9bd2ebef9b4 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -579,11 +579,9 @@ void NancyEngine::bootGameEngine() {
SearchMan.addSubDirectoryMatching(gameDataDir, "font");
// Load archive if running a compressed variant
- if (isCompressed()) {
- Common::Archive *cabinet = Common::makeInstallShieldArchive("data");
- if (cabinet) {
- SearchMan.add("data1.cab", cabinet);
- }
+ Common::Archive *cabinet = Common::makeInstallShieldArchive("data");
+ if (cabinet) {
+ SearchMan.add("data1.cab", cabinet);
}
_resource->readCifTree("ciftree", "dat", 1);
@@ -978,8 +976,4 @@ Common::Error NancyEngine::synchronize(Common::Serializer &ser) {
return Common::kNoError;
}
-bool NancyEngine::isCompressed() {
- return getGameFlags() & GF_COMPRESSED;
-}
-
} // End of namespace Nancy
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index e3ec6af9737..e422e32d99f 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -181,8 +181,6 @@ private:
Common::Error synchronize(Common::Serializer &serializer);
- bool isCompressed();
-
StaticData _staticData;
Common::HashMap<Common::String, EngineData *> _engineData;
Commit: 8d230b12fe8562532e350c4bf6539f907b17f6af
https://github.com/scummvm/scummvm/commit/8d230b12fe8562532e350c4bf6539f907b17f6af
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-11T08:56:12+03:00
Commit Message:
NANCY: NANCY14: Fix making phone calls
The length of local and long distance calls is now stored in the
Telephone AR data
Changed paths:
engines/nancy/action/puzzle/telephone.cpp
engines/nancy/action/puzzle/telephone.h
diff --git a/engines/nancy/action/puzzle/telephone.cpp b/engines/nancy/action/puzzle/telephone.cpp
index a8953a17398..746cb3c1a3b 100644
--- a/engines/nancy/action/puzzle/telephone.cpp
+++ b/engines/nancy/action/puzzle/telephone.cpp
@@ -128,6 +128,11 @@ void Telephone::readData(Common::SeekableReadStream &stream) {
stream.skip(1);
readRect(stream, _exitHotspot);
+ if (_phoneType == kTelephone && g_nancy->getGameType() >= kGameTypeNancy14) {
+ _numberLength = stream.readUint16LE();
+ _longDistanceNumberLength = stream.readUint16LE();
+ }
+
uint numCalls = stream.readUint16LE();
_calls.resize(numCalls);
@@ -193,6 +198,9 @@ void Telephone::execute() {
// Pressed a new button, check all numbers for match
// We do this before going to the ringing state to support nancy4's voice mail system,
// where call numbers can be 1 digit long
+ uint numberLength = (_calledNumber.size() && _calledNumber[0] == 1) ? _longDistanceNumberLength : _numberLength;
+ bool isNumberComplete = _calledNumber.size() >= numberLength;
+
for (uint i = 0; i < _calls.size(); ++i) {
auto &call = _calls[i];
bool invalid = false;
@@ -206,13 +214,8 @@ void Telephone::execute() {
}
// We do not want to check for a terminator if the dialed number is of
- // appropriate size (7 digits, or 11 when the number starts with '1')
- bool checkNextDigit = true;
- if (_calledNumber.size() >= 11 || (_calledNumber.size() >= 7 && (_calledNumber[0] != 1))) {
- checkNextDigit = false;
- }
-
- if (!invalid && checkNextDigit) {
+ // appropriate size
+ if (!invalid && !isNumberComplete) {
// Check if the next digit in the phone number is '10' (star). Presumably, that will never
// be contained in a valid phone number
if (_calls[i].phoneNumber[_calledNumber.size()] != 10) {
@@ -230,7 +233,7 @@ void Telephone::execute() {
if (_selected == -1) {
// Did not find a suitable match, check if the dialed number is above allowed size
- if (_calledNumber.size() >= 11 || (_calledNumber.size() >= 7 && (_calledNumber[0] != 1))) {
+ if (isNumberComplete) {
shouldRing = true;
}
} else {
diff --git a/engines/nancy/action/puzzle/telephone.h b/engines/nancy/action/puzzle/telephone.h
index b1655fb1139..44944d6ea40 100644
--- a/engines/nancy/action/puzzle/telephone.h
+++ b/engines/nancy/action/puzzle/telephone.h
@@ -85,6 +85,11 @@ protected:
Common::Rect _exitHotspot;
Common::Array<PhoneCall> _calls;
+ // Number of digits a number needs before the phone starts dialing. Numbers
+ // beginning with a '1' are long distance and have their own length
+ uint16 _numberLength = 7;
+ uint16 _longDistanceNumberLength = 11;
+
// NewPhone properties
bool _hasDisplay = false;
uint16 _displayFont = 0;
Commit: 5b32023837544e719614a8a6eb770d876f23c2af
https://github.com/scummvm/scummvm/commit/5b32023837544e719614a8a6eb770d876f23c2af
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-11T08:56:14+03:00
Commit Message:
NANCY: NANCY10: Fix making calls using numbers
Changed paths:
engines/nancy/ui/cellphonepopup.cpp
diff --git a/engines/nancy/ui/cellphonepopup.cpp b/engines/nancy/ui/cellphonepopup.cpp
index 3bf1a964ff1..ad46d4be08e 100644
--- a/engines/nancy/ui/cellphonepopup.cpp
+++ b/engines/nancy/ui/cellphonepopup.cpp
@@ -1799,23 +1799,24 @@ int CellPhonePopup::findContactByDialBuffer() const {
return -1;
}
- // Dial pattern lives in prefix[2..], terminated by '\n'.
+ // The whole dial pattern is compared against the dialed digits, with any
+ // digit not yet entered counting as a zero. Contacts carry one entry per
+ // form of their number (full, without the leading '1', local only), each
+ // padded out with zeroes, so a shorter number pressed with Talk matches
+ // its own entry. Entries hidden from the directory are still callable, so
+ // the visibility flag plays no part here.
const uint dialLen = _dialedNumber.size();
for (uint i = 0; i < _contacts.size(); ++i) {
const UICL::Contact &c = _contacts[i];
- if (!isContactVisible(c)) {
- continue;
- }
bool match = true;
- for (uint b = 0; b < dialLen; ++b) {
- const byte slotIdx = (byte)(_dialedNumber[b] - '0');
- if (b >= sizeof(c.dialPattern) || slotIdx != c.dialPattern[b]) {
+ for (uint b = 0; b < sizeof(c.dialPattern); ++b) {
+ const byte slotIdx = b < dialLen ? (byte)(_dialedNumber[b] - '0') : 0;
+ if (slotIdx != c.dialPattern[b]) {
match = false;
break;
}
}
- if (match && dialLen < sizeof(c.dialPattern) &&
- c.dialPattern[dialLen] == '\n') {
+ if (match) {
return (int)i;
}
}
Commit: 566aed00f3d8aefec314008e0744e8977e1ef837
https://github.com/scummvm/scummvm/commit/566aed00f3d8aefec314008e0744e8977e1ef837
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2026-09-11T08:56:15+03:00
Commit Message:
NANCY: NANCY1-9: Cellphone fixes
- Backing away using the left hotspot no longer produces a beep sound
- During the "We're sorry" message after a bad dialed number, both the
left anr right hotspots are now active
Fix #16684
Changed paths:
engines/nancy/action/puzzle/telephone.cpp
diff --git a/engines/nancy/action/puzzle/telephone.cpp b/engines/nancy/action/puzzle/telephone.cpp
index 746cb3c1a3b..f44efbf7b6d 100644
--- a/engines/nancy/action/puzzle/telephone.cpp
+++ b/engines/nancy/action/puzzle/telephone.cpp
@@ -198,15 +198,22 @@ void Telephone::execute() {
// Pressed a new button, check all numbers for match
// We do this before going to the ringing state to support nancy4's voice mail system,
// where call numbers can be 1 digit long
+ // Phones without automatic dialing leave it to the dial button to decide when
+ // to place a call, so the whole number gets matched, with digits that were
+ // never entered counting as zeroes
+ bool matchWholeNumber = !_dialAutomatically;
uint numberLength = (_calledNumber.size() && _calledNumber[0] == 1) ? _longDistanceNumberLength : _numberLength;
- bool isNumberComplete = _calledNumber.size() >= numberLength;
+ bool isNumberComplete = matchWholeNumber || _calledNumber.size() >= numberLength;
for (uint i = 0; i < _calls.size(); ++i) {
auto &call = _calls[i];
bool invalid = false;
+ uint numDigits = matchWholeNumber ? call.phoneNumber.size() : _calledNumber.size();
- for (uint j = 0; j < _calledNumber.size(); ++j) {
- if (_calledNumber[j] != call.phoneNumber[j]) {
+ for (uint j = 0; j < numDigits; ++j) {
+ byte dialedDigit = j < _calledNumber.size() ? _calledNumber[j] : 0;
+
+ if (dialedDigit != call.phoneNumber[j]) {
// Invalid number, move onto next
invalid = true;
break;
@@ -414,6 +421,11 @@ void Telephone::handleInput(NancyInput &input) {
continue;
}
+ // So are the directory buttons when there is only a single entry to show
+ if ((i == _upDirButtonID || i == _downDirButtonID) && _calls.size() == 1) {
+ continue;
+ }
+
if (NancySceneState.getViewport().convertViewportToScreen(_destRects[i]).contains(input.mousePos)) {
g_nancy->_cursor->setCursorType(CursorManager::kHotspot);
buttonNr = i;
@@ -421,16 +433,21 @@ void Telephone::handleInput(NancyInput &input) {
}
}
- if (_callState != kWaiting && _callState != kRinging) {
- return;
- }
-
+ // The exit hotspot stays active for as long as the record is running, even
+ // while ringing, talking, or playing the bad number message. Only the
+ // buttons are limited to the states where the phone accepts input.
if (NancySceneState.getViewport().convertViewportToScreen(_exitHotspot).contains(input.mousePos)) {
g_nancy->_cursor->setCursorType(g_nancy->_cursor->_puzzleExitCursor);
if (input.input & NancyInput::kLeftMouseButtonUp) {
- g_nancy->_sound->loadSound(_hangUpSound);
- g_nancy->_sound->playSound(_hangUpSound);
+ if (_phoneType == kTelephone) {
+ g_nancy->_sound->loadSound(_hangUpSound);
+ g_nancy->_sound->playSound(_hangUpSound);
+ } else {
+ // The new phone hangs up without a sound, and without waiting for
+ // whatever is currently playing to finish
+ _state = kActionTrigger;
+ }
_callState = kHangUp;
}
More information about the Scummvm-git-logs
mailing list