[Scummvm-git-logs] scummvm branch-3-0 -> 2bfda36ae8bd8f4feb390cd4006424cb5c611628
sluicebox
noreply at scummvm.org
Mon Nov 24 16:16:31 UTC 2025
This automated email contains information about 9 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
09cbe2433e PRIVATE: Implement LoseInventory()
b423565c05 PRIVATE: Implement all Leave Item sounds
96f943b6d7 PRIVATE: Implement all Take Item sounds
152dbe2d28 PRIVATE: Finish implementing PoliceBust and BustMovie
d791c0e023 PRIVATE: Fix addMemory crash when helping Mavis
810266ddc8 PRIVATE: Clear diary page exits
267e3c826b PRIVATE: Hide dossier arrows when unavailable
160ea57388 PRIVATE: Improve dossier navigation
2bfda36ae8 PRIVATE: Add mapping for Japanese Windows cursors
Commit: 09cbe2433e03d3b37da982619f8ef13300d28dbb
https://github.com/scummvm/scummvm/commit/09cbe2433e03d3b37da982619f8ef13300d28dbb
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:14:18-08:00
Commit Message:
PRIVATE: Implement LoseInventory()
Changed paths:
engines/private/funcs.cpp
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index 6a163abec6b..6ab508d1b78 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -359,8 +359,9 @@ static void fNoStopSounds(ArgArray args) {
static void fLoseInventory(ArgArray args) {
assert(args.size() == 0);
- debugC(1, kPrivateDebugScript, "LoveInventory()");
- g_private->inventory.clear();
+ debugC(1, kPrivateDebugScript, "LoseInventory()");
+
+ g_private->removeRandomInventory();
}
static void fInventory(ArgArray args) {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 2374bd6fe7d..5c63b3a199b 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1081,6 +1081,31 @@ bool PrivateEngine::inInventory(const Common::String &bmp) const {
return false;
}
+void PrivateEngine::removeRandomInventory() {
+ // This logic was extracted from the executable.
+ // Examples:
+ // 0-3 items: 0 items removed
+ // 4-6 items: 1 item removed
+ // 7-10 items: 2 items removed
+ //
+ // TODO: Clear the inventory flag for the item.
+ // We are currently only removing items from the diary. We need to also
+ // remove them from Marlowe's inventory by clearing their item flag.
+ // We can do this once item flags are stored and included in save files.
+ uint numberOfItemsToRemove = (inventory.size() * 30) / 100;
+ for (uint i = 0; i < numberOfItemsToRemove; i++) {
+ uint indexToRemove = _rnd->getRandomNumber(inventory.size() - 1);
+ uint index = 0;
+ for (InvList::iterator it = inventory.begin(); it != inventory.end(); ++it) {
+ if (index == indexToRemove) {
+ inventory.erase(it);
+ break;
+ }
+ index++;
+ }
+ }
+}
+
void PrivateEngine::selectAMRadioArea(Common::Point mousePos) {
if (_AMRadioArea.surf == nullptr)
return;
diff --git a/engines/private/private.h b/engines/private/private.h
index fb45db8b4d0..5259867229a 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -335,6 +335,7 @@ public:
// Diary
InvList inventory;
bool inInventory(const Common::String &bmp) const;
+ void removeRandomInventory();
Common::String _diaryLocPrefix;
void loadLocations(const Common::Rect &);
void loadInventory(uint32, const Common::Rect &, const Common::Rect &);
Commit: b423565c059bcd818a23653f7d98105200fc237d
https://github.com/scummvm/scummvm/commit/b423565c059bcd818a23653f7d98105200fc237d
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:14:27-08:00
Commit Message:
PRIVATE: Implement all Leave Item sounds
Changed paths:
engines/private/funcs.cpp
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index 6ab508d1b78..bade9e645a2 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -59,6 +59,14 @@ static void fChgMode(ArgArray args) {
int maxLocationValue = g_private->getMaxLocationValue();
setSymbol(location, maxLocationValue + 1);
}
+ // set a game flag when visiting the police station.
+ if (!g_private->isDemo()) {
+ if (*(args[2].u.sym->name) == g_private->getPoliceStationLocation()) {
+ Common::String beenDowntownName = g_private->getBeenDowntownVariable();
+ Symbol *beenDowntown = g_private->maps.lookupVariable(&beenDowntownName);
+ setSymbol(beenDowntown, 1);
+ }
+ }
}
if (g_private->_mode == 0) {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 5c63b3a199b..93e6742b0c6 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -746,6 +746,14 @@ Common::String PrivateEngine::getWallSafeValueVariable() {
return getSymbolName("kWallSafeValue", "k3");
}
+Common::String PrivateEngine::getBeenDowntownVariable() {
+ return getSymbolName("kBeenDowntown", "k8");
+}
+
+Common::String PrivateEngine::getPoliceStationLocation() {
+ return getSymbolName("kLocationPO", "k12");
+}
+
Common::String PrivateEngine::getExitCursor() {
return getSymbolName("kExit", "k5");
}
@@ -2241,8 +2249,19 @@ Common::String PrivateEngine::getLeaveSound() {
if (isDemo())
return (_globalAudioPath + "mvo008.wav");
- uint r = _rnd->getRandomNumber(4) + 1;
- return Common::String::format("%sleft%d.wav", _globalAudioPath.c_str(), r);
+ // The last sound is only available after going to the police station.
+ const char *sounds[7] = {
+ "mvo008.wav",
+ "mvo004.wav",
+ "left1.wav",
+ "left2.wav",
+ "left3.wav",
+ "left4.wav",
+ "left5.wav" // "I've had enough trouble with the police"
+ };
+ Private::Symbol *beenDowntown = maps.variables.getVal(getBeenDowntownVariable());
+ uint r = _rnd->getRandomNumber(beenDowntown->u.val ? 6 : 5);
+ return _globalAudioPath + sounds[r];
}
Common::String PrivateEngine::getRandomPhoneClip(const char *clip, int i, int j) {
diff --git a/engines/private/private.h b/engines/private/private.h
index 5259867229a..8302e540bbe 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -302,6 +302,8 @@ public:
Common::String getAlternateGameVariable();
Common::String getPoliceIndexVariable();
Common::String getWallSafeValueVariable();
+ Common::String getBeenDowntownVariable();
+ Common::String getPoliceStationLocation();
const char *getSymbolName(const char *name, const char *strippedName, const char *demoName = nullptr);
// movies
Commit: 96f943b6d7a206659e242dfebfc89e5d8e9cde82
https://github.com/scummvm/scummvm/commit/96f943b6d7a206659e242dfebfc89e5d8e9cde82
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:14:34-08:00
Commit Message:
PRIVATE: Implement all Take Item sounds
Changed paths:
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 93e6742b0c6..f2a693c5c44 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -70,6 +70,7 @@ PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
_modified = false;
_mode = -1;
_toTake = false;
+ _haveTakenItem = false;
// Movies
_nextMovie = "";
@@ -878,6 +879,7 @@ void PrivateEngine::selectMask(Common::Point mousePos) {
setSymbol(m.flag1, 1);
playSound(getTakeSound(), 1, false, false);
_toTake = false;
+ _haveTakenItem = true;
}
}
@@ -1392,6 +1394,8 @@ void PrivateEngine::restartGame() {
sym->u.val = 0;
}
inventory.clear();
+ _toTake = false;
+ _haveTakenItem = false;
_dossiers.clear();
_diaryPages.clear();
@@ -1444,6 +1448,7 @@ Common::Error PrivateEngine::loadGameStream(Common::SeekableReadStream *stream)
for (uint32 i = 0; i < size; ++i) {
inventory.push_back(stream->readString());
}
+ _haveTakenItem = (inventory.size() > 1); // TODO: include this in save format
// Diary pages
_diaryPages.clear();
@@ -2232,8 +2237,18 @@ Common::String PrivateEngine::getTakeSound() {
if (isDemo())
return (_globalAudioPath + "mvo007.wav");
- uint r = _rnd->getRandomNumber(4) + 1;
- return Common::String::format("%stook%d.wav", _globalAudioPath.c_str(), r);
+ // Only the first four sounds are available when taking the first item.
+ const char *sounds[7] = {
+ "mvo007.wav",
+ "mvo003.wav",
+ "took1.wav",
+ "took2.wav",
+ "took3.wav",
+ "took4.wav",
+ "took5.wav"
+ };
+ uint r = _rnd->getRandomNumber(_haveTakenItem ? 6 : 3);
+ return _globalAudioPath + sounds[r];
}
Common::String PrivateEngine::getTakeLeaveSound() {
diff --git a/engines/private/private.h b/engines/private/private.h
index 8302e540bbe..806c17fe43c 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -342,6 +342,7 @@ public:
void loadLocations(const Common::Rect &);
void loadInventory(uint32, const Common::Rect &, const Common::Rect &);
bool _toTake;
+ bool _haveTakenItem;
DiaryPages _diaryPages;
int _currentDiaryPage;
ExitInfo _diaryNextPageExit;
Commit: 152dbe2d28a7bb328994e988eaab7184a6b299b1
https://github.com/scummvm/scummvm/commit/152dbe2d28a7bb328994e988eaab7184a6b299b1
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:14:51-08:00
Commit Message:
PRIVATE: Finish implementing PoliceBust and BustMovie
Changed paths:
engines/private/funcs.cpp
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index bade9e645a2..d9ae5259809 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -232,50 +232,39 @@ static void fRestartGame(ArgArray args) {
static void fPoliceBust(ArgArray args) {
// assert types
assert(args.size() == 1 || args.size() == 2);
- g_private->_policeBustEnabled = args[0].u.val;
- //debug("Number of clicks %d", g_private->computePoliceIndex());
+ int mode = (args.size() == 2) ? args[1].u.val : 0;
+ debugC(1, kPrivateDebugScript, "PoliceBust(%d, %d)", args[0].u.val, mode);
+
+ if (mode == 3) {
+ g_private->completePoliceBust();
+ return;
+ }
+ if (mode == 2) {
+ g_private->wallSafeAlarm();
+ return;
+ }
+ if (mode == 1) {
+ // Not implemented: a special mode for police busts
+ // in Marlowe's office that was removed from the game.
+ return;
+ }
- if (g_private->_policeBustEnabled)
+ if (args[0].u.val) {
g_private->startPoliceBust();
-
- if (args.size() == 2) {
- if (args[1].u.val == 2) {
- // Unclear what it means
- } else if (args[1].u.val == 3) {
- g_private->_nextSetting = g_private->getMainDesktopSetting();
- g_private->_mode = 0;
- g_private->_origin = Common::Point(kOriginZero[0], kOriginZero[1]);
- } else
- assert(0);
+ } else {
+ g_private->stopPoliceBust();
}
- debugC(1, kPrivateDebugScript, "PoliceBust(%d, ..)", args[0].u.val);
- debugC(1, kPrivateDebugScript, "WARNING: PoliceBust partially implemented");
}
static void fBustMovie(ArgArray args) {
// assert types
assert(args.size() == 1);
debugC(1, kPrivateDebugScript, "BustMovie(%s)", args[0].u.sym->name->c_str());
- uint policeIndex = g_private->maps.variables.getVal(g_private->getPoliceIndexVariable())->u.val;
- int videoIndex = policeIndex / 2 - 1;
- if (videoIndex < 0)
- videoIndex = 0;
- assert(videoIndex <= 5);
- Common::String pv =
- Common::String::format("po/animatio/spoc%02dxs.smk",
- kPoliceBustVideos[videoIndex]);
-
- if (kPoliceBustVideos[videoIndex] == 2) {
- Common::String s("global/transiti/audio/spoc02VO.wav");
- g_private->playSound(s, 1, false, false);
- g_private->changeCursor("default");
- g_private->waitForSoundToStop();
- }
- g_private->_nextMovie = pv;
+ g_private->_nextMovie = g_private->_policeBustMovie;
g_private->_nextSetting = args[0].u.sym->name->c_str();
- Common::String memoryPath = pv;
+ Common::String memoryPath = g_private->_policeBustMovie;
memoryPath.replace('/', '\\');
g_private->addMemory(memoryPath);
}
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index f2a693c5c44..bdbcccce9d0 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -53,7 +53,7 @@ extern int parse(const char *);
PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
: Engine(syst), _gameDescription(gd), _image(nullptr), _videoDecoder(nullptr),
_compositeSurface(nullptr), _transparentColor(0), _frameImage(nullptr),
- _framePalette(nullptr), _maxNumberClicks(0), _sirenWarning(0),
+ _framePalette(nullptr),
_subtitles(nullptr), _sfxSubtitles(false), _useSubtitles(false),
_defaultCursor(nullptr),
_screenW(640), _screenH(480) {
@@ -86,9 +86,7 @@ PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
_framePath = "inface/general/inface2.bmp";
// Police
- _policeBustEnabled = false;
- _policeBustSetting = "";
- _numberClicks = 0;
+ resetPoliceBust();
_sirenSound = "po/audio/posfx002.wav";
// General sounds
@@ -542,43 +540,125 @@ void PrivateEngine::clearAreas() {
}
}
+void PrivateEngine::resetPoliceBust() {
+ _policeBustEnabled = false;
+ _policeSirenPlayed = false;
+ _numberOfClicks = 0;
+ _numberClicksAfterSiren = 0;
+ _policeBustMovieIndex = 0;
+ _policeBustMovie = "";
+ _policeBustPreviousSetting = "";
+}
+
void PrivateEngine::startPoliceBust() {
- // This logic was extracted from the binary
+ _policeBustEnabled = true;
+ _policeSirenPlayed = false;
+
+ // Calculate two click counts:
+ // 1. the number of clicks until the siren warning
+ // 2. the number of clicks after the siren warning until the bust
+ // This logic was extracted from the executable.
int policeIndex = maps.variables.getVal(getPoliceIndexVariable())->u.val;
- int r = _rnd->getRandomNumber(0xc);
- if (policeIndex > 0x14) {
- policeIndex = 0x15;
+ if (policeIndex > 20) {
+ policeIndex = 21;
+ }
+ int r = _rnd->getRandomNumber(11);
+ int numberOfClicks = r + ((policeIndex * 14) / -21) + 16;
+ _numberClicksAfterSiren = _rnd->getRandomNumber(6) + 3;
+ if ((numberOfClicks - _numberClicksAfterSiren) <= 2) {
+ _numberOfClicks = 2;
+ } else {
+ _numberOfClicks = numberOfClicks - _numberClicksAfterSiren;
}
- _maxNumberClicks = r + 0x10 + (policeIndex * 0xe) / -0x15;
- _sirenWarning = _rnd->getRandomNumber(0x7) + 3;
- _numberClicks = 0;
- if (_sirenWarning >= _maxNumberClicks)
- _sirenWarning = _maxNumberClicks - 1;
}
-void PrivateEngine::checkPoliceBust() {
- if (!_policeBustEnabled)
+void PrivateEngine::stopPoliceBust() {
+ _policeBustEnabled = false;
+}
+
+void PrivateEngine::wallSafeAlarm() {
+ // This logic was extracted from the executable.
+ // It looks like the developers' intended to randomly reduce
+ // the number of clicks until the police arrive.
+ // But instead of using their low random number, they generated
+ // a new random number, so the safe alarm may increase the
+ // number of clicks until the police arrive.
+
+ int r1 = _rnd->getRandomNumber(3);
+ int r2 = _rnd->getRandomNumber(3);
+ if (r1 + r2 + 1 <= _numberOfClicks) {
+ r1 = _rnd->getRandomNumber(3);
+ r2 = _rnd->getRandomNumber(3);
+ _numberOfClicks = r1 + r2 + 1;
+ }
+}
+
+void PrivateEngine::completePoliceBust() {
+ if (!_policeBustPreviousSetting.empty()) {
+ _nextSetting = _policeBustPreviousSetting;
+ }
+
+ int policeIndex = maps.variables.getVal(getPoliceIndexVariable())->u.val;
+ if (policeIndex > 13) {
return;
+ }
+
+ // Set kPoliceArrived. This flag is cleared by the wall safe alarm.
+ Symbol *policeArrived = maps.variables.getVal(getPoliceArrivedVariable());
+ setSymbol(policeArrived, 1);
+
+ // Select the movie for BustMovie() to play
+ _policeBustMovie =
+ Common::String::format("po/animatio/spoc%02dxs.smk",
+ kPoliceBustVideos[g_private->_policeBustMovieIndex]);
+
+ // Play audio on the second bust movie
+ if (kPoliceBustVideos[_policeBustMovieIndex] == 2) {
+ Common::String s("global/transiti/audio/spoc02VO.wav");
+ g_private->playSound(s, 1, false, false);
+ g_private->changeCursor("default");
+ g_private->waitForSoundToStop();
+ }
- if (_numberClicks < _sirenWarning)
+ // Cycle to the next movie and wrap around
+ _policeBustMovieIndex = (_policeBustMovieIndex + 1) % ARRAYSIZE(kPoliceBustVideos);
+
+ _nextSetting = getPOGoBustMovieSetting();
+}
+
+void PrivateEngine::checkPoliceBust() {
+ if (!_policeBustEnabled) {
return;
+ }
- if (_numberClicks == _sirenWarning) {
- stopSound(true);
- playSound(_sirenSound, 0, false, false);
- _numberClicks++; // Won't execute again
+ if (_numberOfClicks >= 0) {
return;
}
- if (_numberClicks == _maxNumberClicks + 1) {
- uint policeIndex = maps.variables.getVal(getPoliceIndexVariable())->u.val;
- _policeBustSetting = _currentSetting;
- if (policeIndex <= 13) {
- _nextSetting = getPOGoBustMovieSetting();
+ if (!_policeSirenPlayed) {
+ // Play siren
+ stopSound(true);
+ playSound(_sirenSound, 1, false, false);
+
+ _policeSirenPlayed = true;
+ _numberOfClicks = _numberClicksAfterSiren;
+ } else {
+ // Bust Marlowe.
+ // The original seems to record _currentSetting instead of
+ // _nextSetting, but that causes a click to do nothing if it
+ // triggers a police bust that doesn't do anything except for
+ // restoring the current scene.
+ if (!_nextSetting.empty()) {
+ _policeBustPreviousSetting = _nextSetting;
} else {
- _nextSetting = getPoliceBustFromMOSetting();
+ _policeBustPreviousSetting = _currentSetting;
}
- clearAreas();
+ // The next setting is indeed kPoliceBustFromMO, even though it
+ // occurs from all locations and is unrelated to Marlowe's office.
+ // According to comments in the game script, Marlowe's office
+ // originally required a special mode but it was later removed.
+ // Apparently the developers didn't rename the setting.
+ _nextSetting = getPoliceBustFromMOSetting();
_policeBustEnabled = false;
}
}
@@ -747,6 +827,10 @@ Common::String PrivateEngine::getWallSafeValueVariable() {
return getSymbolName("kWallSafeValue", "k3");
}
+Common::String PrivateEngine::getPoliceArrivedVariable() {
+ return getSymbolName("kPoliceArrived", "k7");
+}
+
Common::String PrivateEngine::getBeenDowntownVariable() {
return getSymbolName("kBeenDowntown", "k8");
}
@@ -853,7 +937,7 @@ void PrivateEngine::selectExit(Common::Point mousePos) {
}
}
if (!ns.empty()) {
- _numberClicks++; // count click only if it hits a hotspot
+ _numberOfClicks--; // count click only if it hits a hotspot
_nextSetting = ns;
_highlightMasks = false;
}
@@ -890,7 +974,7 @@ void PrivateEngine::selectMask(Common::Point mousePos) {
}
}
if (!ns.empty()) {
- _numberClicks++; // count click only if it hits a hotspot
+ _numberOfClicks--; // count click only if it hits a hotspot
_nextSetting = ns;
_highlightMasks = false;
}
@@ -916,8 +1000,6 @@ bool PrivateEngine::selectLocation(const Common::Point &mousePos) {
}
}
- _numberClicks++;
-
// Prevent crash if there are no memories for this location
if (!diaryPageSet) {
return true;
@@ -1388,6 +1470,9 @@ void PrivateEngine::restartGame() {
sym->u.val = 0;
}
+ // Police Bust
+ resetPoliceBust();
+
// Diary
for (NameList::iterator it = maps.locationList.begin(); it != maps.locationList.end(); ++it) {
Private::Symbol *sym = maps.locations.getVal(*it);
diff --git a/engines/private/private.h b/engines/private/private.h
index 806c17fe43c..21b6b97e2c1 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -302,6 +302,7 @@ public:
Common::String getAlternateGameVariable();
Common::String getPoliceIndexVariable();
Common::String getWallSafeValueVariable();
+ Common::String getPoliceArrivedVariable();
Common::String getBeenDowntownVariable();
Common::String getPoliceStationLocation();
const char *getSymbolName(const char *name, const char *strippedName, const char *demoName = nullptr);
@@ -327,12 +328,18 @@ public:
// Police Bust
bool _policeBustEnabled;
+ bool _policeSirenPlayed;
+ int _numberOfClicks;
+ int _numberClicksAfterSiren;
+ int _policeBustMovieIndex;
+ Common::String _policeBustMovie;
+ Common::String _policeBustPreviousSetting;
+ void resetPoliceBust();
void startPoliceBust();
+ void stopPoliceBust();
+ void wallSafeAlarm();
+ void completePoliceBust();
void checkPoliceBust();
- int _numberClicks;
- int _maxNumberClicks;
- int _sirenWarning;
- Common::String _policeBustSetting;
// Diary
InvList inventory;
Commit: d791c0e0234c7ba49fe950fede371f0a40307d10
https://github.com/scummvm/scummvm/commit/d791c0e0234c7ba49fe950fede371f0a40307d10
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:14:58-08:00
Commit Message:
PRIVATE: Fix addMemory crash when helping Mavis
Changed paths:
engines/private/funcs.cpp
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index d9ae5259809..d79c4f53603 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -53,12 +53,8 @@ static void fChgMode(ArgArray args) {
if (args.size() == 3) {
Symbol *location = g_private->maps.lookupLocation(args[2].u.sym->name);
- if (location->u.val == 0) {
- // visited locations have non-zero values.
- // set to an incrementing value to record the order visited.
- int maxLocationValue = g_private->getMaxLocationValue();
- setSymbol(location, maxLocationValue + 1);
- }
+ g_private->setLocationAsVisited(location);
+
// set a game flag when visiting the police station.
if (!g_private->isDemo()) {
if (*(args[2].u.sym->name) == g_private->getPoliceStationLocation()) {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index bdbcccce9d0..6db85c1e491 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1108,7 +1108,7 @@ void PrivateEngine::addMemory(const Common::String &path) {
uint locationIndex = 0;
for (auto &it : maps.locationList) {
- const Private::Symbol *sym = maps.locations.getVal(it);
+ Private::Symbol *sym = maps.locations.getVal(it);
locationIndex++;
Common::String currentLocation = it.substr(9);
@@ -1146,7 +1146,13 @@ void PrivateEngine::addMemory(const Common::String &path) {
}
currentLocation.toLowercase();
- if (sym->u.val && currentLocation == location) {
+ if (currentLocation == location) {
+ // Ensure that the location is marked as visited.
+ // Police station video spoc00xs can be played before the
+ // police station has been visited if the player has not
+ // been busted by the police yet.
+ setLocationAsVisited(sym);
+
diaryPage.locationID = locationIndex;
break;
}
@@ -2474,6 +2480,15 @@ void PrivateEngine::loadMemories(const Common::Rect &rect, uint rightPageOffset,
}
}
+void PrivateEngine::setLocationAsVisited(Symbol *location) {
+ if (location->u.val == 0) {
+ // visited locations have non-zero values.
+ // set to an incrementing value to record the order visited.
+ int maxLocationValue = getMaxLocationValue();
+ setSymbol(location, maxLocationValue + 1);
+ }
+}
+
int PrivateEngine::getMaxLocationValue() {
int maxValue = 0;
for (SymbolMap::iterator it = maps.locations.begin(); it != maps.locations.end(); ++it) {
diff --git a/engines/private/private.h b/engines/private/private.h
index 21b6b97e2c1..78a99c05c6a 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -362,6 +362,7 @@ public:
Common::Array<MaskInfo> _locationMasks;
Common::Array<MaskInfo> _memoryMasks;
bool selectMemory(const Common::Point &mousePos);
+ void setLocationAsVisited(Symbol *location);
int getMaxLocationValue();
// Save/Load games
Commit: 810266ddc818db1a59efc8059e62716f4152fcaf
https://github.com/scummvm/scummvm/commit/810266ddc818db1a59efc8059e62716f4152fcaf
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:15:06-08:00
Commit Message:
PRIVATE: Clear diary page exits
Fixes diary page exits staying active during game
Bug ##16341
Changed paths:
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 6db85c1e491..3c00ff9bce8 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -529,6 +529,8 @@ void PrivateEngine::clearAreas() {
_dossierPrevSuspectMask.clear();
_dossierNextSheetMask.clear();
_dossierPrevSheetMask.clear();
+ _diaryNextPageExit.clear();
+ _diaryPrevPageExit.clear();
for (uint d = 0 ; d < 3; d++) {
if (_safeDigitArea[d].surf) {
diff --git a/engines/private/private.h b/engines/private/private.h
index 78a99c05c6a..24ecc4eddb2 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -82,6 +82,12 @@ typedef struct ExitInfo {
Common::String nextSetting;
Common::Rect rect;
Common::String cursor;
+
+ void clear() {
+ nextSetting.clear();
+ rect.setEmpty();
+ cursor.clear();
+ }
} ExitInfo;
typedef struct MaskInfo {
Commit: 267e3c826ba2090edacef1b7f11dceb7a02c56b0
https://github.com/scummvm/scummvm/commit/267e3c826ba2090edacef1b7f11dceb7a02c56b0
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:15:19-08:00
Commit Message:
PRIVATE: Hide dossier arrows when unavailable
Changed paths:
engines/private/funcs.cpp
engines/private/private.cpp
diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index d79c4f53603..1b648f7de5b 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -315,6 +315,10 @@ static void fDossierPrevSuspect(ArgArray args) {
Common::String s(args[0].u.str);
MaskInfo m;
+ if (g_private->_dossierSuspect == 0) {
+ return;
+ }
+
int x = args[1].u.val;
int y = args[2].u.val;
@@ -332,6 +336,10 @@ static void fDossierNextSuspect(ArgArray args) {
Common::String s(args[0].u.str);
MaskInfo m;
+ if ((g_private->_dossierSuspect + 1) >= g_private->_dossiers.size()) {
+ return;
+ }
+
int x = args[1].u.val;
int y = args[2].u.val;
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 3c00ff9bce8..e2274672107 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1306,10 +1306,9 @@ bool PrivateEngine::selectDossierNextSuspect(Common::Point mousePos) {
playSound(getPaperShuffleSound(), 1, false, false);
_dossierSuspect++;
_dossierPage = 0;
- loadDossier();
- drawMask(_dossierNextSuspectMask.surf);
- drawMask(_dossierPrevSuspectMask.surf);
- drawScreen();
+
+ // reload kDossierOpen
+ _nextSetting = _currentSetting;
}
return true;
}
@@ -1324,10 +1323,9 @@ bool PrivateEngine::selectDossierPrevSheet(Common::Point mousePos) {
if (_dossierPage == 1) {
playSound(getPaperShuffleSound(), 1, false, false);
_dossierPage = 0;
- loadDossier();
- drawMask(_dossierNextSuspectMask.surf);
- drawMask(_dossierPrevSuspectMask.surf);
- drawScreen();
+
+ // reload kDossierOpen
+ _nextSetting = _currentSetting;
}
return true;
}
@@ -1343,10 +1341,9 @@ bool PrivateEngine::selectDossierNextSheet(Common::Point mousePos) {
if (_dossierPage == 0 && !m.page2.empty()) {
playSound(getPaperShuffleSound(), 1, false, false);
_dossierPage = 1;
- loadDossier();
- drawMask(_dossierNextSuspectMask.surf);
- drawMask(_dossierPrevSuspectMask.surf);
- drawScreen();
+
+ // reload kDossierOpen
+ _nextSetting = _currentSetting;
}
return true;
}
@@ -1362,10 +1359,9 @@ bool PrivateEngine::selectDossierPrevSuspect(Common::Point mousePos) {
playSound(getPaperShuffleSound(), 1, false, false);
_dossierSuspect--;
_dossierPage = 0;
- loadDossier();
- drawMask(_dossierNextSuspectMask.surf);
- drawMask(_dossierPrevSuspectMask.surf);
- drawScreen();
+
+ // reload kDossierOpen
+ _nextSetting = _currentSetting;
}
return true;
}
Commit: 160ea573885c3a47dc813d4da4515bbde3ed90b1
https://github.com/scummvm/scummvm/commit/160ea573885c3a47dc813d4da4515bbde3ed90b1
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:15:35-08:00
Commit Message:
PRIVATE: Improve dossier navigation
Fixes two small issues:
- The "next sheet" cursor appeared even when there was no next sheet
- The dossier page acted like an exit hotspot
Changed paths:
engines/private/funcs.cpp
engines/private/private.cpp
engines/private/private.h
diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index 1b648f7de5b..6a1178e1d55 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -291,6 +291,11 @@ static void fDossierChgSheet(ArgArray args) {
Common::String s(args[0].u.str);
MaskInfo m;
+ // do nothing if suspect only has one sheet
+ if (g_private->_dossiers[g_private->_dossierSuspect].page2.empty()) {
+ return;
+ }
+
int p = args[1].u.val;
int x = args[2].u.val;
int y = args[3].u.val;
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index e2274672107..1267e0a87ab 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -105,6 +105,7 @@ PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
// Dossiers
_dossierPage = 0;
_dossierSuspect = 0;
+ _dossierPageMask.clear();
_dossierNextSuspectMask.clear();
_dossierPrevSuspectMask.clear();
_dossierNextSheetMask.clear();
@@ -380,6 +381,8 @@ Common::Error PrivateEngine::run() {
break;
else if (selectDossierPrevSheet(mousePos))
break;
+ else if (selectDossierPage(mousePos))
+ break;
else if (selectSafeDigit(mousePos))
break;
else if (selectDiaryNextPage(mousePos))
@@ -525,6 +528,7 @@ void PrivateEngine::clearAreas() {
_policeRadioArea.clear();
_AMRadioArea.clear();
_phoneArea.clear();
+ _dossierPageMask.clear();
_dossierNextSuspectMask.clear();
_dossierPrevSuspectMask.clear();
_dossierNextSheetMask.clear();
@@ -1286,15 +1290,31 @@ void PrivateEngine::loadDossier() {
int x = 40;
int y = 30;
- DossierInfo m = _dossiers[_dossierSuspect];
+ MaskInfo m;
+ DossierInfo d = _dossiers[_dossierSuspect];
if (_dossierPage == 0) {
- loadImage(m.page1, x, y);
+ m.surf = loadMask(d.page1, x, y, true);
} else if (_dossierPage == 1) {
- loadImage(m.page2, x, y);
+ m.surf = loadMask(d.page2, x, y, true);
} else {
error("Invalid page");
}
+
+ m.cursor = "default";
+ _dossierPageMask = m;
+ _masks.push_back(m); // not push_front, as this occurs after DossierChgSheet
+}
+
+bool PrivateEngine::selectDossierPage(Common::Point mousePos) {
+ if (_dossierPageMask.surf == nullptr) {
+ return false;
+ }
+
+ if (inMask(_dossierPageMask.surf, mousePos)) {
+ return true;
+ }
+ return false;
}
bool PrivateEngine::selectDossierNextSuspect(Common::Point mousePos) {
diff --git a/engines/private/private.h b/engines/private/private.h
index 24ecc4eddb2..cbe9678d03f 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -321,10 +321,12 @@ public:
DossierArray _dossiers;
uint _dossierSuspect;
uint _dossierPage;
+ MaskInfo _dossierPageMask;
MaskInfo _dossierNextSuspectMask;
MaskInfo _dossierPrevSuspectMask;
MaskInfo _dossierNextSheetMask;
MaskInfo _dossierPrevSheetMask;
+ bool selectDossierPage(Common::Point);
bool selectDossierNextSuspect(Common::Point);
bool selectDossierPrevSuspect(Common::Point);
bool selectDossierNextSheet(Common::Point);
Commit: 2bfda36ae8bd8f4feb390cd4006424cb5c611628
https://github.com/scummvm/scummvm/commit/2bfda36ae8bd8f4feb390cd4006424cb5c611628
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-24T08:15:55-08:00
Commit Message:
PRIVATE: Add mapping for Japanese Windows cursors
Changed paths:
engines/private/cursors.cpp
diff --git a/engines/private/cursors.cpp b/engines/private/cursors.cpp
index a74c9d47ea1..7d739d2a407 100644
--- a/engines/private/cursors.cpp
+++ b/engines/private/cursors.cpp
@@ -42,6 +42,7 @@ struct CursorEntry {
const char *name;
const char *aname;
uint id;
+ uint japaneseId;
};
void PrivateEngine::loadCursors() {
@@ -49,14 +50,14 @@ void PrivateEngine::loadCursors() {
if (_platform == Common::kPlatformWindows) {
const CursorEntry cursorIDReference[] = {
- { "kTurnLeft", "k1", 23 },
- { "kTurnRight", "k2", 9 },
- { "kZoomIn", "k3", 17 },
- { "kZoomOut", "k4", 11 },
- { "kExit", "k5", 7 },
- { "kPhone", "k6", 25 },
- { "kInventory", "k7", 19 },
- { nullptr, nullptr, 0 }
+ { "kTurnLeft", "k1", 23, 17 },
+ { "kTurnRight", "k2", 9, 3 },
+ { "kZoomIn", "k3", 17, 11 },
+ { "kZoomOut", "k4", 11, 5 },
+ { "kExit", "k5", 7, 1 },
+ { "kPhone", "k6", 25, 19 },
+ { "kInventory", "k7", 19, 13 },
+ { nullptr, nullptr, 0, 0 }
};
Common::WinResources *exe = nullptr;
@@ -98,7 +99,8 @@ void PrivateEngine::loadCursors() {
const CursorEntry *entry = cursorIDReference;
while (entry->name != nullptr) {
- if (entry->id == _cursors[i].winCursorGroup->cursors[0].id.getID()) {
+ uint entryId = (_language == Common::JA_JPN) ? entry->japaneseId : entry->id;
+ if (entryId == _cursors[i].winCursorGroup->cursors[0].id.getID()) {
_cursors[i].name = entry->name;
_cursors[i].aname = entry->aname;
break;
@@ -111,14 +113,14 @@ void PrivateEngine::loadCursors() {
delete exeStream;
} else {
const CursorEntry cursorIDReference[] = {
- { "kTurnLeft", "k1", 133 },
- { "kTurnRight", "k2", 132 },
- { "kZoomIn", "k3", 138 },
- { "kZoomOut", "k4", 135 },
- { "kExit", "k5", 130 },
- { "kPhone", "k6", 141 },
- { "kInventory", "k7", 139 },
- { nullptr, nullptr, 0 }
+ { "kTurnLeft", "k1", 133, 0 },
+ { "kTurnRight", "k2", 132, 0 },
+ { "kZoomIn", "k3", 138, 0 },
+ { "kZoomOut", "k4", 135, 0 },
+ { "kExit", "k5", 130, 0 },
+ { "kPhone", "k6", 141, 0 },
+ { "kInventory", "k7", 139, 0 },
+ { nullptr, nullptr, 0, 0 }
};
Common::MacResManager resMan;
More information about the Scummvm-git-logs
mailing list