[Scummvm-git-logs] scummvm master -> f84c8aec71f2f215e1512dec28f544e693898bf3
neuromancer
noreply at scummvm.org
Sun Nov 23 07:15:06 UTC 2025
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
f84c8aec71 PRIVATE: Finish implementing PoliceBust and BustMovie
Commit: f84c8aec71f2f215e1512dec28f544e693898bf3
https://github.com/scummvm/scummvm/commit/f84c8aec71f2f215e1512dec28f544e693898bf3
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-23T08:15:01+01: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;
More information about the Scummvm-git-logs
mailing list