[Scummvm-git-logs] scummvm branch-2-7 -> 66a0193cf500047c46a2ef598d58094192162c46

antoniou79 noreply at scummvm.org
Sat Jul 1 10:19:50 UTC 2023


This automated email contains information about 12 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
792af3f417 DEVTOOLS: BLADERUNNER: Update info on fontCreator args
b631423f48 BLADERUNNER: Don't show subtitles message for demo
9baa953423 BLADERUNNER: Notes and minor fixes for sound
7a3fe451a1 BLADERUNNER: Comment fix and notes for some Luther cues
d393610f27 BLADERUNNER: Don't spare Zuben if he hits McCoy
c5ce933aa8 BLADERUNNER: Fix glitch in CT01 mainloop
387c0129ce BLADERUNNER: Janitorial remove rogue space
d34180f962 BLADERUNNER: Fix glitches in CT01 and PS15
c2de0497a7 BLADERUNNER: Rename static method that hid base class method
3d09a61e04 BLADERUNNER: Custom beta cursors for exits and esper
4669227324 BLADERUNNER: Fix regression in zbuffer
66a0193cf5 BLADERUNNER: Fix overlay queuing in BB07


Commit: 792af3f4179fb6576c8a265fee49f848fd5c1f05
    https://github.com/scummvm/scummvm/commit/792af3f4179fb6576c8a265fee49f848fd5c1f05
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:17:19+03:00

Commit Message:
DEVTOOLS: BLADERUNNER: Update info on fontCreator args

Changed paths:
    devtools/create_bladerunner/subtitles/README.md


diff --git a/devtools/create_bladerunner/subtitles/README.md b/devtools/create_bladerunner/subtitles/README.md
index ee1578e468a..451a6ae86af 100644
--- a/devtools/create_bladerunner/subtitles/README.md
+++ b/devtools/create_bladerunner/subtitles/README.md
@@ -186,7 +186,7 @@ python2.7 fontCreator.py -ip folderpathForMIXFiles
 
 Syntax B - To create the subtitle's font:
 ```bash
-python2.7 fontCreator.py -im imageRowPNGFilename -om targetFONfilename [-oe pathToOverrideEncodingTxt] -pxLL minSpaceBetweenLettersInRowLeftToLeft -pxTT minSpaceBetweenLettersInColumnTopToTop -pxKn kerningForFirstDummyFontLetter -pxWS whiteSpaceWidthInPixels [--trace]
+python2.7 fontCreator.py -im imageRowPNGFilename -om targetFONfilename [-oe pathToOverrideEncodingTxt] -pxLL minSpaceBetweenLettersInRowLeftToLeft -pxTT minSpaceBetweenLettersInColumnTopToTop -pxKn kerningForFirstDummyFontLetter -pxWS whiteSpaceWidthInPixels [-pxYo yOffsetInPixels] [--noAutoTabCalculation] [--noSpecialGlyphs] [--trace]
 ```
 
 This tool __requires an override encoding text file__ in its Syntax B mode (subtitle font creation). You can specify the path to this file after a "-oe" switch. If you don't provide this path, the script will search for an "overrideEncoding.txt" file in the current working directory.
@@ -258,6 +258,12 @@ __For the creation of subtitles' font mode__, there are six (6) mandatory launch
 
 6.  whiteSpaceWidthInPixels: This is a positive integer value that sets the width in pixels for the single white space between words for the subtitles in-game.
 
+The "-pxYo" optional switch takes a yOffsetInPixels value: This is an integer value which sets a y-axis offset in pixels adjusting the y-axis positioning of the glyphs in-game. Typically, this is will be a small positive number, eg. "1", which would lower the glyphs on the y-axis by that amount of pixels.
+
+The "--noAutoTabCalculation" optional switch forces the tool to more accurately set the start of each glyph, which can eliminate a x-offset of all the glyphs caused by the automatic tab calculation method.
+
+The "--noSpecialGlyphs" optional switch explicitly indicates to the tool that there are no special (out of order) glyph cases.
+
 The "--trace" optional switch enables extra debug messages to be printed.
 
 A suggested method of creating decent looking PNG with the row of glyphs for your subtitles' font is the following:


Commit: b631423f4837f500f7e1920755ebfb77b54585c8
    https://github.com/scummvm/scummvm/commit/b631423f4837f500f7e1920755ebfb77b54585c8
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:17:26+03:00

Commit Message:
BLADERUNNER: Don't show subtitles message for demo

This is with regard to the warning message about missing subtitles and where to find them

Changed paths:
    engines/bladerunner/bladerunner.cpp


diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index d965f2ec3e2..cbee15b8880 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -601,14 +601,16 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
 	// Try to load the SUBTITLES.MIX first, before Startup.MIX
 	// allows overriding any identically named resources (such as the original font files and as a bonus also the TRE files for the UI and dialogue menu)
 	_subtitles = new Subtitles(this);
-	if (MIXArchive::exists("SUBTITLES.MIX")) {
-		bool r = openArchive("SUBTITLES.MIX");
-		if (!r)
-			return false;
+	if (!_isNonInteractiveDemo) {
+		if (MIXArchive::exists("SUBTITLES.MIX")) {
+			bool r = openArchive("SUBTITLES.MIX");
+			if (!r)
+				return false;
 
-		_subtitles->init();
-	} else {
-		debug("Download SUBTITLES.MIX from ScummVM's website to enable subtitles");
+			_subtitles->init();
+		} else {
+			debug("Download SUBTITLES.MIX from ScummVM's website to enable subtitles");
+		}
 	}
 
 	_audioMixer = new AudioMixer(this);


Commit: 9baa95342307e117c7ac88df1aced242f6ae773a
    https://github.com/scummvm/scummvm/commit/9baa95342307e117c7ac88df1aced242f6ae773a
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:17:33+03:00

Commit Message:
BLADERUNNER: Notes and minor fixes for sound

Also added a dedicated debugSound channel for debugging

Fixes include closer conformance to original code (for entering/exiting ESPER and VK), and a change in assigning a track slot to a new track with priority equal to the lowest existing (it will now take the place of the old stored track). Also Music::adjustVolume() now takes the target volume as argument and stores it in the track volume field similar to how Music::adjustPan works.

Changed paths:
    engines/bladerunner/actor.cpp
    engines/bladerunner/ambient_sounds.cpp
    engines/bladerunner/ambient_sounds.h
    engines/bladerunner/audio_mixer.cpp
    engines/bladerunner/audio_mixer.h
    engines/bladerunner/audio_player.cpp
    engines/bladerunner/audio_player.h
    engines/bladerunner/audio_speech.cpp
    engines/bladerunner/audio_speech.h
    engines/bladerunner/bladerunner.h
    engines/bladerunner/detection.cpp
    engines/bladerunner/music.cpp
    engines/bladerunner/music.h
    engines/bladerunner/script/script.cpp
    engines/bladerunner/ui/end_credits.cpp
    engines/bladerunner/ui/esper.cpp
    engines/bladerunner/ui/esper.h
    engines/bladerunner/ui/vk.cpp
    engines/bladerunner/ui/vk.h
    engines/bladerunner/vqa_player.cpp


diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp
index 23e54d08d5a..037e2fa8150 100644
--- a/engines/bladerunner/actor.cpp
+++ b/engines/bladerunner/actor.cpp
@@ -1581,6 +1581,7 @@ int Actor::soundVolume() const {
 }
 
 // overrideRange argument was added to allow for more accurate sound balance on occasion (if required)
+// overrideRange value should be in [35, 100]
 int Actor::soundPan(uint8 overrideRange) const {
 	Vector3 screenPosition = _vm->_view->calculateScreenPosition(_position);
 	// By default map [0..640] to [-overrideRange..overrideRange] (default range [-35..35])
diff --git a/engines/bladerunner/ambient_sounds.cpp b/engines/bladerunner/ambient_sounds.cpp
index bc6de09d400..f02a6fdce7a 100644
--- a/engines/bladerunner/ambient_sounds.cpp
+++ b/engines/bladerunner/ambient_sounds.cpp
@@ -42,10 +42,13 @@ AmbientSounds::AmbientSounds(BladeRunnerEngine *vm) {
 	// In our BladeRunner engine ambient sounds do not have a distinct sound type of their own,
 	// so they are treated as kAmbientSoundType (default type, see: ambient_sounds.h).
 	//
-	// _ambientVolume here sets a percentage to be appied on the specified track volume
-	// before sending it to the audio player
-	// (setting _ambientVolume to 100 renders it indifferent)
-	_ambientVolume = BLADERUNNER_ORIGINAL_SETTINGS ? 65 : 100;
+	// _ambientVolumeFactorOriginalEngine here sets a percentage to be applied on the ambient audio tracks' volume
+	// before sending them to the audio player.
+	// This is how the original engine set the volume via the in-game KIA volume slider controls.
+	// Setting _ambientVolumeFactorOriginalEngine to 100, for the purposes ScummVM engine, renders it indifferent,
+	// so sound volume can be controlled by ScummVM's Global Main Menu / ConfMan/ syncSoundSettings().
+	// Note however that _ambientVolumeFactorOriginalEngine is also changed when entering and exiting ESPER and possibly VK modes.
+	_ambientVolumeFactorOriginalEngine = BLADERUNNER_ORIGINAL_SETTINGS ? 65 : 100;
 
 	for (int i = 0; i != kNonLoopingSounds; ++i) {
 		NonLoopingSound &track = _nonLoopingSounds[i];
@@ -109,33 +112,39 @@ static inline void sort(uint32 *a, uint32 *b) {
 // addSound() will add a track to the non-looping tracks array list
 // it will use the kAmbientSoundType for Mixer's Sound Type.
 // see AmbientSounds::tick()
-void AmbientSounds::addSound(
-	int sfxId,
-	uint32 delayMinSeconds, uint32 delayMaxSeconds,
-	int volumeMin, int volumeMax,
-	int panStartMin, int panStartMax,
-	int panEndMin, int panEndMax,
-	int priority, int unk) {
-
-#if BLADERUNNER_ORIGINAL_BUGS
-#else
-	sort(&delayMinSeconds, &delayMaxSeconds);
-#endif // BLADERUNNER_ORIGINAL_BUGS
-	sort(&volumeMin, &volumeMax);
-	sort(&panStartMin, &panStartMax);
-	sort(&panEndMin, &panEndMax);
-
-	addSoundByName(
-				_vm->_gameInfo->getSfxTrack(sfxId),
-				delayMinSeconds, delayMaxSeconds,
-				volumeMin, volumeMax,
-				panStartMin, panStartMax,
-				panEndMin, panEndMax,
-				priority, unk
-				);
+// Used also by:
+//            Ambient_Sounds_Add_Sound()
+//            Spinner::chooseDestination()
+// Calls:
+//            addSoundByName()
+//
+// volumeMin, volumeMax should be in [0, 100]
+// panStartMin, panStartMax should be in [-100, 100]
+// panEndMin, panEndMax should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
+// priority should be in [0, 100]
+void AmbientSounds::addSound(int sfxId,
+                             uint32 delayMinSeconds, uint32 delayMaxSeconds,
+                             int volumeMin, int volumeMax,
+                             int panStartMin, int panStartMax,
+                             int panEndMin, int panEndMax,
+                             int priority, int unk) {
+	debugC(6, kDebugSound, "AmbientSounds::addSound id:%d dMin:%d,dMax:%d vMin:%d,vMax:%d pSMin:%d,pSMax:%d pEMin:%d,pEMax:%d pr:%d unk:%d",
+	       sfxId,
+	       delayMinSeconds, delayMaxSeconds,
+	       volumeMin, volumeMax,
+	       panStartMin,panStartMax,
+	       panEndMin, panEndMax,
+	       priority, unk);
+	addSoundByName(_vm->_gameInfo->getSfxTrack(sfxId),
+	               delayMinSeconds, delayMaxSeconds,
+	               volumeMin, volumeMax,
+	               panStartMin, panStartMax,
+	               panEndMin, panEndMax,
+	               priority, unk);
 }
 
 void AmbientSounds::removeNonLoopingSound(int sfxId, bool stopPlaying) {
+	debugC(6, kDebugSound, "AmbientSounds::removeNonLoopingSound id:%d stop:%d", sfxId, stopPlaying? 1: 0);
 	int32 hash = MIXArchive::getHash(_vm->_gameInfo->getSfxTrack(sfxId));
 	int index = findNonLoopingTrackByHash(hash);
 	if (index >= 0) {
@@ -144,6 +153,7 @@ void AmbientSounds::removeNonLoopingSound(int sfxId, bool stopPlaying) {
 }
 
 void AmbientSounds::removeAllNonLoopingSounds(bool stopPlaying) {
+	debugC(6, kDebugSound, "AmbientSounds::removeAllNonLoopingSounds stop:%d", stopPlaying? 1: 0);
 	for (int i = 0; i < kNonLoopingSounds; ++i) {
 		removeNonLoopingSoundByIndex(i, stopPlaying);
 	}
@@ -153,38 +163,65 @@ void AmbientSounds::removeAllNonLoopingSounds(bool stopPlaying) {
 // addSpeech() will add a track to the non-looping tracks array list
 // it will use the kAmbientSoundType for Mixer's Sound Type
 // see AmbientSounds::tick()
-void AmbientSounds::addSpeech(int actorId, int sentenceId, uint32 delayMinSeconds, uint32 delayMaxSeconds, int volumeMin, int volumeMax, int panStartMin, int panStartMax, int panEndMin, int panEndMax, int priority, int unk) {
-#if BLADERUNNER_ORIGINAL_BUGS
-#else
-	sort(&delayMinSeconds, &delayMaxSeconds);
-#endif // BLADERUNNER_ORIGINAL_BUGS
-	sort(&volumeMin, &volumeMax);
-	sort(&panStartMin, &panStartMax);
-	sort(&panEndMin, &panEndMax);
-
+// Mainly used for dispatch radio ambient sounds and blimp announcements.
+// Called by:
+//            Ambient_Sounds_Add_Speech_Sound()
+// Calls:
+//            addSoundByName()
+//
+// volumeMin, volumeMax should be in [0, 100]
+// panStartMin, panStartMax should be in [-100, 100]
+// panEndMin, panEndMax should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
+// priority should be in [0, 100]
+void AmbientSounds::addSpeech(int actorId, int sentenceId,
+                              uint32 delayMinSeconds, uint32 delayMaxSeconds,
+                              int volumeMin, int volumeMax,
+                              int panStartMin, int panStartMax,
+                              int panEndMin, int panEndMax,
+                              int priority, int unk) {
+	debugC(6, kDebugSound, "AmbientSounds::addSpeech id:%d-%d dMin:%d,dMax:%d vMin:%d,vMax:%d pSMin:%d,pSMax:%d pEMin:%d,pEMax:%d pr:%d unk:%d",
+	       actorId, sentenceId,
+	       delayMinSeconds, delayMaxSeconds,
+	       volumeMin, volumeMax,
+	       panStartMin,panStartMax,
+	       panEndMin, panEndMax,
+	       priority, unk);
 	Common::String name = Common::String::format( "%02d-%04d%s.AUD", actorId, sentenceId, _vm->_languageCode.c_str());
 	addSoundByName(name,
-					delayMinSeconds, delayMaxSeconds,
-					volumeMin, volumeMax,
-					panStartMin, panStartMax,
-					panEndMin, panEndMax,
-					priority, unk);
+	               delayMinSeconds, delayMaxSeconds,
+	               volumeMin, volumeMax,
+	               panStartMin, panStartMax,
+	               panEndMin, panEndMax,
+	               priority, unk);
 }
 
 // Explicitly plays a sound effect (sfx) track (specified by id)
 // It does not add it as a track to the non-looping tracks array list
 // It uses the parameter "type" as the mixer's sound type - which determines the volume setting in effect.
 // By default sound type is kAmbientSoundType (see ambient_sounds.h).
+//
+// volume should be in [0, 100]
+// panStart should be in [-100, 100]
+// panEnd should be in [-100, 100]
+// priority should be in [0, 100]
 void AmbientSounds::playSound(int sfxId, int volume, int panStart, int panEnd, int priority, Audio::Mixer::SoundType type) {
-	_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(sfxId), volume * _ambientVolume / 100, panStart, panEnd, priority, kAudioPlayerOverrideVolume, type);
+	debugC(6, kDebugSound, "AmbientSounds::playSound id:%d v:%d pS:%d pE:%d pr:%d typ:%d", sfxId, volume, panStart, panEnd, priority, (int32) type);
+	_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(sfxId), (volume * _ambientVolumeFactorOriginalEngine) / 100, panStart, panEnd, priority, kAudioPlayerOverrideVolume, type);
 }
 
 // Explicitly plays a speech cue
 // It does not add it as a track to the non-looping tracks array list
 // It uses mixer's sound type kSpeechSoundType - which determines the volume setting in effect (Speech)
+//
+// volume should be in [0, 100]
+// panStart should be in [-100, 100]
+// panEnd should be in [-100, 100]
+// priority should be in [0, 100]
 void AmbientSounds::playSpeech(int actorId, int sentenceId, int volume, int panStart, int panEnd, int priority) {
+	debugC(6, kDebugSound, "AmbientSounds::playSpeech id:%d-%d v:%d pS:%d pE:%d pr:%d", actorId, sentenceId, volume, panStart, panEnd, priority);
 	Common::String name = Common::String::format( "%02d-%04d%s.AUD", actorId, sentenceId, _vm->_languageCode.c_str());
-	_vm->_audioPlayer->playAud(name, volume * _ambientVolume / 100, panStart, panEnd, priority, kAudioPlayerOverrideVolume, Audio::Mixer::kSpeechSoundType);
+	// (volume * _ambientVolume) / 100 should result in a value in [0, 100]
+	_vm->_audioPlayer->playAud(name, (volume * _ambientVolumeFactorOriginalEngine) / 100, panStart, panEnd, priority, kAudioPlayerOverrideVolume, Audio::Mixer::kSpeechSoundType);
 }
 
 // Looping Sound will use paramerter "type" as the mixer's SoundType when playing this track.
@@ -197,7 +234,11 @@ void AmbientSounds::playSpeech(int actorId, int sentenceId, int volume, int panS
 // which is skipped for *both* looping and non-looping tracks in save() and load() code
 // However, the issue is negligible; the default SoundType for looping tracks is overridden
 // only in one special case so far (restored content Outtake "FLYTRU_E.VQA", see: outtake.cpp)
+//
+// volume should be in [0, 100]
+// pan should be in [-100, 100]
 void AmbientSounds::addLoopingSound(int sfxId, int volume, int pan, uint32 delaySeconds, Audio::Mixer::SoundType type) {
+	debugC(6, kDebugSound, "AmbientSounds::addLoopingSound id:%d v:%d p:%d d:%u typ:%d", sfxId, volume, pan, delaySeconds, (int32) type);
 	const Common::String &name = _vm->_gameInfo->getSfxTrack(sfxId);
 	int32 hash = MIXArchive::getHash(name);
 
@@ -218,13 +259,16 @@ void AmbientSounds::addLoopingSound(int sfxId, int volume, int pan, uint32 delay
 	track.volume = volume;
 	track.soundType = (int32) type;
 
-	int actualVolumeStart = volume * _ambientVolume / 100;
+	int actualVolumeStart = (volume * _ambientVolumeFactorOriginalEngine) / 100;
 	int actualVolumeEnd = actualVolumeStart;
 
 	if (delaySeconds > 0u) {
 		actualVolumeStart = 0;
 	}
 
+	// actualVolumeStart should be in [0, 100]
+	// pan should be in [-100, 100]
+	// priority should be in [0, 100]
 	track.audioPlayerTrack = _vm->_audioPlayer->playAud(name, actualVolumeStart, pan, pan, 99, kAudioPlayerLoop | kAudioPlayerOverrideVolume, type);
 
 	if (track.audioPlayerTrack == -1) {
@@ -236,14 +280,17 @@ void AmbientSounds::addLoopingSound(int sfxId, int volume, int pan, uint32 delay
 	}
 }
 
+// volume should be in [0, 100], with "-1" being a special value for skipping volume adjustment
+// pan should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
 void AmbientSounds::adjustLoopingSound(int sfxId, int volume, int pan, uint32 delaySeconds) {
+	debugC(6, kDebugSound, "AmbientSounds::adjustLoopingSound id:%d v:%d p:%d d:%u", sfxId, volume, pan, delaySeconds);
 	int32 hash = MIXArchive::getHash(_vm->_gameInfo->getSfxTrack(sfxId));
 	int index = findLoopingTrackByHash(hash);
 
 	if (index >= 0 && _loopingSounds[index].audioPlayerTrack != -1 && _vm->_audioPlayer->isActive(_loopingSounds[index].audioPlayerTrack)) {
 		if (volume != -1) {
 			_loopingSounds[index].volume = volume;
-			_vm->_audioPlayer->adjustVolume(_loopingSounds[index].audioPlayerTrack, _ambientVolume * volume / 100, delaySeconds, false);
+			_vm->_audioPlayer->adjustVolume(_loopingSounds[index].audioPlayerTrack, (volume * _ambientVolumeFactorOriginalEngine) / 100, delaySeconds, false);
 		}
 		if (pan != -101) {
 			_loopingSounds[index].pan = pan;
@@ -253,6 +300,7 @@ void AmbientSounds::adjustLoopingSound(int sfxId, int volume, int pan, uint32 de
 }
 
 void AmbientSounds::removeLoopingSound(int sfxId, uint32 delaySeconds) {
+	debugC(6, kDebugSound, "AmbientSounds::removeLoopingSound id:%d d:%u", sfxId, delaySeconds);
 	int32 hash = MIXArchive::getHash(_vm->_gameInfo->getSfxTrack(sfxId));
 	int index = findLoopingTrackByHash(hash);
 	if (index >= 0) {
@@ -261,6 +309,7 @@ void AmbientSounds::removeLoopingSound(int sfxId, uint32 delaySeconds) {
 }
 
 void AmbientSounds::removeAllLoopingSounds(uint32 delaySeconds) {
+	debugC(6, kDebugSound, "AmbientSounds::removeAllLoopingSounds d:%u", delaySeconds);
 	for (int i = 0; i < kLoopingSounds; ++i) {
 		removeLoopingSoundByIndex(i, delaySeconds);
 	}
@@ -280,10 +329,12 @@ void AmbientSounds::tick() {
 
 		int panEnd;
 		int panStart = _vm->_rnd.getRandomNumberRng(track.panStartMin, track.panStartMax);
-		if (track.panEndMin == -101) {
-			panEnd = panStart;
-		} else {
+		// typically when using the -101 special value, both panEndMin and panEndMax have this value
+		// -101 here means "do not adjust the panning for the track (while it's playing)"
+		if (track.panEndMin != -101) {
 			panEnd = _vm->_rnd.getRandomNumberRng(track.panEndMin, track.panEndMax);
+		} else {
+			panEnd = panStart;
 		}
 
 		track.volume = _vm->_rnd.getRandomNumberRng(track.volumeMin, track.volumeMax);
@@ -293,7 +344,7 @@ void AmbientSounds::tick() {
 			mixerAmbientSoundType = (Audio::Mixer::SoundType) track.soundType;
 		}
 		track.audioPlayerTrack = _vm->_audioPlayer->playAud(track.name,
-		                                                    track.volume * _ambientVolume / 100,
+		                                                    (track.volume * _ambientVolumeFactorOriginalEngine) / 100,
 		                                                    panStart,
 		                                                    panEnd,
 		                                                    track.priority,
@@ -305,11 +356,19 @@ void AmbientSounds::tick() {
 	}
 }
 
+// TODO Evaluate if for ScummVM we can avoid using and modifying _ambientVolumeFactorOriginalEngine altogether.
+// While we no longer use the original engine's mechanism to set the ambient sounds volume
+// with the AmbientSounds::setVolume() public method, when using the in-game KIA volume slider,
+// we do use this method as did the original engine to temporarily set the volume levels
+// in ESPER and VK modes.
+// This affects only looping ambient sounds.
+// volume should be in [0, 100]
 void AmbientSounds::setVolume(int volume) {
+	debugC(6, kDebugSound, "AmbientSounds::setVolume v:%d", volume);
 	if (_loopingSounds) {
 		for (int i = 0; i < kLoopingSounds; ++i) {
 			if (_loopingSounds[i].isActive && _loopingSounds[i].audioPlayerTrack != -1) {
-				int newVolume = _loopingSounds[i].volume * volume / 100;
+				int newVolume = (_loopingSounds[i].volume * volume) / 100;
 				if (_vm->_audioPlayer->isActive(_loopingSounds[i].audioPlayerTrack)) {
 					_vm->_audioPlayer->adjustVolume(_loopingSounds[i].audioPlayerTrack, newVolume, 1u, false);
 				} else {
@@ -327,14 +386,15 @@ void AmbientSounds::setVolume(int volume) {
 			}
 		}
 	}
-	_ambientVolume = volume;
+	_ambientVolumeFactorOriginalEngine = volume;
 }
 
 int AmbientSounds::getVolume() const {
-	return _ambientVolume;
+	return _ambientVolumeFactorOriginalEngine;
 }
 
 void AmbientSounds::playSample() {
+	// Original uses priority 0 here also
 	playSound(kSfxSPIN1A, 100, 0, 0, 0);
 }
 
@@ -382,13 +442,16 @@ int AmbientSounds::findLoopingTrackByHash(int32 hash) const {
 	return -1;
 }
 
-void AmbientSounds::addSoundByName(
-	const Common::String &name,
-	uint32 delayMinSeconds, uint32 delayMaxSeconds,
-	int volumeMin, int volumeMax,
-	int panStartMin, int panStartMax,
-	int panEndMin, int panEndMax,
-	int priority, int unk) {
+// volumeMin, volumeMax should be in [0, 100]
+// panStartMin, panStartMax should be in [-100, 100]
+// panEndMin, panEndMax should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
+// priority should be in [0, 100]
+void AmbientSounds::addSoundByName(const Common::String &name,
+                                   uint32 delayMinSeconds, uint32 delayMaxSeconds,
+                                   int volumeMin, int volumeMax,
+                                   int panStartMin, int panStartMax,
+                                   int panEndMin, int panEndMax,
+                                   int priority, int unk) {
 
 	int i = findAvailableNonLoopingTrack();
 	if (i < 0) {
@@ -399,13 +462,12 @@ void AmbientSounds::addSoundByName(
 
 	uint32 now = _vm->_time->current();
 
-#if BLADERUNNER_ORIGINAL_BUGS
-#else
+#if !BLADERUNNER_ORIGINAL_BUGS
 	sort(&delayMinSeconds, &delayMaxSeconds);
+#endif // BLADERUNNER_ORIGINAL_BUGS
 	sort(&volumeMin, &volumeMax);
 	sort(&panStartMin, &panStartMax);
 	sort(&panEndMin, &panEndMax);
-#endif // BLADERUNNER_ORIGINAL_BUGS
 
 	track.isActive = true;
 	track.name = name;
@@ -594,11 +656,13 @@ void AmbientSounds::load(SaveFileReadStream &f) {
 			if (track.soundType >= 0) {
 				mixerAmbientSoundType = (Audio::Mixer::SoundType) track.soundType;
 			}
+			// Looping sound (loaded) gets high priority (99)
+			// Also started with volume at 1 (but adjusted below appropriately)
 			track.audioPlayerTrack = _vm->_audioPlayer->playAud(track.name, 1, track.pan, track.pan, 99, kAudioPlayerLoop | kAudioPlayerOverrideVolume, mixerAmbientSoundType);
 			if (track.audioPlayerTrack == -1) {
 				removeLoopingSoundByIndex(i, 0u);
 			} else {
-				_vm->_audioPlayer->adjustVolume(track.audioPlayerTrack, _ambientVolume * track.volume / 100, 2u, false);
+				_vm->_audioPlayer->adjustVolume(track.audioPlayerTrack, (track.volume * _ambientVolumeFactorOriginalEngine) / 100, 2u, false);
 			}
 		}
 	}
diff --git a/engines/bladerunner/ambient_sounds.h b/engines/bladerunner/ambient_sounds.h
index eb797c6991f..98b45f64c03 100644
--- a/engines/bladerunner/ambient_sounds.h
+++ b/engines/bladerunner/ambient_sounds.h
@@ -22,6 +22,8 @@
 #ifndef BLADERUNNER_AMBIENT_SOUNDS_H
 #define BLADERUNNER_AMBIENT_SOUNDS_H
 
+#include "bladerunner/bladerunner.h" // For BLADERUNNER_ORIGINAL_SETTINGS symbol
+
 #include "audio/audiostream.h"
 #include "audio/mixer.h"
 
@@ -47,15 +49,15 @@ class AmbientSounds {
 		uint32         delayMax;          // milliseconds
 		uint32         nextPlayTimeStart; // milliseconds
 		uint32         nextPlayTimeDiff;  // milliseconds
-		int            volumeMin;
-		int            volumeMax;
-		int            volume;
-		int            panStartMin;
-		int            panStartMax;
-		int            panEndMin;
-		int            panEndMax;
-		int            priority;
-		int32          soundType; // new - not stored in saved games
+		int            volumeMin;   // should be in [0, 100]
+		int            volumeMax;   // should be in [0, 100]
+		int            volume;      // should be in [0, 100] (calculated as a random value within [volumeMin, volumeMax]
+		int            panStartMin; // should be in [-100, 100]
+		int            panStartMax; // should be in [-100, 100]
+		int            panEndMin;   // should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
+		int            panEndMax;   // should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
+		int            priority;    // should be in [0, 100]
+		int32          soundType;   // new - not stored in saved games
 	};
 
 	struct LoopingSound {
@@ -63,8 +65,8 @@ class AmbientSounds {
 		Common::String name;
 		int32          hash;
 		int            audioPlayerTrack;
-		int            volume;
-		int            pan;
+		int            volume; // should be in [0, 100]
+		int            pan;    // should be in [-100, 100]
 		int32          soundType; // new - not stored in saved games
 	};
 
@@ -72,30 +74,27 @@ class AmbientSounds {
 
 	NonLoopingSound *_nonLoopingSounds;
 	LoopingSound    *_loopingSounds;
-	int              _ambientVolume;
+	int              _ambientVolumeFactorOriginalEngine; // should be in [0, 100]
 
 public:
 	AmbientSounds(BladeRunnerEngine *vm);
 	~AmbientSounds();
 
-	void addSound(
-		int sfxId,
-		uint32 delayMinSeconds, uint32 delayMaxSeconds,
-		int volumeMin, int volumeMax,
-		int panStartMin, int panStartMax,
-		int panEndMin, int panEndMax,
-		int priority, int unk
-	);
+	void addSound(int sfxId,
+	              uint32 delayMinSeconds, uint32 delayMaxSeconds,
+	              int volumeMin, int volumeMax,
+	              int panStartMin, int panStartMax,
+	              int panEndMin, int panEndMax,
+	              int priority, int unk);
 	void removeNonLoopingSound(int sfxId, bool stopPlaying);
 	void removeAllNonLoopingSounds(bool stopPlaying);
 
-	void addSpeech(
-		int actorId, int sentenceId,
-		uint32 delayMinSeconds, uint32 delayMaxSeconds,
-		int volumeMin, int volumeMax,
-		int panStartMin, int panStartMax,
-		int panEndMin, int panEndMax,
-		int priority, int unk);
+	void addSpeech(int actorId, int sentenceId,
+	               uint32 delayMinSeconds, uint32 delayMaxSeconds,
+	               int volumeMin, int volumeMax,
+	               int panStartMin, int panStartMax,
+	               int panEndMin, int panEndMax,
+	               int priority, int unk);
 	void playSound(int sfxId, int volume, int panStart, int panEnd, int priority, Audio::Mixer::SoundType type = kAmbientSoundType);
 	void playSpeech(int actorId, int sentenceId, int volume, int panStart, int panEnd, int priority);
 
@@ -122,13 +121,12 @@ private:
 	int findAvailableLoopingTrack() const;
 	int findLoopingTrackByHash(int32 hash) const;
 
-	void addSoundByName(
-		const Common::String &name,
-		uint32 delayMinSeconds, uint32 delayMaxSeconds,
-		int volumeMin, int volumeMax,
-		int panStartMin, int panStartMax,
-		int panEndMin, int panEndMax,
-		int priority, int unk);
+	void addSoundByName(const Common::String &name,
+	                    uint32 delayMinSeconds, uint32 delayMaxSeconds,
+	                    int volumeMin, int volumeMax,
+	                    int panStartMin, int panStartMax,
+	                    int panEndMin, int panEndMax,
+	                    int priority, int unk);
 
 	void removeNonLoopingSoundByIndex(int index, bool stopPlaying);
 	void removeLoopingSoundByIndex(int index, uint32 delaySeconds);
diff --git a/engines/bladerunner/audio_mixer.cpp b/engines/bladerunner/audio_mixer.cpp
index b4d0a793d83..55d1e700a23 100644
--- a/engines/bladerunner/audio_mixer.cpp
+++ b/engines/bladerunner/audio_mixer.cpp
@@ -54,15 +54,17 @@ AudioMixer::~AudioMixer() {
 	_vm->getTimerManager()->removeTimerProc(timerCallback);
 }
 
+// volume should be in [0, 100]
+// pan should be in [-100, 100]
+// priority should be in [0, 100]
 int AudioMixer::play(Audio::Mixer::SoundType type, Audio::RewindableAudioStream *stream, int priority, bool loop, int volume, int pan, void (*endCallback)(int, void *), void *callbackData, uint32 trackDurationMs) {
 	Common::StackLock lock(_mutex);
-
-	int channel = -1;
+	int channelToAssign = -1;
 	int lowestPriority = 1000000;
 	int lowestPriorityChannel = -1;
 	for (int i = 0; i < kUsableChannels; ++i) {
 		if (!_channels[i].isPresent) {
-			channel = i;
+			channelToAssign = i;
 			break;
 		}
 		if (_channels[i].priority < lowestPriority) {
@@ -70,22 +72,28 @@ int AudioMixer::play(Audio::Mixer::SoundType type, Audio::RewindableAudioStream
 			lowestPriorityChannel = i;
 		}
 	}
-	if (channel == -1) {
+
+	// If there's no available channel found
+	if (channelToAssign == -1) {
+		// Give up if the lowest priority channel still has greater priority (lowestPriority).
+		// NOTE If the new priority is *equal* to the existing lowestPriority,
+		// then the new audio will replace the old one.
 		if (priority < lowestPriority) {
 			//debug("No available audio channel found - giving up");
 			return -1;
 		}
+		// Otherwise, stop the lowest priority channel, and assign the slot to the new one.
 		//debug("Stopping lowest priority channel %d with lower prio %d!", lowestPriorityChannel, lowestPriority);
 		stop(lowestPriorityChannel, 0u);
-		channel = lowestPriorityChannel;
+		channelToAssign = lowestPriorityChannel;
 	}
 
-	return playInChannel(channel, type, stream, priority, loop, volume, pan, endCallback, callbackData, trackDurationMs);
+	return playInChannel(channelToAssign, type, stream, priority, loop, volume, pan, endCallback, callbackData, trackDurationMs);
 }
 
+// volume should be in [0, 100]
 int AudioMixer::playMusic(Audio::RewindableAudioStream *stream, int volume, void(*endCallback)(int, void *), void *callbackData, uint32 trackDurationMs) {
 	Common::StackLock lock(_mutex);
-
 	return playInChannel(kMusicChannel, Audio::Mixer::kMusicSoundType, stream, 100, false, volume, 0, endCallback, callbackData, trackDurationMs);
 }
 
@@ -109,6 +117,9 @@ void AudioMixer::stop(int channel, uint32 time) {
 	}
 }
 
+// volume should be in [0, 100]
+// pan should be in [-100, 100]
+// priority should be in [0, 100]
 int AudioMixer::playInChannel(int channel, Audio::Mixer::SoundType type, Audio::RewindableAudioStream *stream, int priority, bool loop, int volume, int pan, void(*endCallback)(int, void *), void *callbackData, uint32 trackDurationMs) {
 	_channels[channel].isPresent = true;
 	_channels[channel].stream = stream;
@@ -137,13 +148,15 @@ int AudioMixer::playInChannel(int channel, Audio::Mixer::SoundType type, Audio::
 	}
 	_channels[channel].sentToMixer = true;
 
-	_vm->_mixer->playStream(
-		type,
-		&_channels[channel].handle,
-		audioStream,
-		-1,
-		volume * 255 / 100,
-		pan * 127 / 100);
+	// Note: 127 (multiplier for pan) is the max (abs) balance value (see common/mixer.cpp)
+	_vm->_mixer->playStream(type,
+	                        &_channels[channel].handle,
+	                        audioStream,
+	                        -1,
+	                        (volume * Audio::Mixer::kMaxChannelVolume) / 100, // the resulting value will be a percentage over kMaxChannelVolume
+	                                              // playStream() will get the soundtype volume into consideration
+	                                              // See: Channel::updateChannelVolumes() in audio/mixer.cpp
+	                        (pan * 127) / 100);
 
 	return channel;
 }
@@ -160,24 +173,30 @@ void AudioMixer::timerCallback(void *self) {
 	((AudioMixer *)self)->tick();
 }
 
+// This method sets the target volume (as a percent) and the delta increment or decrement
+// to reach the target in the specified time.
 // Note: time tends to be the requested time in seconds multiplied by 60u
-void AudioMixer::adjustVolume(int channel, int newVolume, uint32 time) {
+// targetVolume should be in [0, 100]
+void AudioMixer::adjustVolume(int channel, int targetVolume, uint32 time) {
 	Common::StackLock lock(_mutex);
 
 	if (_channels[channel].isPresent) {
-		_channels[channel].volumeTarget = newVolume;
-		_channels[channel].volumeDelta = ((newVolume - _channels[channel].volume) / (time / 60.0f)) / (float)kUpdatesPerSecond;
+		_channels[channel].volumeTarget = targetVolume;
+		_channels[channel].volumeDelta = ((targetVolume - _channels[channel].volume) / (time / 60.0f)) / (float)kUpdatesPerSecond;
 	}
 }
 
+// This method sets the target pan (as a percent) and the delta increment or decrement
+// to reach the target in the specified time.
 // Note: time tends to be the requested time in seconds multiplied by 60u
-void AudioMixer::adjustPan(int channel, int newPan, uint32 time) {
+// targetPan should be in [-100, 100]
+void AudioMixer::adjustPan(int channel, int targetPan, uint32 time) {
 	Common::StackLock lock(_mutex);
 
 	if (_channels[channel].isPresent) {
-		newPan = CLIP(newPan, -100, 100);
-		_channels[channel].panTarget = newPan;
-		_channels[channel].panDelta = ((newPan - _channels[channel].pan) / (time / 60.0f)) / (float)kUpdatesPerSecond;
+		targetPan = CLIP(targetPan, -100, 100);
+		_channels[channel].panTarget = targetPan;
+		_channels[channel].panDelta = ((targetPan - _channels[channel].pan) / (time / 60.0f)) / (float)kUpdatesPerSecond;
 	}
 }
 
@@ -200,7 +219,8 @@ void AudioMixer::tick() {
 			}
 
 			if (channel->sentToMixer) {
-				_vm->_mixer->setChannelVolume(channel->handle, (channel->volume * Audio::Mixer::kMaxChannelVolume) / 100); // map [0..100] to [0..kMaxChannelVolume]
+				// map volume value from [0..100] to [0..kMaxChannelVolume]
+				_vm->_mixer->setChannelVolume(channel->handle, (channel->volume * Audio::Mixer::kMaxChannelVolume) / 100);
 			}
 
 			if (channel->volume <= 0.0f) {
@@ -217,7 +237,8 @@ void AudioMixer::tick() {
 			}
 
 			if (channel->sentToMixer) {
-				_vm->_mixer->setChannelBalance(channel->handle, (channel->pan * 127) / 100); // map [-100..100] to [-127..127]
+				// map balance value from [-100..100] to [-127..127]
+				_vm->_mixer->setChannelBalance(channel->handle, (channel->pan * 127) / 100);
 			}
 		}
 
diff --git a/engines/bladerunner/audio_mixer.h b/engines/bladerunner/audio_mixer.h
index 08637557035..518271eebf1 100644
--- a/engines/bladerunner/audio_mixer.h
+++ b/engines/bladerunner/audio_mixer.h
@@ -60,12 +60,12 @@ class AudioMixer {
 		bool                loop;
 		Audio::SoundHandle  handle;
 		Audio::AudioStream *stream;
-		float               volume;
+		float               volume;       // should be in [0.0f, 100.0f]. It's percent for the Audio::Mixer::kMaxChannelVolume
 		float               volumeDelta;
-		float               volumeTarget;
-		float               pan;
+		float               volumeTarget; // should be in [0.0f, 100.0f], as for volume field.
+		float               pan;          // should be in [-100.0f, 100.0f]. It's percent for 127 (max absolute balance value)
 		float               panDelta;
-		float               panTarget;
+		float               panTarget;    // should be in [-100.0f, 100.0f], as for pan field.
 		void              (*endCallback)(int channel, void *data);
 		void               *callbackData;
 		uint32              timeStarted;
@@ -96,8 +96,8 @@ public:
 	int playMusic(Audio::RewindableAudioStream *stream, int volume, void(*endCallback)(int, void *), void *callbackData, uint32 trackDurationMs);
 	void stop(int channel, uint32 time);
 
-	void adjustVolume(int channel, int newVolume, uint32 time);
-	void adjustPan(int channel, int newPan, uint32 time);
+	void adjustVolume(int channel, int targetVolume, uint32 time);
+	void adjustPan(int channel, int targetPan, uint32 time);
 
 #if !BLADERUNNER_ORIGINAL_BUGS
 	void startAppTimerProc(int audioMixAppTimerId, uint32 intervalMillis);
diff --git a/engines/bladerunner/audio_player.cpp b/engines/bladerunner/audio_player.cpp
index f82f023fc83..6fc9d76b83d 100644
--- a/engines/bladerunner/audio_player.cpp
+++ b/engines/bladerunner/audio_player.cpp
@@ -47,10 +47,12 @@ AudioPlayer::AudioPlayer(BladeRunnerEngine *vm) {
 		_tracks[i].stream = nullptr;
 	}
 
-	// _sfxVolume here sets a percentage to be appied on the specified track volume
-	// before sending it to the audio player
-	// (setting _sfxVolume to 100 renders it indifferent)
-	_sfxVolume = BLADERUNNER_ORIGINAL_SETTINGS ? 65 : 100;
+	// _sfxVolumeFactorOriginalEngine here sets a percentage to be applied on the audio tracks' volume
+	// before sending them to the audio player.
+	// This is how the original engine set the volume via the in-game KIA volume slider controls.
+	// Setting _sfxVolumeFactorOriginalEngine to 100, for the purposes ScummVM engine, renders it indifferent,
+	// so sound volume can be controlled by ScummVM's Global Main Menu / ConfMan/ syncSoundSettings().
+	_sfxVolumeFactorOriginalEngine = BLADERUNNER_ORIGINAL_SETTINGS ? 65 : 100;
 }
 
 AudioPlayer::~AudioPlayer() {
@@ -68,20 +70,26 @@ void AudioPlayer::stopAll() {
 	}
 }
 
-void AudioPlayer::adjustVolume(int track, int volume, uint32 delaySeconds, bool overrideVolume) {
+// This method sets the target volume (as a percent) for the track
+// and the time (delaySeconds) to reach that target in.
+// volume (and actualVolume) should be in [0, 100]
+void AudioPlayer::adjustVolume(int track, int volume, uint32 delaySeconds, bool explicitVolumeAdjustment) {
 	if (track < 0 || track >= kTracks || !_tracks[track].isActive || _tracks[track].channel == -1) {
 		return;
 	}
 
 	int actualVolume = volume;
-	if (!overrideVolume) {
-		actualVolume = actualVolume * _sfxVolume / 100;
+	if (explicitVolumeAdjustment) {
+		actualVolume = (actualVolume * _sfxVolumeFactorOriginalEngine) / 100;
 	}
 
 	_tracks[track].volume = actualVolume;
 	_vm->_audioMixer->adjustVolume(_tracks[track].channel, actualVolume, 60u * delaySeconds);
 }
 
+// This method sets the target pan (as a percent) for the track
+// and the time (delaySeconds) to reach that target in.
+// pan should be in [-100, 100]
 void AudioPlayer::adjustPan(int track, int pan, uint32 delaySeconds) {
 	if (track < 0 || track >= kTracks || !_tracks[track].isActive || _tracks[track].channel == -1) {
 		return;
@@ -91,30 +99,40 @@ void AudioPlayer::adjustPan(int track, int pan, uint32 delaySeconds) {
 	_vm->_audioMixer->adjustPan(_tracks[track].channel, pan, 60u * delaySeconds);
 }
 
-// We no longer set the _sfxVolume (audio player's default volume percent) via a public method
-// It is set in AudioPlayer::AudioPlayer() constructor and keeps its value constant.
-//void AudioPlayer::setVolume(int volume) {
-//	_sfxVolume = volume;
-//}
+#if BLADERUNNER_ORIGINAL_SETTINGS
+// We no longer set the _sfxVolumeFactorOriginalEngine via a public method.
+// For the ScummVM Engine's purposes it is set in AudioPlayer::AudioPlayer() constructor and keeps its value constant.
+void AudioPlayer::setVolume(int volume) {
+	_sfxVolumeFactorOriginalEngine = volume;
+}
 
 int AudioPlayer::getVolume() const {
-	return _sfxVolume;
+	return _sfxVolumeFactorOriginalEngine;
 }
+#endif // BLADERUNNER_ORIGINAL_SETTINGS
 
 void AudioPlayer::playSample() {
 	Common::String name;
 
-	int rnd = _vm->_rnd.getRandomNumber(3);
-	if (rnd == 0) {
+	switch (_vm->_rnd.getRandomNumber(3)) {
+	case 0:
 		name = "gunmiss1.aud";
-	} else if (rnd == 1) {
+		break;
+
+	case 1:
 		name = "gunmiss2.aud";
-	} else if (rnd == 2) {
+		break;
+
+	case 2:
 		name = "gunmiss3.aud";
-	} else {
+		break;
+
+	default:
 		name = "gunmiss4.aud";
+		break;
 	}
 
+	// Sample plays with priority 100 (max)
 	playAud(name, 100, 0, 0, 100, 0);
 }
 
@@ -136,41 +154,64 @@ void AudioPlayer::mixerChannelEnded(int channel, void *data) {
 	audioPlayer->remove(channel);
 }
 
+// This method plays an audio file, at volume "volume" (as a percent, set immediately, no fade-in),
+// with audio balance starting at panStart (as a signed percent) and ending at panEnd.
+// The balance shifting happens throughout the duration of the audio track.
+// volume (and actualVolume) should be in [0, 100]
+// panStart and panEnd should be in [-100, 100]
+// priority should be in [0, 100]
+// The higher the priority, the more likely it is that this track will replace another active one
+// (with the lowest priority), if no available track slots exists.
+// Returns the index of the track slot assigned (for _tracks array) or -1 otherwise (gave up)
+// The code here is very similar to AudioMixer::play()
+// Note that this method calls AudioMixer::play() which also uses the priority value to assign a channel to the track.
+// If that fails, the new track is dropped (gave up).
+// TODO Maybe explain why we need this two step priority check (for track slot and then channel slot)
 int AudioPlayer::playAud(const Common::String &name, int volume, int panStart, int panEnd, int priority, byte flags, Audio::Mixer::SoundType type) {
-	/* Find first available track or, alternatively, the lowest priority playing track */
-	int track = -1;
-	int lowestPriority = 1000000;
-	int lowestPriorityTrack = -1;
+	debugC(6, kDebugSound, "AudioPlayer::playAud name:%s v:%d pS:%d pE:%d pr:%d type:%d", name.c_str(), volume, panStart, panEnd, priority, (int)type);
+	// Find first available track or, alternatively, the lowest priority playing track
+	int trackSlotToAssign = -1;
+	int lowestPriority = 1000000; // TODO wouldn't a lower value work as well? eg. 1000? Original uses 100 but code is a bit different
+	int lowestPriorityTrackSlot = -1;
 
+	// Find an available track slot
 	for (int i = 0; i != kTracks; ++i) {
 		if (!isActive(i)) {
 			//debug("Assigned track %i to %s", i, name.c_str());
-			track = i;
+			trackSlotToAssign = i;
 			break;
 		}
 
-		if (lowestPriorityTrack == -1 || _tracks[i].priority < lowestPriority) {
+		if (lowestPriorityTrackSlot == -1 || _tracks[i].priority < lowestPriority) {
 			lowestPriority = _tracks[i].priority;
-			lowestPriorityTrack = i;
+			lowestPriorityTrackSlot = i;
 		}
 	}
 
-	/* If there's no available track, stop the lowest priority track if it's lower than
-	 * the new priority
-	 */
-	if (track == -1 && lowestPriority < priority) {
-		//debug("Stop lowest priority  track (with lower prio: %d %d), for %s %d!", lowestPriorityTrack, lowestPriority, name.c_str(), priority);
-		stop(lowestPriorityTrack, true);
-		track = lowestPriorityTrack;
-	}
-
-	/* If there's still no available track, give up */
-	if (track == -1) {
-		//debug("No available track for %s %d - giving up", name.c_str(), priority);
-		return -1;
+	// If there's still no available track slot
+	if (trackSlotToAssign == -1) {
+		// Give up if the lowest priority track still has greater priority (lowestPriority).
+#if BLADERUNNER_ORIGINAL_BUGS
+		// NOTE If the new priority is *equal* to the existing lowestPriority,
+		// then the new audio would still not replace the old one.
+		if (priority <= lowestPriority) {
+			return -1;
+		}
+#else
+		// NOTE If the new priority is *equal* to the existing lowestPriority,
+		// then the new audio will replace the old one.
+		if (priority < lowestPriority) {
+			//debug("No available track for %s %d - giving up", name.c_str(), priority);
+			return -1;
+		}
+#endif
+		// Otherwise, stop the lowest priority track, and assign the slot to the new one.
+		//debug("Stop lowest priority  track (with lower prio: %d %d), for %s %d!", lowestPriorityTrackSlot, lowestPriority, name.c_str(), priority);
+		stop(lowestPriorityTrackSlot, true);
+		trackSlotToAssign = lowestPriorityTrackSlot;
 	}
 
-	/* Load audio resource and store in cache. Playback will happen directly from there. */
+	// Load audio resource and store in cache. Playback will happen directly from there.
 	int32 hash = MIXArchive::getHash(name);
 	if (!_vm->_audioCache->findByHash(hash)) {
 		Common::SeekableReadStream *r = _vm->getResourceStream(_vm->_enhancedEdition ? ("audio/" + name) : name);
@@ -195,20 +236,18 @@ int AudioPlayer::playAud(const Common::String &name, int volume, int panStart, i
 
 	int actualVolume = volume;
 	if (!(flags & kAudioPlayerOverrideVolume)) {
-		actualVolume = _sfxVolume * volume / 100;
+		actualVolume = (actualVolume * _sfxVolumeFactorOriginalEngine) / 100;
 	}
 
-	int channel = _vm->_audioMixer->play(
-		type,
-		audioStream,
-		priority,
-		flags & kAudioPlayerLoop,
-		actualVolume,
-		panStart,
-		mixerChannelEnded,
-		this,
-		audioStream->getLength()
-		);
+	int channel = _vm->_audioMixer->play(type,
+	                                     audioStream,
+	                                     priority,
+	                                     flags & kAudioPlayerLoop,
+	                                     actualVolume,
+	                                     panStart,
+	                                     mixerChannelEnded,
+	                                     this,
+	                                     audioStream->getLength());
 
 	if (channel == -1) {
 		delete audioStream;
@@ -220,13 +259,13 @@ int AudioPlayer::playAud(const Common::String &name, int volume, int panStart, i
 		_vm->_audioMixer->adjustPan(channel, panEnd, (60u * audioStream->getLength()) / 1000u);
 	}
 
-	_tracks[track].isActive = true;
-	_tracks[track].channel  = channel;
-	_tracks[track].priority = priority;
-	_tracks[track].volume   = actualVolume;
-	_tracks[track].stream   = audioStream;
+	_tracks[trackSlotToAssign].isActive = true;
+	_tracks[trackSlotToAssign].channel  = channel;
+	_tracks[trackSlotToAssign].priority = priority;
+	_tracks[trackSlotToAssign].volume   = actualVolume;
+	_tracks[trackSlotToAssign].stream   = audioStream;
 
-	return track;
+	return trackSlotToAssign;
 }
 
 bool AudioPlayer::isActive(int track) const {
diff --git a/engines/bladerunner/audio_player.h b/engines/bladerunner/audio_player.h
index b0ec5ad6d54..7ae240c74a4 100644
--- a/engines/bladerunner/audio_player.h
+++ b/engines/bladerunner/audio_player.h
@@ -29,7 +29,7 @@
 #include "audio/audiostream.h"
 #include "audio/mixer.h"
 
-#include "bladerunner/bladerunner.h" // For BLADERUNNER_ORIGINAL_BUGS symbol
+#include "bladerunner/bladerunner.h" // For BLADERUNNER_ORIGINAL_BUGS and BLADERUNNER_ORIGINAL_SETTINGS symbols
 
 namespace BladeRunner {
 
@@ -56,8 +56,8 @@ class AudioPlayer {
 		bool                isActive;
 		int                 channel;
 		int                 priority;
-		int                 volume;
-		int                 pan;
+		int                 volume;   // should be in [0, 100]
+		int                 pan;      // should be in [-100, 100]
 		AudStream          *stream;
 	};
 
@@ -65,7 +65,7 @@ class AudioPlayer {
 
 	Common::Mutex _mutex;
 	Track         _tracks[kTracks];
-	int           _sfxVolume;
+	int           _sfxVolumeFactorOriginalEngine; // should be in [0, 100] - Unused in ScummVM Engine, used in original engine
 
 public:
 	AudioPlayer(BladeRunnerEngine *vm);
@@ -76,11 +76,13 @@ public:
 	uint32 getLength(int track) const;
 	void stop(int track, bool immediately);
 	void stopAll();
-	void adjustVolume(int track, int volume, uint32 delaySeconds, bool overrideVolume);
+	void adjustVolume(int track, int volume, uint32 delaySeconds, bool explicitVolumeAdjustment);
 	void adjustPan(int track, int pan, uint32 delaySeconds);
 
-//	void setVolume(int volume);
+#if BLADERUNNER_ORIGINAL_SETTINGS
+	void setVolume(int volume);
 	int getVolume() const;
+#endif // BLADERUNNER_ORIGINAL_SETTINGS
 	void playSample();
 
 private:
diff --git a/engines/bladerunner/audio_speech.cpp b/engines/bladerunner/audio_speech.cpp
index 6840b6c0629..3015bcb6cb3 100644
--- a/engines/bladerunner/audio_speech.cpp
+++ b/engines/bladerunner/audio_speech.cpp
@@ -48,10 +48,12 @@ void AudioSpeech::mixerChannelEnded(int channel, void *data) {
 
 AudioSpeech::AudioSpeech(BladeRunnerEngine *vm) {
 	_vm = vm;
-	// _speechVolume here sets a percentage to be appied on the specified voice cue volume
-	// before sending it to the audio player
-	// (setting _speechVolume to 100 renders it indifferent)
-	_speechVolume = BLADERUNNER_ORIGINAL_SETTINGS ? 50 : 100;
+	// _speechVolumeFactorOriginalEngine here sets a percentage to be applied on the voice cues' volume
+	// before sending them to the audio player.
+	// This is how the original engine set the volume via the in-game KIA volume slider controls.
+	// Setting _speechVolumeFactorOriginalEngine to 100, for the purposes ScummVM engine, renders it indifferent,
+	// so sound volume can be controlled by ScummVM's Global Main Menu / ConfMan/ syncSoundSettings().
+	_speechVolumeFactorOriginalEngine = BLADERUNNER_ORIGINAL_SETTINGS ? 50 : 100;
 	_isActive = false;
 	_data = new byte[kBufferSize];
 	_channel = -1;
@@ -66,6 +68,7 @@ AudioSpeech::~AudioSpeech() {
 	delete[] _data;
 }
 
+// pan should be in [-100, 100]
 bool AudioSpeech::playSpeech(const Common::String &name, int pan) {
 	if (isPlaying()) {
 		stopSpeech();
@@ -98,16 +101,19 @@ bool AudioSpeech::playSpeech(const Common::String &name, int pan) {
 
 	AudStream *audioStream = new AudStream(_data, _vm->_shortyMode ? 33000 : -1);
 
-	_channel = _vm->_audioMixer->play(
-		Audio::Mixer::kSpeechSoundType,
-		audioStream,
-		100,
-		false,
-		_speechVolume,
-		pan,
-		mixerChannelEnded,
-		this,
-		audioStream->getLength());
+	// Speech plays here with priority 100 (max)
+	// Using directly _speechVolumeFactorOriginalEngine as the volume for audioMixer::play(),
+	// which for the ScummVM engine is 100, so speech volume will be only determined
+	// by the ScummVM volume for the speech sound type.
+	_channel = _vm->_audioMixer->play(Audio::Mixer::kSpeechSoundType,
+	                                  audioStream,
+	                                  100,
+	                                  false,
+	                                  _speechVolumeFactorOriginalEngine,
+	                                  pan,
+	                                  mixerChannelEnded,
+	                                  this,
+	                                  audioStream->getLength());
 
 	_isActive = true;
 
@@ -128,21 +134,26 @@ bool AudioSpeech::isPlaying() const {
 	return _isActive;
 }
 
+// volume should be in [0, 100]
+// priority should be in [0, 100]
+// pan is calculated based on actor's position with Actor::soundPan()
 bool AudioSpeech::playSpeechLine(int actorId, int sentenceId, int volume, int a4, int priority) {
 	int pan = _vm->_actors[actorId]->soundPan();
 	Common::String name = Common::String::format("%02d-%04d%s.AUD", actorId, sentenceId, _vm->_languageCode.c_str());
-	return _vm->_audioPlayer->playAud(name, _speechVolume * volume / 100, pan, pan, priority, kAudioPlayerOverrideVolume, Audio::Mixer::kSpeechSoundType);
+	return _vm->_audioPlayer->playAud(name, (volume * _speechVolumeFactorOriginalEngine) / 100, pan, pan, priority, kAudioPlayerOverrideVolume, Audio::Mixer::kSpeechSoundType);
 }
 
-// We no longer set the _speechVolume (speech default volume percent) via a public method
-// It is set in AudioSpeech::AudioSpeech() constructor and keeps its value constant.
-//void AudioSpeech::setVolume(int volume) {
-//	_speechVolume = volume;
-//}
+#if BLADERUNNER_ORIGINAL_SETTINGS
+// We no longer set the _speechVolumeFactorOriginalEngine via a public method.
+// For the ScummVM Engine's purposes it is set in AudioSpeech::AudioSpeech() constructor and keeps its value constant.
+void AudioSpeech::setVolume(int volume) {
+	_speechVolumeFactorOriginalEngine = volume;
+}
 
 int AudioSpeech::getVolume() const {
-	return _speechVolume;
+	return _speechVolumeFactorOriginalEngine;
 }
+#endif // BLADERUNNER_ORIGINAL_SETTINGS
 
 void AudioSpeech::playSample() {
 #if BLADERUNNER_ORIGINAL_BUGS
diff --git a/engines/bladerunner/audio_speech.h b/engines/bladerunner/audio_speech.h
index 0f2904d3880..77d033104d7 100644
--- a/engines/bladerunner/audio_speech.h
+++ b/engines/bladerunner/audio_speech.h
@@ -22,6 +22,8 @@
 #ifndef BLADERUNNER_AUDIO_SPEECH_H
 #define BLADERUNNER_AUDIO_SPEECH_H
 
+#include "bladerunner/bladerunner.h" // For BLADERUNNER_ORIGINAL_SETTINGS symbol
+
 #include "common/str.h"
 #include "common/types.h"
 
@@ -35,7 +37,7 @@ class AudioSpeech {
 
 	BladeRunnerEngine *_vm;
 
-	int   _speechVolume;
+	int   _speechVolumeFactorOriginalEngine;  // should be in [0, 100] - Unused in ScummVM Engine, used in original engine
 	bool  _isActive;
 	int   _channel;
 	byte *_data;
@@ -50,8 +52,10 @@ public:
 
 	bool playSpeechLine(int actorId, int sentenceId, int volume, int a4, int priority);
 
-//	void setVolume(int volume);
+#if BLADERUNNER_ORIGINAL_SETTINGS
+	void setVolume(int volume);
 	int getVolume() const;
+#endif // BLADERUNNER_ORIGINAL_SETTINGS
 	void playSample();
 
 private:
diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h
index 30ccf49521b..d76f1c7ac29 100644
--- a/engines/bladerunner/bladerunner.h
+++ b/engines/bladerunner/bladerunner.h
@@ -56,7 +56,8 @@ struct ADGameDescription;
 namespace BladeRunner {
 
 enum DebugLevels {
-	kDebugScript = 1 << 0
+	kDebugScript = 1 << 0,
+	kDebugSound = 1 << 1
 };
 
 class Actor;
diff --git a/engines/bladerunner/detection.cpp b/engines/bladerunner/detection.cpp
index 7326616c88e..26b3b06fbed 100644
--- a/engines/bladerunner/detection.cpp
+++ b/engines/bladerunner/detection.cpp
@@ -34,6 +34,7 @@
 
 static const DebugChannelDef debugFlagList[] = {
 	{BladeRunner::kDebugScript, "Script", "Debug the scripts"},
+	{BladeRunner::kDebugSound, "Sound", "Debug the sound"},
 	DEBUG_CHANNEL_END
 };
 
diff --git a/engines/bladerunner/music.cpp b/engines/bladerunner/music.cpp
index 83db62dee1a..4719ea3ec35 100644
--- a/engines/bladerunner/music.cpp
+++ b/engines/bladerunner/music.cpp
@@ -33,10 +33,12 @@ namespace BladeRunner {
 
 Music::Music(BladeRunnerEngine *vm) {
 	_vm = vm;
-	// _musicVolume here sets a percentage to be appied on the specified track volume
-	// before sending it to the audio player
-	// (setting _musicVolume to 100 renders it indifferent)
-	_musicVolume = BLADERUNNER_ORIGINAL_SETTINGS ? 65 : 100;
+	// _musicVolumeFactorOriginalEngine here sets a percentage to be applied on the music tracks' volume
+	// before sending them to the audio player.
+	// This is how the original engine set the volume via the in-game KIA volume slider controls.
+	// Setting _musicVolumeFactorOriginalEngine to 100, for the purposes ScummVM engine, renders it indifferent,
+	// so sound volume can be controlled by ScummVM's Global Main Menu / ConfMan/ syncSoundSettings().
+	_musicVolumeFactorOriginalEngine = BLADERUNNER_ORIGINAL_SETTINGS ? 65 : 100;
 	reset();
 }
 
@@ -69,14 +71,19 @@ void Music::reset() {
 	_stream = nullptr;
 }
 
+// volume should be in [0, 100]
+// pan should be in [-100, 100]
+// A negative (typically -1) value for timePlaySeconds, means "play the whole music track".
 bool Music::play(const Common::String &trackName, int volume, int pan, int32 timeFadeInSeconds, int32 timePlaySeconds, int loop, int32 timeFadeOutSeconds) {
 	//Common::StackLock lock(_mutex);
 
-	if (_musicVolume <= 0) {
+	// TODO Does this mean that when music volume slider is at mute (0) (in the original engine),
+	// the music track would *not* be "played silently" and would not be loaded nor queued at all?
+	if (_musicVolumeFactorOriginalEngine <= 0) {
 		return false;
 	}
 
-	int volumeAdjusted = volume * _musicVolume / 100;
+	int volumeAdjusted = (volume * _musicVolumeFactorOriginalEngine) / 100; //volumeAdjusted will be in [0, 100]
 	int volumeStart = volumeAdjusted;
 	if (timeFadeInSeconds > 0) {
 		volumeStart = 1;
@@ -89,15 +96,16 @@ bool Music::play(const Common::String &trackName, int volume, int pan, int32 tim
 	//       However, if a "next" track already exists,
 	//       then stop the _current track after 2 seconds (force stop current playing track)
 	//       Also the previous "next" track still gets replaced by the new requested one.
-	// 	     This can be best test at Animoid Row, Hawker's Circle moving from Izo's Pawn Shop to the Bar.
+	// 	     This can be best tested at Animoid Row, within Hawker's Circle,
+	// 	     moving from Izo's Pawn Shop to the Bar.
 	//    if the requested track is the same as the currently playing,
 	//       update the loop int value of the _current to the new one
 	//       and adjust its fadeIn and balance/pan
-	//    In these both cases above, the _current track is not (yet) changed.
+	//    In both of the above cases, the _current track is not (yet) changed.
 	if (isPlaying()) {
 		if (!_current.name.equalsIgnoreCase(trackName)) {
 			_next.name = trackName;
-			_next.volume = volume; // Don't store the adjustedVolume - This is a "target" value for the volume
+			_next.volume = volume; // Don't store the adjusted volume - This is a "target" volume (before any adjustments from volume sliders or special mode like VK)
 			_next.pan = pan;       // This is a "target" value for the pan (balance)
 			_next.timeFadeInSeconds = timeFadeInSeconds;
 			_next.timePlaySeconds = timePlaySeconds;
@@ -112,7 +120,11 @@ bool Music::play(const Common::String &trackName, int volume, int pan, int32 tim
 			if (timeFadeInSeconds < 0) {
 				timeFadeInSeconds = 0;
 			}
+#if BLADERUNNER_ORIGINAL_BUGS
 			adjustVolume(volumeAdjusted, timeFadeInSeconds);
+#else
+			adjustVolume(volume, timeFadeInSeconds);
+#endif // BLADERUNNER_ORIGINAL_BUGS
 			adjustPan(pan, timeFadeInSeconds);
 		}
 		return true;
@@ -153,7 +165,11 @@ bool Music::play(const Common::String &trackName, int volume, int pan, int32 tim
 		return false;
 	}
 	if (timeFadeInSeconds > 0) {
+#if BLADERUNNER_ORIGINAL_BUGS
 		adjustVolume(volumeAdjusted, timeFadeInSeconds);
+#else
+		adjustVolume(volume, timeFadeInSeconds);
+#endif // BLADERUNNER_ORIGINAL_BUGS
 	}
 	_current.name = trackName;
 
@@ -177,7 +193,7 @@ bool Music::play(const Common::String &trackName, int volume, int pan, int32 tim
 #endif //BLADERUNNER_ORIGINAL_BUGS
 	}
 	_isPlaying = true;
-	_current.volume = volume; // Don't store the adjustedVolume - This is a "target" value for the volume
+	_current.volume = volume; // Don't store the adjusted volume - This is a "target" volume (before any adjustments from volume sliders or special mode like VK)
 	_current.pan = pan;       // This is a "target" value for the pan (balance)
 	_current.timeFadeInSeconds = timeFadeInSeconds;
 	_current.timePlaySeconds = timePlaySeconds;
@@ -207,11 +223,19 @@ void Music::stop(uint32 delaySeconds) {
 	_vm->_audioMixer->stop(_channel, 60u * delaySeconds);
 }
 
+// adjust() is a public method, and note that it accepts special values for its arguments
+// volume should be in [0, 100], with "-1" being a special value for skipping volume adjustment
+// pan should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
 void Music::adjust(int volume, int pan, uint32 delaySeconds) {
+	// value -1 for volume means "do not adjust volume for this music track (while it's playing)"
 	if (volume != -1) {
-		adjustVolume(_musicVolume * volume/ 100, delaySeconds);
+#if BLADERUNNER_ORIGINAL_BUGS
+		adjustVolume((volume * _musicVolumeFactorOriginalEngine)/ 100, delaySeconds);
+#else
+		adjustVolume(volume, delaySeconds);
+#endif // BLADERUNNER_ORIGINAL_BUGS
 	}
-	// -101 is used as a special value to skip adjusting pan
+	// value -101 for pan means "do not adjust pan for this music track (while it's playing)"
 	if (pan != -101) {
 		adjustPan(pan, delaySeconds);
 	}
@@ -221,18 +245,25 @@ bool Music::isPlaying() {
 	return _channel >= 0 && _isPlaying;
 }
 
+// TODO Evaluate if for ScummVM we can avoid using and modifying _musicVolumeFactorOriginalEngine altogether.
+// While we no longer use the original engine's mechanism to set the music tracks' volume
+// with the Music::setVolume() public method (when using the in-game KIA volume slider),
+// we do use this method as did the original engine to temporarily set the volume levels
+// in VK mode.
+// volume should be in [0, 100]. If volume < 0 then it's treated as 0, and the track is stopped with 2 seconds fade out.
 void Music::setVolume(int volume) {
-	_musicVolume = volume;
-	if (volume <= 0) {
+	// Just don't set the _musicVolumeFactorOriginalEngine to a negative value
+	_musicVolumeFactorOriginalEngine = (volume < 0) ? 0 : volume;
+	if (_musicVolumeFactorOriginalEngine == 0) {
 		stop(2u);
 	} else if (isPlaying()) {
 		// delay is 2 seconds (multiplied by 60u as expected by AudioMixer::adjustVolume())
-		_vm->_audioMixer->adjustVolume(_channel, _musicVolume * _current.volume / 100, 120u);
+		_vm->_audioMixer->adjustVolume(_channel, (_current.volume * _musicVolumeFactorOriginalEngine) / 100, 120u);
 	}
 }
 
-int Music::getVolume() {
-	return _musicVolume;
+int Music::getVolume() const {
+	return _musicVolumeFactorOriginalEngine;
 }
 
 void Music::playSample() {
@@ -303,15 +334,33 @@ void Music::load(SaveFileReadStream &f) {
 	}
 }
 
+// volume should be in [0, 100]
+#if BLADERUNNER_ORIGINAL_BUGS
+void Music::adjustVolume(int adjustedVolume, uint32 delaySeconds) {
+	// adjustVolume() takes an "adjusted volume" value as an argument
+	// We don't store that as the target _current.volume. Music::play() stores the proper value
+	// However, adjustVolume() is called from Music::play() but also from Music::adjust() (called by ScriptBase::Music_Adjust()).
+	if (_channel >= 0) {
+		_vm->_audioMixer->adjustVolume(_channel, adjustedVolume, 60u * delaySeconds);
+	}
+}
+#else
 void Music::adjustVolume(int volume, uint32 delaySeconds) {
-	// adjustVolume takes an "adjusted volume" value as an argument
-	// We don't store that as target _current.volume - play() stores the proper value
+	// adjustVolume() takes a "target" volume value as an argument
+	// We store the new volume value as the _current.volume (which is a target volume).
+	// adjustVolume() is called from Music::play() but also from Music::adjust() (called by ScriptBase::Music_Adjust()).
+	_current.volume = volume;
 	if (_channel >= 0) {
-		_vm->_audioMixer->adjustVolume(_channel, volume, 60u * delaySeconds);
+		_vm->_audioMixer->adjustVolume(_channel, (volume * _musicVolumeFactorOriginalEngine) / 100, 60u * delaySeconds);
 	}
 }
+#endif // BLADERUNNER_ORIGINAL_BUGS
+
 
+// pan should be in [-100, 100]
 void Music::adjustPan(int pan, uint32 delaySeconds) {
+	// adjustPan() is called from Music::play() but also from Music::adjust().
+	// We store the new pan value here as the _current.pan (which is a target pan).
 	_current.pan = pan;
 	if (_channel >= 0) {
 		_vm->_audioMixer->adjustPan(_channel, pan, 60u * delaySeconds);
diff --git a/engines/bladerunner/music.h b/engines/bladerunner/music.h
index 8ea6c0bdf66..c8532c9ba5c 100644
--- a/engines/bladerunner/music.h
+++ b/engines/bladerunner/music.h
@@ -25,7 +25,7 @@
 #include "common/mutex.h"
 #include "common/str.h"
 
-#include "bladerunner/bladerunner.h" // For BLADERUNNER_ORIGINAL_BUGS symbol
+#include "bladerunner/bladerunner.h" // For BLADERUNNER_ORIGINAL_BUGS and BLADERUNNER_ORIGINAL_SETTINGS symbols
 
 namespace BladeRunner {
 
@@ -37,8 +37,8 @@ class SaveFileWriteStream;
 class Music {
 	struct Track {
 		Common::String name;
-		int            volume;             // A value between 0 and 100 - It is the set volume for the track regardless of fadeIn and fadeOut transitions
-		int            pan;                // A value between -100 (left) and 100 (right) (0 is center) - It is the set pan/balance for the track regardless of any ongoing adjustments
+		int            volume;             // A value in [0, 100] - It is the set (target) volume for the track regardless of fadeIn and fadeOut transitions
+		int            pan;                // A value in [-100, 100]. -100 is left, 100 is right and 0 is center - It is the set (target) pan/balance for the track regardless of any ongoing adjustments
 		int32          timeFadeInSeconds;  // how long will it take for the track to reach target volume (in seconds)
 		int32          timePlaySeconds;    // how long the track will play before starting fading out (in seconds) - uses timeFadeOutSeconds for fadeout
 		                                   // -1: Special value for playing the whole track
@@ -49,7 +49,7 @@ class Music {
 	BladeRunnerEngine *_vm;
 
 	Common::Mutex _mutex;
-	int           _musicVolume;
+	int           _musicVolumeFactorOriginalEngine; // should be in [0, 100]
 	int           _channel;
 	bool          _isNextPresent;
 	bool          _isPlaying;
@@ -69,7 +69,7 @@ public:
 	bool isPlaying();
 
 	void setVolume(int volume);
-	int getVolume();
+	int getVolume() const;
 	void playSample();
 
 	void save(SaveFileWriteStream &f);
@@ -84,7 +84,11 @@ public:
 
 private:
 	void reset();
+#if BLADERUNNER_ORIGINAL_BUGS
+	void adjustVolume(int adjustedVolume, uint32 delaySeconds);
+#else
 	void adjustVolume(int volume, uint32 delaySeconds);
+#endif // BLADERUNNER_ORIGINAL_BUGS
 	void adjustPan(int pan, uint32 delaySeconds);
 
 	void ended();
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index 9dd4775c859..ee05d8b630a 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -1102,11 +1102,16 @@ int ScriptBase::Random_Query(int min, int max) {
 	return _vm->_rnd.getRandomNumberRng(min, max);
 }
 
+// volume should be in [0, 100]
+// panStart, panEnd should be in [-100, 100]
+// priority should be in [0, 100]
 void ScriptBase::Sound_Play(int id, int volume, int panStart, int panEnd, int priority) {
 	debugC(6, kDebugScript, "Sound_Play(%d, %d, %d, %d, %d)", id, volume, panStart, panEnd, priority);
 	_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(id), volume, panStart, panEnd, priority);
 }
 
+// volume should be in [0, 100]
+// priority should be in [0, 100]
 void ScriptBase::Sound_Play_Speech_Line(int actorId, int sentenceId, int volume, int a4, int priority) {
 	debugC(kDebugScript, "Sound_Play_Speech_Line(%d, %d, %d, %d, %d)", actorId, sentenceId, volume, a4, priority);
 	_vm->_audioSpeech->playSpeechLine(actorId, sentenceId, volume, a4, priority);
@@ -1177,11 +1182,16 @@ void ScriptBase::Footstep_Sound_Override_Off() {
 	_vm->_scene->_set->resetFoodstepSoundOverride();
 }
 
+// volume should be in [0, 100]
+// pan should be in [-100, 100]
+// A negative (typically -1) value for timePlaySeconds, means "play the whole music track"
 bool ScriptBase::Music_Play(int musicId, int volume, int pan, int32 timeFadeInSeconds, int32 timePlaySeconds, int loop, int32 timeFadeOutSeconds) {
 	debugC(kDebugScript, "Music_Play(%d, %d, %d, %d, %d, %d, %d)", musicId, volume, pan, timeFadeInSeconds, timePlaySeconds, loop, timeFadeOutSeconds);
 	return _vm->_music->play(_vm->_gameInfo->getMusicTrack(musicId), volume, pan, timeFadeInSeconds, timePlaySeconds, loop, timeFadeOutSeconds);
 }
 
+// volume should be in [0, 100], with "-1" being a special value for skipping volume adjustment 
+// pan should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
 void ScriptBase::Music_Adjust(int volume, int pan, uint32 delaySeconds) {
 	debugC(kDebugScript, "Music_Adjust(%d, %d, %u)", volume, pan, delaySeconds);
 	_vm->_music->adjust(volume, pan, delaySeconds);
@@ -1228,6 +1238,10 @@ void ScriptBase::Outtake_Play(int id, int noLocalization, int container) {
 	_vm->outtakePlay(id, noLocalization, container);
 }
 
+// volumeMin, volumeMax should be in [0, 100]
+// panStartMin, panStartMax should be in [-100, 100]
+// panEndMin, panEndMax should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
+// priority should be in [0, 100]
 void ScriptBase::Ambient_Sounds_Add_Sound(int sfxId, uint32 delayMinSeconds, uint32 delayMaxSeconds, int volumeMin, int volumeMax, int panStartMin, int panStartMax, int panEndMin, int panEndMax, int priority, int unk) {
 	debugC(kDebugScript, "Ambient_Sounds_Add_Sound(%d, %u, %u, %d, %d, %d, %d, %d, %d, %d, %d)", sfxId, delayMinSeconds, delayMaxSeconds, volumeMin, volumeMax, panStartMin, panStartMax, panEndMin, panEndMax, priority, unk);
 	_vm->_ambientSounds->addSound(sfxId, delayMinSeconds, delayMaxSeconds, volumeMin, volumeMax, panStartMin, panStartMax, panEndMin, panEndMax, priority, unk);
@@ -1238,6 +1252,10 @@ void  ScriptBase::Ambient_Sounds_Remove_Sound(int sfxId, bool stopPlaying) {
 	_vm->_ambientSounds->removeNonLoopingSound(sfxId,  stopPlaying);
 }
 
+// volumeMin, volumeMax should be in [0, 100]
+// panStartMin, panStartMax should be in [-100, 100]
+// panEndMin, panEndMax should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
+// priority should be in [0, 100]
 void ScriptBase::Ambient_Sounds_Add_Speech_Sound(int actorId, int sentenceId, uint32 delayMinSeconds, uint32 delayMaxSeconds, int volumeMin, int volumeMax, int panStartMin, int panStartMax, int panEndMin, int panEndMax, int priority, int unk) {
 	debugC(kDebugScript, "Ambient_Sounds_Add_Speech_Sound(%d, %d, %u, %u, %d, %d, %d, %d, %d, %d, %d, %d)", actorId, sentenceId, delayMinSeconds, delayMaxSeconds, volumeMin, volumeMax, panStartMin, panStartMax, panEndMin, panEndMax, priority, unk);
 	_vm->_ambientSounds->addSpeech(actorId, sentenceId, delayMinSeconds, delayMaxSeconds, volumeMin, volumeMax, panStartMin, panStartMax, panEndMin, panEndMax, priority, unk);
@@ -1245,11 +1263,18 @@ void ScriptBase::Ambient_Sounds_Add_Speech_Sound(int actorId, int sentenceId, ui
 
 // ScriptBase::Ambient_Sounds_Remove_Speech_Sound
 
+
+// volume should be in [0, 100]
+// panStart, panEnd should be in [-100, 100]
+// priority should be in [0, 100]
 void ScriptBase::Ambient_Sounds_Play_Sound(int sfxId, int volume, int panStart, int panEnd, int priority) {
 	debugC(kDebugScript, "Ambient_Sounds_Play_Sound(%d, %d, %d, %d, %d)", sfxId, volume, panStart, panEnd, priority);
 	_vm->_ambientSounds->playSound(sfxId, volume, panStart, panEnd, priority);
 }
 
+// volume should be in [0, 100]
+// panStart, panEnd should be in [-100, 100]
+// priority should be in [0, 100]
 void ScriptBase::Ambient_Sounds_Play_Speech_Sound(int actorId, int sentenceId, int volume, int panStart, int panEnd, int priority) {
 	debugC(kDebugScript, "Ambient_Sounds_Play_Speech_Sound(%d, %d, %d, %d, %d, %d)", actorId, sentenceId, volume, panStart, panEnd, priority);
 	_vm->_ambientSounds->playSpeech(actorId, sentenceId, volume, panStart, panEnd, priority);
@@ -1260,11 +1285,15 @@ void ScriptBase::Ambient_Sounds_Remove_All_Non_Looping_Sounds(bool stopPlaying)
 	_vm->_ambientSounds->removeAllNonLoopingSounds(stopPlaying);
 }
 
+// volume should be in [0, 100]
+// pan should be in [-100, 100]
 void ScriptBase::Ambient_Sounds_Add_Looping_Sound(int sfxId, int volume, int pan, uint32 delaySeconds) {
 	debugC(kDebugScript, "Ambient_Sounds_Add_Looping_Sound(%d, %d, %d, %u)", sfxId, volume, pan, delaySeconds);
 	_vm->_ambientSounds->addLoopingSound(sfxId, volume, pan, delaySeconds);
 }
 
+// volume should be in [0, 100], with "-1" being a special value for skipping volume adjustment 
+// pan should be in [-100, 100], with "-101" being a special value for skipping pan (balance) adjustment
 void ScriptBase::Ambient_Sounds_Adjust_Looping_Sound(int sfxId, int volume, int pan, uint32 delaySeconds) {
 	debugC(kDebugScript, "Ambient_Sounds_Adjust_Looping_Sound(%d, %d, %d, %u)", sfxId, volume, pan, delaySeconds);
 	_vm->_ambientSounds->adjustLoopingSound(sfxId, volume, pan, delaySeconds);
diff --git a/engines/bladerunner/ui/end_credits.cpp b/engines/bladerunner/ui/end_credits.cpp
index 040e592ec98..edee3695086 100644
--- a/engines/bladerunner/ui/end_credits.cpp
+++ b/engines/bladerunner/ui/end_credits.cpp
@@ -178,7 +178,6 @@ void EndCredits::show() {
 	_vm->_ambientSounds->removeAllLoopingSounds(4u);
 	_vm->_audioSpeech->stopSpeech();
 
-	// ASDF volume is 100 here (correct it should be from 0..100)
 	_vm->_music->play(_vm->_gameInfo->getMusicTrack(kMusicCredits), 100, 0, 2, -1, kMusicLoopPlayOnce, 3);
 
 	Font *fontBig = Font::load(_vm, "TAHOMA24.FON", 1, true);
diff --git a/engines/bladerunner/ui/esper.cpp b/engines/bladerunner/ui/esper.cpp
index 723f19adf58..b76e48373e7 100644
--- a/engines/bladerunner/ui/esper.cpp
+++ b/engines/bladerunner/ui/esper.cpp
@@ -87,9 +87,11 @@ void ESPER::open(Graphics::Surface *surface) {
 
 	_vm->_time->pause();
 
-	_ambientVolume = _vm->_ambientSounds->getVolume();
-	_vm->_ambientSounds->setVolume(_ambientVolume / 2);
-
+	// NOTE It's probably intentional that music level is not adjusted when entering ESPER mode,
+	// since it is possible to use ESPER in McCoy's apartment while the moody Blade Runner Blues is playing,
+	// and it would not be desirable to have that one's volume lowered further.
+	_ambientVolumeFactorOutsideEsper = _vm->_ambientSounds->getVolume();
+	_vm->_ambientSounds->setVolume(_ambientVolumeFactorOutsideEsper / 2);
 	reset();
 
 	if (!_vm->openArchive("MODE.MIX")) {
@@ -148,7 +150,7 @@ void ESPER::close() {
 
 	_vm->_time->resume();
 
-	_vm->_ambientSounds->setVolume(_ambientVolume);
+	_vm->_ambientSounds->setVolume(_ambientVolumeFactorOutsideEsper);
 	_vm->_scene->resume();
 
 	reset();
@@ -514,6 +516,7 @@ void ESPER::wait(uint32 timeout) {
 	}
 }
 
+// volume should be in [0, 100]
 void ESPER::playSound(int soundId, int volume) {
 	if (_soundId1 == -1) {
 		_soundId1 = soundId;
diff --git a/engines/bladerunner/ui/esper.h b/engines/bladerunner/ui/esper.h
index 5b8f2bf340f..a2287581f2a 100644
--- a/engines/bladerunner/ui/esper.h
+++ b/engines/bladerunner/ui/esper.h
@@ -177,12 +177,12 @@ class ESPER {
 	uint32 _timeScrollNextStart;
 
 	int _soundId1;
-	int _volume1;
+	int _volume1;  // should be in [0, 100]
 	int _soundId2;
-	int _volume2;
+	int _volume2;  // should be in [0, 100]
 	int _soundId3;
-	int _volume3;
-	int _ambientVolume;
+	int _volume3;  // should be in [0, 100]
+	int _ambientVolumeFactorOutsideEsper;
 
 public:
 	ESPER(BladeRunnerEngine *vm);
diff --git a/engines/bladerunner/ui/vk.cpp b/engines/bladerunner/ui/vk.cpp
index 3a6122fab46..4bb2f0f1117 100644
--- a/engines/bladerunner/ui/vk.cpp
+++ b/engines/bladerunner/ui/vk.cpp
@@ -75,12 +75,15 @@ void VK::open(int actorId, int calibrationRatio) {
 		}
 	}
 
-	_volumeAmbient = _vm->_ambientSounds->getVolume();
-	_volumeMusic   = _vm->_music->getVolume();
+	_ambientVolumeFactorOutsideVK = _vm->_ambientSounds->getVolume();
+	_musicVolumeFactorOutsideVK = _vm->_music->getVolume();
+	// Original engine sets volume to 1 for ambient and music
+	_vm->_ambientSounds->setVolume(1);
+	_vm->_music->setVolume(1);
 
 	_actorId          = actorId;
 	_calibrationRatio = calibrationRatio;
-	_calibration      = 0;
+	_calibration      = 0; // TODO Original uses a float (0.0) var for calibration. Does this make any difference?
 
 	_buttons = new UIImagePicker(_vm, 8);
 
@@ -175,8 +178,9 @@ void VK::close() {
 	_shapes->unload();
 
 	_vm->closeArchive("MODE.MIX");
-	_vm->_music->setVolume(_volumeMusic);
-	_vm->_ambientSounds->setVolume(_volumeAmbient);
+
+	_vm->_music->setVolume(_musicVolumeFactorOutsideVK);
+	_vm->_ambientSounds->setVolume(_ambientVolumeFactorOutsideVK);
 
 	_vm->_time->resume();
 	_vm->_scene->resume();
@@ -442,8 +446,8 @@ void VK::reset() {
 
 	_shapes->unload();
 
-	_volumeAmbient = 0;
-	_volumeMusic   = 0;
+	_ambientVolumeFactorOutsideVK = 0;
+	_musicVolumeFactorOutsideVK   = 0;
 
 	_calibrationRatio   = 0;
 	_calibrationCounter = 0;
diff --git a/engines/bladerunner/ui/vk.h b/engines/bladerunner/ui/vk.h
index ea847defeb9..503cec61ada 100644
--- a/engines/bladerunner/ui/vk.h
+++ b/engines/bladerunner/ui/vk.h
@@ -66,8 +66,8 @@ class VK {
 
 	Common::Array<Common::Array<Question> > _questions;
 
-	int _volumeAmbient;
-	int _volumeMusic;
+	int _ambientVolumeFactorOutsideVK; // should be in [0, 100]
+	int _musicVolumeFactorOutsideVK;   // should be in [0, 100]
 	int _soundTrackId1;
 	int _soundTrackId2;
 	int _soundTrackId3;
@@ -133,7 +133,7 @@ public:
 
 	void tick();
 
-	void resume();
+//	void resume();
 
 	void handleMouseDown(int mouseX, int mouseY, bool mainButton);
 	void handleMouseUp(int mouseX, int mouseY, bool mainButton);
diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp
index b7550d24b65..53981775492 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -24,6 +24,9 @@
 #include "bladerunner/bladerunner.h"
 #include "bladerunner/time.h"
 #include "bladerunner/audio_player.h"
+#if BLADERUNNER_ORIGINAL_SETTINGS
+#include "bladerunner/audio_speech.h"
+#endif
 
 #include "audio/decoders/raw.h"
 
@@ -234,7 +237,15 @@ int VQAPlayer::update(bool forceDraw, bool advanceFrame, bool useTime, Graphics:
 					// Audio stream starts playing, consuming queued "audio frames"
 					// Note: On its own, the audio will not re-synch with video;
 					// It plays independently so it can get ahead!
+#if BLADERUNNER_ORIGINAL_SETTINGS
+					_vm->_mixer->playStream(kVQASoundType, &_soundHandle, _audioStream, -1, (_vm->_audioSpeech->getVolume() * Audio::Mixer::kMaxChannelVolume) / 100);
+#else
+					// using the default volume argument (Audio::Mixer::kMaxChannelVolume)
+					// will result in the the configured volume for speech being used,
+					// since playStream() does get the soundtype volume into consideration.
+					// See: Channel::updateChannelVolumes() in audio/mixer.cpp
 					_vm->_mixer->playStream(kVQASoundType, &_soundHandle, _audioStream);
+#endif // BLADERUNNER_ORIGINAL_SETTINGS
 				}
 				_audioStarted = true;
 			}


Commit: 7a3fe451a15b24654d5fb7ff44158f737c853590
    https://github.com/scummvm/scummvm/commit/7a3fe451a15b24654d5fb7ff44158f737c853590
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:17:41+03:00

Commit Message:
BLADERUNNER: Comment fix and notes for some Luther cues

Changed paths:
    engines/bladerunner/script/ai/blimp_guy.cpp
    engines/bladerunner/script/ai/luther.cpp


diff --git a/engines/bladerunner/script/ai/blimp_guy.cpp b/engines/bladerunner/script/ai/blimp_guy.cpp
index fe8027dcdd2..c9203ed2861 100644
--- a/engines/bladerunner/script/ai/blimp_guy.cpp
+++ b/engines/bladerunner/script/ai/blimp_guy.cpp
@@ -35,7 +35,7 @@ namespace BladeRunner {
 // and one cutscene:
 //  - TB_FLY
 // In the in-game scenes (not cutscenes) this speech is played as ambient sound
-// using Ambient_Sounds_Add_Speech_Sound() and is thus not subtitles as of yet.
+// using Ambient_Sounds_Add_Speech_Sound() and is thus not subtitled as of yet.
 // TODO: maybe we could support dual subtitles being displayed on-screen for cases when Ambient Speech Sound
 // would overlap over character speech.
 // The Blimp Guy's speech in the TB_FLY VQA cutscene is subtitled.
diff --git a/engines/bladerunner/script/ai/luther.cpp b/engines/bladerunner/script/ai/luther.cpp
index 3a5d965032b..34d348feeae 100644
--- a/engines/bladerunner/script/ai/luther.cpp
+++ b/engines/bladerunner/script/ai/luther.cpp
@@ -48,9 +48,9 @@ bool AIScriptLuther::Update() {
 	 && !Game_Flag_Query(kFlagUG16PulledGun)
 	 &&  Global_Variable_Query(kVariableChapter) == 4
 	) {
-		Actor_Says(kActorMcCoy, 5720, 12);
-		Actor_Says(kActorLuther, 80, 13);
-		Actor_Says(kActorLance, 40, 12);
+		Actor_Says(kActorMcCoy, 5720, 12); // Just a moment of your time, please.
+		Actor_Says(kActorLuther, 80, 13); // I am sick and tired of people waving those things around.
+		Actor_Says(kActorLance, 40, 12); // Just give it up. You got no jurisdiction down here.
 		Game_Flag_Set(kFlagUG16PulledGun);
 		return false;
 	}


Commit: d393610f277aea67c9470bb59d6b34cab5314dbd
    https://github.com/scummvm/scummvm/commit/d393610f277aea67c9470bb59d6b34cab5314dbd
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:17:50+03:00

Commit Message:
BLADERUNNER: Don't spare Zuben if he hits McCoy

Original engine bug. Zuben could slash McCoy multiple times and McCoy would still spare him.

Re-uses the kFlagMcCoyShotAtZuben flag that prevents McCoy from sparing Zuben.

Changed paths:
    engines/bladerunner/script/ai/zuben.cpp


diff --git a/engines/bladerunner/script/ai/zuben.cpp b/engines/bladerunner/script/ai/zuben.cpp
index a7639829a3c..5e190f23685 100644
--- a/engines/bladerunner/script/ai/zuben.cpp
+++ b/engines/bladerunner/script/ai/zuben.cpp
@@ -19,6 +19,7 @@
  *
  */
 
+#include "bladerunner/bladerunner.h"
 #include "bladerunner/script/ai_script.h"
 
 namespace BladeRunner {
@@ -784,6 +785,16 @@ bool AIScriptZuben::UpdateAnimation(int *animation, int *frame) {
 
 		if (_animationFrame == 11) {
 			Actor_Combat_AI_Hit_Attempt(kActorZuben);
+#if !BLADERUNNER_ORIGINAL_BUGS
+			if (Game_Flag_Query(kFlagCT07ZubenAttack)
+			    && !Game_Flag_Query(kFlagMcCoyShotAtZuben)) {
+				// We re-use the flag that indicates that McCoy shot at Zuben,
+				// even though here it's Zuben who hits McCoy.
+				// This should be fine, since it serves the same purpose:
+				// McCoy can no longer spare Zuben if he holsters his gun.
+				Game_Flag_Set(kFlagMcCoyShotAtZuben);
+			}
+#endif // BLADERUNNER_ORIGINAL_BUGS
 		}
 
 		if (_animationFrame >= Slice_Animation_Query_Number_Of_Frames(*animation)) {


Commit: c5ce933aa8b2247e190b7d422f167cb49ca618d3
    https://github.com/scummvm/scummvm/commit/c5ce933aa8b2247e190b7d422f167cb49ca618d3
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:17:57+03:00

Commit Message:
BLADERUNNER: Fix glitch in CT01 mainloop

Changed paths:
    engines/bladerunner/script/scene/ct01.cpp
    engines/bladerunner/vqa_player.cpp


diff --git a/engines/bladerunner/script/scene/ct01.cpp b/engines/bladerunner/script/scene/ct01.cpp
index e3895baa401..9ccf1b7cc2a 100644
--- a/engines/bladerunner/script/scene/ct01.cpp
+++ b/engines/bladerunner/script/scene/ct01.cpp
@@ -26,7 +26,7 @@ namespace BladeRunner {
 enum kCT01Loops {
 	kCT01LoopInshotFromCT12WithSpinner = 0, //   0 -  14
 	kCT01LoopInshot                    = 1, //  15 - 194
-	kCT01LoopMainLoop                  = 2, // 195 - 255
+	kCT01LoopMainLoop                  = 2, // 195 - 255 (plays up to 254 due to a bug fix)
 	kCT01LoopDoorAnim                  = 4, // 256 - 315
 	kCT01LoopOutshot                   = 5, // 316 - 435
 	kCT01LoopInshotFromCT12NoSpinner   = 6, // 436 - 450
diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp
index 53981775492..f2d1556ba7b 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -54,6 +54,11 @@ bool VQAPlayer::open() {
 		// smoke (overlay) after explosion of Dermo Labs in DR04
 		// This has still frames in the end that so it looked as if the smoke was "frozen"
 		_decoder._loopInfo.loops[0].end  = 58; // 59 up to 74 are still frames
+	} else if (_name.equals("CT01.VQA")) {
+		// In the last frame of the Mainloop (255) a Howie Lee's customer's hand
+		// backwards abruptly the loop looks jarring. We skip the last frame.
+		_decoder._loopInfo.loops[2].end  = 254;
+		_decoder._loopInfo.loops[3].end  = 254;
 	}
 #endif
 
@@ -187,9 +192,8 @@ int VQAPlayer::update(bool forceDraw, bool advanceFrame, bool useTime, Graphics:
 			}
 #endif
 		}
-		if (_frameNext != _frameBeginNext) {
-			_frameNext = _frameBeginNext;
-		}
+
+		_frameNext = _frameBeginNext;
 
 		if (loopEndQueued == -1) {
 			if (_repeatsCount != -1) {


Commit: 387c0129ce4af3ecd9678c1c368422798efcf99c
    https://github.com/scummvm/scummvm/commit/387c0129ce4af3ecd9678c1c368422798efcf99c
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:18:04+03:00

Commit Message:
BLADERUNNER: Janitorial remove rogue space

Changed paths:
    engines/bladerunner/ui/esper.cpp


diff --git a/engines/bladerunner/ui/esper.cpp b/engines/bladerunner/ui/esper.cpp
index b76e48373e7..d3fae00a7df 100644
--- a/engines/bladerunner/ui/esper.cpp
+++ b/engines/bladerunner/ui/esper.cpp
@@ -1105,7 +1105,7 @@ void ESPER::drawMouse(Graphics::Surface &surface) {
 					_mouseOverScroll = 4;
 				} else if (_mouseOverScroll == 1 && this->_viewport.right == kPhotoWidth - 1) {
 					_mouseOverScroll = 4;
-				} else if (_mouseOverScroll == 2 && this->_viewport.bottom ==  kPhotoHeight - 1) {
+				} else if (_mouseOverScroll == 2 && this->_viewport.bottom == kPhotoHeight - 1) {
 					_mouseOverScroll = 4;
 				} else if (_mouseOverScroll == 3 && this->_viewport.left == 0) {
 					_mouseOverScroll = 4;


Commit: d34180f96227c40906ae5a162329112a506eb795
    https://github.com/scummvm/scummvm/commit/d34180f96227c40906ae5a162329112a506eb795
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:18:10+03:00

Commit Message:
BLADERUNNER: Fix glitches in CT01 and PS15

PS15 was rogue pixels with bad z-buffer. Both are original bugs

CT01 fix is an expansion of the existing fix to cover other loops and chapters affected.

Changed paths:
    engines/bladerunner/vqa_player.cpp
    engines/bladerunner/vqa_player.h
    engines/bladerunner/zbuffer.cpp
    engines/bladerunner/zbuffer.h


diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp
index f2d1556ba7b..7751ed34265 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -27,6 +27,7 @@
 #if BLADERUNNER_ORIGINAL_SETTINGS
 #include "bladerunner/audio_speech.h"
 #endif
+#include "bladerunner/zbuffer.h"
 
 #include "audio/decoders/raw.h"
 
@@ -47,6 +48,7 @@ bool VQAPlayer::open() {
 	}
 
 #if !BLADERUNNER_ORIGINAL_BUGS
+	_specialPS15GlitchFix = false;
 	// TB05 has wrong end of a loop and this will load empty zbuffer from next loop, which will lead to broken pathfinding
 	if (_name.equals("TB05_2.VQA")) {
 		_decoder._loopInfo.loops[1].end = 60;
@@ -54,11 +56,19 @@ bool VQAPlayer::open() {
 		// smoke (overlay) after explosion of Dermo Labs in DR04
 		// This has still frames in the end that so it looked as if the smoke was "frozen"
 		_decoder._loopInfo.loops[0].end  = 58; // 59 up to 74 are still frames
-	} else if (_name.equals("CT01.VQA")) {
+	} else if (_name.equals("CT01.VQA") || _name.equals("CT01_2.VQA") || _name.equals("CT01_3.VQA") ) {
 		// In the last frame of the Mainloop (255) a Howie Lee's customer's hand
 		// backwards abruptly the loop looks jarring. We skip the last frame.
+		// The issue is also present in the non-spinner versions of the loop
+		// and for all chapters where this scene is available (Acts 1 through 5)
 		_decoder._loopInfo.loops[2].end  = 254;
 		_decoder._loopInfo.loops[3].end  = 254;
+
+		_decoder._loopInfo.loops[7].end  = 510;
+		_decoder._loopInfo.loops[8].end  = 510;
+	} else if (_name.equals("PS15.VQA") || _name.equals("PS15_2.VQA")) {
+		// Fix should be applied in Act 1-3 versions of this background
+		_specialPS15GlitchFix = true;
 	}
 #endif
 
@@ -306,6 +316,21 @@ int VQAPlayer::update(bool forceDraw, bool advanceFrame, bool useTime, Graphics:
 
 void VQAPlayer::updateZBuffer(ZBuffer *zbuffer) {
 	_decoder.decodeZBuffer(zbuffer);
+#if !BLADERUNNER_ORIGINAL_BUGS
+	if (_specialPS15GlitchFix) {
+		// The glitch (bad z-buffer, value zero (0))
+		// is present in the following pixels:
+		//  x: 387, y in [179, 192]
+		//  x: 388, y in [179, 202]
+		for (int y = 179; y < 193; ++y) {
+			_vm->_zbuffer->setDataZbufExplicit(387, y, 10720);
+			_vm->_zbuffer->setDataZbufExplicit(388, y, 10720);
+		}
+		for (int y = 193; y < 203; ++y) {
+			_vm->_zbuffer->setDataZbufExplicit(388, y, 10720);
+		}
+	}
+#endif
 }
 
 void VQAPlayer::updateView(View *view) {
diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h
index f0a00891385..6de6abced66 100644
--- a/engines/bladerunner/vqa_player.h
+++ b/engines/bladerunner/vqa_player.h
@@ -86,6 +86,8 @@ class VQAPlayer {
 	bool   _audioStarted;
 	Audio::SoundHandle _soundHandle;
 
+	bool   _specialPS15GlitchFix;
+
 	void (*_callbackLoopEnded)(void *, int frame, int loopId);
 	void  *_callbackData;
 
@@ -112,6 +114,7 @@ public:
 		  _frameNextTime(0),
 		  _hasAudio(false),
 		  _audioStarted(false),
+		  _specialPS15GlitchFix(false),
 		  _callbackLoopEnded(nullptr),
 		  _callbackData(nullptr) { }
 
diff --git a/engines/bladerunner/zbuffer.cpp b/engines/bladerunner/zbuffer.cpp
index b53a7d09937..843e6c3b6e7 100644
--- a/engines/bladerunner/zbuffer.cpp
+++ b/engines/bladerunner/zbuffer.cpp
@@ -167,7 +167,8 @@ bool ZBuffer::decodeData(const uint8 *data, int size) {
 	} else {
 		clean();
 		decodePartialZBuffer(data, _zbuf1, size);
-		decodePartialZBuffer(data, _zbuf2, size);
+		//decodePartialZBuffer(data, _zbuf2, size);
+		memcpy(_zbuf2, _zbuf1, size);
 	}
 
 	return true;
@@ -177,6 +178,15 @@ uint16 *ZBuffer::getData() const {
 	return _zbuf2;
 }
 
+#if !BLADERUNNER_ORIGINAL_BUGS
+void ZBuffer::setDataZbufExplicit(int x, int y, uint16 overidingVal) {
+	assert(x >= 0 && x < _width);
+	assert(y >= 0 && y < _height);
+	_zbuf1[y * _width + x] = overidingVal;
+	_zbuf2[y * _width + x] = overidingVal;
+}
+#endif // BLADERUNNER_ORIGINAL_BUGS
+
 uint16 ZBuffer::getZValue(int x, int y) const {
 	assert(x >= 0 && x < _width);
 	assert(y >= 0 && y < _height);
diff --git a/engines/bladerunner/zbuffer.h b/engines/bladerunner/zbuffer.h
index ac69900c04e..17b89801503 100644
--- a/engines/bladerunner/zbuffer.h
+++ b/engines/bladerunner/zbuffer.h
@@ -67,6 +67,10 @@ public:
 	uint16 *getData() const;
 	uint16 getZValue(int x, int y) const;
 
+#if !BLADERUNNER_ORIGINAL_BUGS
+	void setDataZbufExplicit(int x, int y, uint16 overidingVal);
+#endif // BLADERUNNER_ORIGINAL_BUGS
+
 private:
 	void blit(Common::Rect rect);
 


Commit: c2de0497a773871034f15e536dcd94b3062eddce
    https://github.com/scummvm/scummvm/commit/c2de0497a773871034f15e536dcd94b3062eddce
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:18:17+03:00

Commit Message:
BLADERUNNER: Rename static method that hid base class method

Changed paths:
    engines/bladerunner/ui/kia_section_save.cpp
    engines/bladerunner/ui/kia_section_save.h


diff --git a/engines/bladerunner/ui/kia_section_save.cpp b/engines/bladerunner/ui/kia_section_save.cpp
index 6908510c27f..3962a495618 100644
--- a/engines/bladerunner/ui/kia_section_save.cpp
+++ b/engines/bladerunner/ui/kia_section_save.cpp
@@ -105,7 +105,7 @@ void KIASectionSave::open() {
 
 	if (!_saveList.empty() || ableToSaveGame) {
 
-		_buttons->activate(onButtonHovered, nullptr, nullptr, onButtonPressed, this);
+		_buttons->activate(onButtonHovered, nullptr, nullptr, onKSSButtonPressed, this);
 		_inputBox->show();
 
 		_scrollBox->clearLines();
@@ -337,7 +337,7 @@ void KIASectionSave::onButtonHovered(int buttonId, void *callbackData) {
 	self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(kSfxTEXT3), 100, 0, 0, 50, 0);
 }
 
-void KIASectionSave::onButtonPressed(int buttonId, void *callbackData) {
+void KIASectionSave::onKSSButtonPressed(int buttonId, void *callbackData) {
 	KIASectionSave *self = (KIASectionSave *)callbackData;
 
 	if (buttonId == 0) {
diff --git a/engines/bladerunner/ui/kia_section_save.h b/engines/bladerunner/ui/kia_section_save.h
index 4f6e2e54772..23964ffd685 100644
--- a/engines/bladerunner/ui/kia_section_save.h
+++ b/engines/bladerunner/ui/kia_section_save.h
@@ -90,7 +90,9 @@ private:
 	static void inputBoxCallback(void *callbackData, void *source);
 
 	static void onButtonHovered(int buttonId, void *callbackData);
-	static void onButtonPressed(int buttonId, void *callbackData);
+	// NOTE: Renamed the method from onButtonPressed() to onKSSButtonPressed(),
+	// since this static method hides the virtual method of KIASectionBase (which is not static and has different signature)
+	static void onKSSButtonPressed(int buttonId, void *callbackData);
 
 	void changeState(State state);
 	void save();


Commit: 3d09a61e04099be4b57b120afa83354b4a1490e7
    https://github.com/scummvm/scummvm/commit/3d09a61e04099be4b57b120afa83354b4a1490e7
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:18:26+03:00

Commit Message:
BLADERUNNER: Custom beta cursors for exits and esper

Also fixes for the beta combat cursors (color and hotspot / target center)

Changed paths:
    engines/bladerunner/debugger.cpp
    engines/bladerunner/mouse.cpp
    engines/bladerunner/mouse.h
    engines/bladerunner/shape.cpp
    engines/bladerunner/shape.h


diff --git a/engines/bladerunner/debugger.cpp b/engines/bladerunner/debugger.cpp
index 26db22b29c1..e168af26f12 100644
--- a/engines/bladerunner/debugger.cpp
+++ b/engines/bladerunner/debugger.cpp
@@ -1899,7 +1899,7 @@ bool Debugger::cmdRegion(int argc, const char **argv) {
 
 /**
 * click:  Toggle showing mouse click info in the text console (not the debugger window)
-* beta:   Toggle beta crosshairs for aiming in combat mode
+* beta:   Toggle beta crosshairs for aiming in combat mode, exit cursors (custom) and ESPER edge cursors (custom)
 * add0:   Toggle semi-transparent hotspot cursor (additive draw mode 0)
 * add1:   Toggle semi-transparent hotspot cursor (additive draw mode 1)
 */
diff --git a/engines/bladerunner/mouse.cpp b/engines/bladerunner/mouse.cpp
index 44d98eea9aa..5a9ef497b81 100644
--- a/engines/bladerunner/mouse.cpp
+++ b/engines/bladerunner/mouse.cpp
@@ -80,6 +80,7 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 0;
 		_hotspotY = 0;
 		break;
+
 	case 1:
 		// normal cursor over hotspot (not exit) (green rotating)
 		// animating: 8 frames (4-11)
@@ -96,36 +97,58 @@ void Mouse::setCursor(int cursor) {
 			}
 		}
 		break;
+
 	case 2:
-		// exit cursor (upwards/North)
+		// static exit cursor (upwards/North)
 		_frame = 12;
 		_hotspotX = 12;
 		_hotspotY = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_UP);
+		} else {
+			_drawModeBitFlags &= ~(MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_UP);
+		}
 		break;
+
 	case 3:
-		// exit cursor (right/East)
+		// static exit cursor (right/East)
 		_frame = 15;
 		_hotspotX = 23;
 		_hotspotY = 12;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_RIGHT);
+		} else {
+			_drawModeBitFlags &= ~(MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_RIGHT);
+		}
 		break;
+
 	case 4:
-		// exit cursor (downwards/South)
+		// static exit cursor (downwards/South)
 		_frame = 13;
 		_hotspotX = 12;
 		_hotspotY = 23;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_DOWN);
+		}
 		break;
+
 	case 5:
-		// exit cursor (left/West)
+		// static exit cursor (left/West)
 		_frame = 14;
 		_hotspotX = 0;
 		_hotspotY = 12;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::ESPER_LEFT);
+		}
 		break;
+
 	case 6:
 		// combat cursor, simple bullets (normal / no target)
 		_frame = 16;
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 7:
 		// combat cursor, simple bullets (hot target)
 		// animating: 8 frames (17-24)
@@ -133,12 +156,14 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 8:
 		// combat cursor, advanced bullets (normal / no target)
 		_frame = 25;
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 9:
 		// combat cursor, advanced bullets (hot target)
 		// animating: 8 frames (26-33)
@@ -146,12 +171,14 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 10:
 		// combat cursor, best bullets (normal / no target)
 		_frame = 34;
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 11:
 		// combat cursor, best bullets (hot target)
 		// animating: 8 frames (35-42)
@@ -159,6 +186,7 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 19;
 		_hotspotY = 19;
 		break;
+
 	case 12:
 		// exit cursor (upwards/North)
 		// resets animCounter too (as opposed to _cursor == 2)
@@ -167,7 +195,11 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 12;
 		_hotspotY = 0;
 		_animCounter = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::EXIT_UP);
+		}
 		break;
+
 	case 13:
 		// exit cursor (right/East)
 		// resets animCounter too (as opposed to _cursor == 3)
@@ -176,7 +208,11 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 23;
 		_hotspotY = 12;
 		_animCounter = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::EXIT_RIGHT);
+		}
 		break;
+
 	case 14:
 		// exit cursor (downwards/South)
 		// resets animCounter too (as opposed to _cursor == 4)
@@ -185,7 +221,11 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 12;
 		_hotspotY = 23;
 		_animCounter = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::EXIT_DOWN);
+		}
 		break;
+
 	case 15:
 		// exit cursor (left/West)
 		// resets animCounter too (as opposed to _cursor == 5)
@@ -194,11 +234,21 @@ void Mouse::setCursor(int cursor) {
 		_hotspotX = 0;
 		_hotspotY = 12;
 		_animCounter = 0;
+		if (_vm->_debugger->_useBetaCrosshairsCursor) {
+			_drawModeBitFlags |= (MouseDrawFlags::CUSTOM | MouseDrawFlags::EXIT_LEFT);
+		}
 		break;
+
 	case 16:
+		// (beta version) combat cursor (inactive)
+		_drawModeBitFlags &= ~(0x01 << _vm->_settings->getAmmoType());
+		_drawModeBitFlags &= ~(MouseDrawFlags::SPECIAL);
 #if !BLADERUNNER_ORIGINAL_BUGS
 		_frame = 0;
+		_hotspotX = 11;
+		_hotspotY = 11;
 		break;
+
 	case 17:
 #endif
 		// (beta version) combat cursor (white or flashing white/blue)
@@ -214,9 +264,13 @@ void Mouse::setCursor(int cursor) {
 		// So:
 		// id 16: inactive (beta) combat crosshairs
 		// id 17: active (beta) combat crosshairs
+		_drawModeBitFlags |= (0x01 << _vm->_settings->getAmmoType());
+		_drawModeBitFlags |=  MouseDrawFlags::SPECIAL;
 		_frame = 1;
 		_hotspotX = 11;
 		_hotspotY = 11;
+		break;
+
 	default:
 		break;
 	}
@@ -230,7 +284,7 @@ void Mouse::getXY(int *x, int *y) const {
 void Mouse::setMouseJitterUp() {
 	switch (_vm->_settings->getDifficulty()) {
 	default:
-		// fallthrough intended
+		// fall through intended
 	case kGameDifficultyEasy:
 		_randomCountdownX = 2;
 		_randomX = _vm->_rnd.getRandomNumberRng(0, 6) - 3;
@@ -254,7 +308,7 @@ void Mouse::setMouseJitterUp() {
 void Mouse::setMouseJitterDown() {
 	switch (_vm->_settings->getDifficulty()) {
 	default:
-		// fallthrough intended
+		// fall through intended
 	case kGameDifficultyEasy:
 		_randomCountdownY = 2;
 		_randomX = _vm->_rnd.getRandomNumberRng(0, 6) - 3;
@@ -332,59 +386,114 @@ void Mouse::updateCursorFrame() {
 	switch (_cursor) {
 	case 0:
 		break;
+
 	case 1:
 		if (++_frame > 11)
 			_frame = 4;
 		break;
+
 	case 2:
+		// fall through
 	case 3:
+		// fall through
 	case 4:
+		// fall through
 	case 5:
+		// fall through
+		// 2,3,4,5 are case for "static" exit arrows, used in ESPER
 	case 6:
+		// 6 is combat cursor, simple bullets (normal / no target)
 		break;
+
 	case 7:
 		if (++_frame > 24)
 			_frame = 17;
 		break;
+
 	case 8:
 		break;
+
 	case 9:
 		if (++_frame > 33)
 			_frame = 26;
 		break;
+
 	case 10:
 		break;
+
 	case 11:
 		if (++_frame > 42)
 			_frame = 35;
 		break;
+
 	case 12:
-		if (++_animCounter >= 4) {
-			_animCounter = 0;
+		if ((_drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM)
+			&& (_drawModeBitFlags & Mouse::MouseDrawFlags::EXIT_UP)) {
+			// use the 3 least significant bits in place of "frame" index
+			_drawModeBitFlags +=1;
+			if ((_drawModeBitFlags & 0x7) == 0x7) {
+				_drawModeBitFlags &= ~0x7;
+			}
+		} else {
+			if (++_animCounter >= 4) {
+				_animCounter = 0;
+			}
+			_hotspotY = -offset[_animCounter];
 		}
-		_hotspotY = -offset[_animCounter];
 		break;
+
 	case 13:
-		if (++_animCounter >= 4) {
-			_animCounter = 0;
+		if ((_drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM)
+		    && (_drawModeBitFlags & Mouse::MouseDrawFlags::EXIT_RIGHT)) {
+			// use the 3 least significant bits in place of "frame" index
+			_drawModeBitFlags +=1;
+			if ((_drawModeBitFlags & 0x7) == 0x7) {
+				_drawModeBitFlags &= ~0x7;
+			}
+		} else {
+			if (++_animCounter >= 4) {
+				_animCounter = 0;
+			}
+			_hotspotX = 23 + offset[_animCounter];
 		}
-		_hotspotX = 23 + offset[_animCounter];
 		break;
+
 	case 14:
-		if (++_animCounter >= 4) {
-			_animCounter = 0;
+		if ((_drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM)
+		    && (_drawModeBitFlags & Mouse::MouseDrawFlags::EXIT_DOWN)) {
+			// use the 3 least significant bits in place of "frame" index
+			_drawModeBitFlags +=1;
+			if ((_drawModeBitFlags & 0x7) == 0x7) {
+				_drawModeBitFlags &= ~0x7;
+			}
+		} else {
+			if (++_animCounter >= 4) {
+				_animCounter = 0;
+			}
+			_hotspotY = 23 + offset[_animCounter];
 		}
-		_hotspotY = 23 + offset[_animCounter];
 		break;
+
 	case 15:
-		if (++_animCounter >= 4) {
-			_animCounter = 0;
+		if ((_drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM)
+		    && (_drawModeBitFlags & Mouse::MouseDrawFlags::EXIT_LEFT)) {
+			// use the 3 least significant bits in place of "frame" index
+			_drawModeBitFlags +=1;
+			if ((_drawModeBitFlags & 0x7) == 0x7) {
+				_drawModeBitFlags &= ~0x7;
+			}
+		} else {
+			if (++_animCounter >= 4) {
+				_animCounter = 0;
+			}
+			_hotspotX = -offset[_animCounter];
 		}
-		_hotspotX = -offset[_animCounter];
 		break;
+
 	case 16:
 #if !BLADERUNNER_ORIGINAL_BUGS
 		break;
+
 	case 17:
 #endif
 		if (++_frame > 2)
@@ -397,6 +506,7 @@ void Mouse::updateCursorFrame() {
 			_frame = 1;
 #endif
 		break;
+
 	default:
 		break;
 	}
@@ -431,15 +541,19 @@ void Mouse::tick(int x, int y) {
 		case 0:
 			cursorId = 12;
 			break;
+
 		case 1:
 			cursorId = 13;
 			break;
+
 		case 2:
 			cursorId = 14;
 			break;
+
 		case 3:
 			cursorId = 15;
 			break;
+
 		default:
 			break;
 		}
@@ -476,19 +590,20 @@ void Mouse::tick(int x, int y) {
 	if (actorId >= 0 || itemId >= 0 || isObject) {
 		if (_vm->_debugger->_useBetaCrosshairsCursor) {
 			cursorId = 17;
-			_drawModeBitFlags |= (0x01 << _vm->_settings->getAmmoType());
-			_drawModeBitFlags |=  MouseDrawFlags::SPECIAL;
 		} else {
 			switch (_vm->_settings->getAmmoType()) {
 			case 0:
 				cursorId = 7;
 				break;
+
 			case 1:
 				cursorId = 9;
 				break;
+
 			case 2:
 				cursorId = 11;
 				break;
+
 			default:
 				break;
 			}
@@ -499,19 +614,20 @@ void Mouse::tick(int x, int y) {
 	} else {
 		if (_vm->_debugger->_useBetaCrosshairsCursor) {
 			cursorId = 16;
-			_drawModeBitFlags &= ~(0x01 << _vm->_settings->getAmmoType());
-			_drawModeBitFlags &= ~(MouseDrawFlags::SPECIAL);
 		} else {
 			switch (_vm->_settings->getAmmoType()) {
 			case 0:
 				cursorId = 6;
 				break;
+
 			case 1:
 				cursorId = 8;
 				break;
+
 			case 2:
 				cursorId = 10;
 				break;
+
 			default:
 				break;
 			}
diff --git a/engines/bladerunner/mouse.h b/engines/bladerunner/mouse.h
index 0324f2da484..a8dddf0c68c 100644
--- a/engines/bladerunner/mouse.h
+++ b/engines/bladerunner/mouse.h
@@ -50,7 +50,7 @@ class Mouse {
 	int _randomX;
 	int _randomY;
 
-	uint8 _drawModeBitFlags; // replaces the additive bool with a set of bit flags (including flags for additive mode)
+	uint16 _drawModeBitFlags; // replaces the additive bool with a set of bit flags (including flags for additive mode)
 
 public:
 	Mouse(BladeRunnerEngine *vm);
@@ -76,12 +76,21 @@ public:
 	Vector3 getXYZ(int x, int y) const;
 
 	typedef enum mouseDrawFlags {
-		REDCROSSHAIRS    = 0x01,
-		YELLOWCROSSHAIRS = 0x02,
-		BLUECROSSHAIRS   = 0x04,
-		SPECIAL          = 0x08,
-		ADDITIVE_MODE0   = 0x10,
-		ADDITIVE_MODE1   = 0x20
+		REDCROSSHAIRS    = 0x0001,
+		YELLOWCROSSHAIRS = 0x0002,
+		BLUECROSSHAIRS   = 0x0004,
+		SPECIAL          = 0x0008,
+		ADDITIVE_MODE0   = 0x0010,
+		ADDITIVE_MODE1   = 0x0020,
+		CUSTOM           = 0x0040,
+		EXIT_UP          = 0x0080,
+		EXIT_DOWN        = 0x0100,
+		EXIT_LEFT        = 0x0200,
+		EXIT_RIGHT       = 0x0400,
+		ESPER_UP         = 0x0800,
+		ESPER_DOWN       = 0x1000,
+		ESPER_LEFT       = 0x2000,
+		ESPER_RIGHT      = 0x4000
 	} MouseDrawFlags;
 };
 
diff --git a/engines/bladerunner/shape.cpp b/engines/bladerunner/shape.cpp
index 5ae26d5a3b6..1c3646ed1b2 100644
--- a/engines/bladerunner/shape.cpp
+++ b/engines/bladerunner/shape.cpp
@@ -61,7 +61,155 @@ Shape::~Shape() {
 	delete[] _data;
 }
 
-void Shape::draw(Graphics::Surface &surface, int x, int y, uint8 drawModeBitFlags) const {
+void Shape::drawFilledTriangleAux(Graphics::Surface &surface, const int &dst_x, const int &dst_y, int x1, int y1, int x2, int y2, int x3, int y3, uint32 colorRGB) const {
+	// Code used is based on the Bresenham-like algorithm as described in:
+	// https://mcejp.github.io/2020/11/06/bresenham.html
+	// http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html
+
+	const Vector2 triangleV1 = Vector2(x1, y1);
+	const Vector2 triangleV2 = Vector2(x2, y2); // (V2, V3) should be the flat side, so either x2 == x3 or y2 == y3
+	const Vector2 triangleV3 = Vector2(x3, y3);
+
+	// vTmp1 will be moving along the "left" side of the triangle, and vTmp2 along the "right" side.
+	Vector2 vTmp1 = triangleV1;
+	Vector2 vTmp2 = triangleV1;
+
+	bool swappedDx1WithDy1 = false;
+	bool swappedDx2WithDy2 = false;
+
+	int dx1 = abs(triangleV2.x - triangleV1.x);
+	int dy1 = abs(triangleV2.y - triangleV1.y);
+
+	if (dy1 > dx1) {
+		SWAP(dy1, dx1);
+		swappedDx1WithDy1 = true;
+	}
+
+	int dx2 = abs(triangleV3.x - triangleV1.x);
+	int dy2 = abs(triangleV3.y - triangleV1.y);
+
+	if (dy2 > dx2) {
+		SWAP(dy2, dx2);
+		swappedDx2WithDy2 = true;
+	}
+
+	int signx1 = (triangleV2.x - triangleV1.x) > 0 ? 1: -1;
+	if (triangleV2.x == triangleV1.x) {
+		signx1 = 0;
+	}
+
+	int signx2 = (triangleV3.x - triangleV1.x) > 0 ? 1: -1;
+	if (triangleV3.x == triangleV1.x) {
+		signx2 = 0;
+	}
+
+	int signy1 = (triangleV2.y - triangleV1.y) > 0 ? 1: -1;
+	if (triangleV2.y == triangleV1.y) {
+		signy1 = 0;
+	}
+
+	int signy2 = (triangleV3.y - triangleV1.y) > 0 ? 1: -1;
+	if (triangleV3.y == triangleV1.y) {
+		signy2 = 0;
+	}
+
+	int e1 = 2 * dy1 - dx1;
+	int e2 = 2 * dy2 - dx2;
+
+	for (int i = 0; i <= dx1; ++i) {
+		// dx1 here may be dy1 (if they swapped above). It is whichever was the largest of the two.
+		// We loop over each pixel of "horizontal" (triangle filling) line
+		// check if paint goes from left endpoint of "horizontal" (triangle filling) line to right or other way round
+		int leftEndPoint, rightEndPoint;
+
+		if (triangleV2.y == triangleV3.y) {
+			if (vTmp1.x < vTmp2.x) {
+				leftEndPoint = ceil(vTmp1.x);
+				rightEndPoint = int(vTmp2.x);
+			} else {
+				leftEndPoint = ceil(vTmp2.x);
+				rightEndPoint = int(vTmp1.x);
+			}
+		} else {
+			if (vTmp1.y < vTmp2.y) {
+				leftEndPoint = ceil(vTmp1.y);
+				rightEndPoint = int(vTmp2.y);
+			} else {
+				leftEndPoint = ceil(vTmp2.y);
+				rightEndPoint = int(vTmp1.y);
+			}
+		}
+
+		void *dstPtr;
+		for (int xPos = leftEndPoint; xPos <= rightEndPoint; ++xPos) {
+			if (triangleV2.y == triangleV3.y) {
+				dstPtr = surface.getBasePtr(CLIP(dst_x + xPos, 0, surface.w - 1), CLIP(dst_y + (int)ceil(vTmp1.y), 0, surface.h - 1));
+			} else {
+				dstPtr = surface.getBasePtr(CLIP(dst_x + (int)ceil(vTmp1.x), 0, surface.w - 1), CLIP(dst_y + xPos, 0, surface.h - 1));
+			}
+			drawPixel(surface, dstPtr, colorRGB);
+		}
+
+		while (e1 >= 0) {
+			if (swappedDx1WithDy1) {
+				vTmp1.x += signx1;
+			} else {
+				vTmp1.y += signy1;
+			}
+			e1 = e1 - 2 * dx1;
+		}
+
+		if (swappedDx1WithDy1) {
+			vTmp1.y += signy1;
+		} else {
+			vTmp1.x += signx1;
+		}
+		e1 = e1 + 2 * dy1;
+
+		// Here we've rendered the next point on the "left" edge triangle line.
+		// We now do the same for the "right" edge triangle line, until we are on
+		// the same y-value as on the "left" edge triangle line.
+		if (triangleV2.y == triangleV3.y) {
+			while (vTmp2.y != vTmp1.y) {
+				while (e2 >= 0) {
+					if (swappedDx2WithDy2) {
+						vTmp2.x += signx2;
+					} else {
+						vTmp2.y += signy2;
+					}
+					e2 = e2 - 2 * dx2;
+				}
+
+				if (swappedDx2WithDy2) {
+					vTmp2.y += signy2;
+				} else {
+					vTmp2.x += signx2;
+				}
+				e2 = e2 + 2 * dy2;
+			}
+		} else {
+			while (vTmp2.x != vTmp1.x) {
+				while (e2 >= 0) {
+					if (swappedDx2WithDy2) {
+						vTmp2.x += signx2;
+					} else {
+						vTmp2.y += signy2;
+					}
+					e2 = e2 - 2 * dx2;
+				}
+
+				if (swappedDx2WithDy2) {
+					vTmp2.y += signy2;
+				} else {
+					vTmp2.x += signx2;
+				}
+				e2 = e2 + 2 * dy2;
+			}
+		}
+	}
+}
+
+void Shape::draw(Graphics::Surface &surface, int x, int y, uint16 drawModeBitFlags) const {
 	int src_x = CLIP(-x, 0, _width);
 	int src_y = CLIP(-y, 0, _height);
 
@@ -77,66 +225,138 @@ void Shape::draw(Graphics::Surface &surface, int x, int y, uint8 drawModeBitFlag
 		return;
 	}
 
-	const uint8 *src_p = _data + 2 * (src_y * _width + src_x);
-
-	uint16 shpColor = 0;
-	uint32 surfaceColorRGBPrev = 0;
-	uint32 newSurfaceColorRGB = 0;
-	uint8 a, r, g, b;
-	uint8 rPrev, gPrev, bPrev;
-	uint16 rgb16bitPrev = 0;
-	uint16 rgb16bitAdd = 0;
-	for (int yi = 0; yi != rect_h; ++yi) {
-		for (int xi = 0; xi != rect_w; ++xi) {
-			shpColor = READ_LE_UINT16(src_p);
-			src_p += 2;
-
-			getGameDataColor(shpColor, a, r, g, b);
-
-			if (!a) {
-				// Ignore the alpha in the output as it is inversed in the input
-				void *dstPtr = surface.getBasePtr(CLIP(dst_x + xi, 0, surface.w - 1), CLIP(dst_y + yi, 0, surface.h - 1));
-				if (drawModeBitFlags & Mouse::MouseDrawFlags::SPECIAL) {
-					// It seems that the additive mode was supposed to be used only for cursor shapes
-					// From testing, the only cursor shape that seems to work with it is the green rotating cursor
-					// We add extra code here to cover the cases of the beta crosshairs cursor
-					// being drawn a different color based on bullet power
-					// The code for creating the specific color is custom.
-					if (drawModeBitFlags & Mouse::MouseDrawFlags::REDCROSSHAIRS) {
-						newSurfaceColorRGB = surface.format.RGBToColor((b & 0x8B) | (g >> 1), 0, 0);
-					} else if (drawModeBitFlags & Mouse::MouseDrawFlags::YELLOWCROSSHAIRS) {
-						newSurfaceColorRGB = surface.format.RGBToColor(b & 0xDF, (b & 0xA5) | (g >> 1), 0);
-					} else if (drawModeBitFlags & Mouse::MouseDrawFlags::BLUECROSSHAIRS) {
-						newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
-					} else {
-						// Additive modes
-						getPixel(surface, dstPtr, surfaceColorRGBPrev);
-						if (drawModeBitFlags & Mouse::MouseDrawFlags::ADDITIVE_MODE0) {
-							// This code makes the cursor semi-transparent
-							// but it may not be what the disassembly of the original was going for.
-							newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
-							newSurfaceColorRGB = (((uint16)surfaceColorRGBPrev >> 1) & 0xFBEF)
-												  + (((uint16)newSurfaceColorRGB >> 1) & 0xFBEF);
-						} else if (drawModeBitFlags & Mouse::MouseDrawFlags::ADDITIVE_MODE1) {
-							// This code may be closer to what the disassembly of the original was doing
-							// for additive draw mode but it doesn't look well.
-							surface.format.colorToRGB(surfaceColorRGBPrev, rPrev, gPrev, bPrev);
-							rgb16bitPrev = (  ((uint16)(rPrev >> 3) << 10)
-							                | ((uint16)(gPrev >> 3) <<  5)
-							                | ((uint16)(bPrev >> 3)));
-							rgb16bitAdd = (((uint16)rgb16bitPrev >> 1) & 0xFBEF)
-							                      + ((shpColor >> 1) & 0xFBEF);
-							getGameDataColor(rgb16bitAdd, a, r, g, b);
+	if (drawModeBitFlags & Mouse::MouseDrawFlags::CUSTOM) {
+		// for both scene exit cursors and static ESPER edge cursors
+		// we choose 25x25px -- odd dimensions chosen so that pixel 12 is the absolute middle (with edges 0-24)
+		rect_w = MIN(CLIP(25 + x, 0, 25), surface.w - x);
+		rect_h = MIN(CLIP(25 + y, 0, 25), surface.h - y);
+
+		const uint32 exitDemoShapeColors[3] = { surface.format.RGBToColor(255, 255, 143),
+		                                        surface.format.RGBToColor(228, 108,  10),
+		                                        surface.format.RGBToColor(140,   0,  37)  };
+
+		const uint32 esperExitDemoShapeColor = surface.format.RGBToColor(230, 230, 230); //  For ESPER arrows
+		Common::Rect tailRect;
+
+		// We mask out the irrelevant bitflags and exploit the fact
+		// that these exit cursor bitflags do not combine,
+		// so only one of them can be set at any time.
+		switch (drawModeBitFlags & ~0x007F) {
+		case Mouse::MouseDrawFlags::EXIT_RIGHT:
+			// 6 px h, 6 px w
+			drawFilledTriangleAux(surface, dst_x, dst_y, 24, 12, 18,  6, 18, 18, exitDemoShapeColors[ (drawModeBitFlags & 0x7)/2 % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 16, 12, 10,  6, 10, 18, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 1) % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y,  8, 12,  2,  6,  2, 18, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 2) % 3]);
+			break;
+
+		case Mouse::MouseDrawFlags::EXIT_LEFT:
+			drawFilledTriangleAux(surface, dst_x, dst_y,  0, 12,  6,  6,  6, 18, exitDemoShapeColors[ (drawModeBitFlags & 0x7)/2 % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y,  8, 12, 14,  6, 14, 18, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 1) % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 16, 12, 22,  6, 22, 18, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 2) % 3]);
+			break;
+
+		case Mouse::MouseDrawFlags::EXIT_UP:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12,  0,  6,  6, 18,  6, exitDemoShapeColors[ (drawModeBitFlags & 0x7)/2 % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12,  8,  6, 14, 18, 14, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 1) % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12, 16,  6, 22, 18, 22, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 2) % 3]);
+			break;
+
+		case Mouse::MouseDrawFlags::EXIT_DOWN:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12, 24,  6, 18, 18, 18, exitDemoShapeColors[ (drawModeBitFlags & 0x7)/2 % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12, 16,  6, 10, 18, 10, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 1) % 3]);
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12,  8,  6,  2, 18,  2, exitDemoShapeColors[((drawModeBitFlags & 0x7)/2 + 2) % 3]);
+			break;
+
+		case Mouse::MouseDrawFlags::ESPER_RIGHT:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 24, 12, 12,  0, 12, 24, esperExitDemoShapeColor);
+			tailRect = Common::Rect(dst_x +  4, dst_y + 6, dst_x + 12, dst_y + 18);
+			surface.fillRect(tailRect, esperExitDemoShapeColor);
+			break;
+
+		case Mouse::MouseDrawFlags::ESPER_LEFT:
+			drawFilledTriangleAux(surface, dst_x, dst_y,  0, 12, 12,  0, 12, 24, esperExitDemoShapeColor);
+			tailRect = Common::Rect(dst_x + 12, dst_y + 6, dst_x + 20, dst_y + 18);
+			surface.fillRect(tailRect, esperExitDemoShapeColor);
+			break;
+
+		case Mouse::MouseDrawFlags::ESPER_UP:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12,  0,  0, 12, 24, 12, esperExitDemoShapeColor);
+			tailRect = Common::Rect(dst_x +  6, dst_y + 12, dst_x + 18, dst_y + 20);
+			surface.fillRect(tailRect, esperExitDemoShapeColor);
+			break;
+
+		case Mouse::MouseDrawFlags::ESPER_DOWN:
+			drawFilledTriangleAux(surface, dst_x, dst_y, 12, 24,  0, 12, 24, 12, esperExitDemoShapeColor);
+			tailRect = Common::Rect(dst_x +  6,  dst_y + 4, dst_x + 18, dst_y + 12);
+			surface.fillRect(tailRect, esperExitDemoShapeColor);
+			break;
+
+		default:
+			debug("Unsupported custom shape %d", drawModeBitFlags &~ 0xEF);
+			break;
+		}
+	} else {
+		const uint8 *src_p = _data + 2 * (src_y * _width + src_x);
+
+		uint16 shpColor = 0;
+		uint32 surfaceColorRGBPrev = 0;
+		uint32 newSurfaceColorRGB = 0;
+		uint8 a, r, g, b;
+		uint8 rPrev, gPrev, bPrev;
+		uint16 rgb16bitPrev = 0;
+		uint16 rgb16bitAdd = 0;
+		for (int yi = 0; yi != rect_h; ++yi) {
+			for (int xi = 0; xi != rect_w; ++xi) {
+				shpColor = READ_LE_UINT16(src_p);
+				src_p += 2;
+
+				getGameDataColor(shpColor, a, r, g, b);
+
+				if (!a) {
+					// Ignore the alpha in the output as it is inversed in the input
+					void *dstPtr = surface.getBasePtr(CLIP(dst_x + xi, 0, surface.w - 1), CLIP(dst_y + yi, 0, surface.h - 1));
+					if (drawModeBitFlags & Mouse::MouseDrawFlags::SPECIAL) {
+						// It seems that the additive mode was supposed to be used only for cursor shapes
+						// From testing, the only cursor shape that seems to work with it is the green rotating cursor
+						// We add extra code here to cover the cases of the beta crosshairs cursor
+						// being drawn a different color based on bullet power
+						// The code for creating the specific color is custom.
+						if (drawModeBitFlags & Mouse::MouseDrawFlags::REDCROSSHAIRS) {
+							newSurfaceColorRGB = surface.format.RGBToColor((b & 0x8B) | (g >> 1), 0, 0);
+						} else if (drawModeBitFlags & Mouse::MouseDrawFlags::YELLOWCROSSHAIRS) {
+							newSurfaceColorRGB = surface.format.RGBToColor(b & 0xDF, (b & 0xA5) | (g >> 1), 0);
+						} else if (drawModeBitFlags & Mouse::MouseDrawFlags::BLUECROSSHAIRS) {
 							newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
+						} else {
+							// Additive modes
+							getPixel(surface, dstPtr, surfaceColorRGBPrev);
+							if (drawModeBitFlags & Mouse::MouseDrawFlags::ADDITIVE_MODE0) {
+								// This code makes the cursor semi-transparent
+								// but it may not be what the disassembly of the original was going for.
+								newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
+								newSurfaceColorRGB = (((uint16)surfaceColorRGBPrev >> 1) & 0xFBEF)
+								                    + (((uint16)newSurfaceColorRGB >> 1) & 0xFBEF);
+							} else if (drawModeBitFlags & Mouse::MouseDrawFlags::ADDITIVE_MODE1) {
+								// This code may be closer to what the disassembly of the original was doing
+								// for additive draw mode but it doesn't look well.
+								surface.format.colorToRGB(surfaceColorRGBPrev, rPrev, gPrev, bPrev);
+								rgb16bitPrev = (  ((uint16)(rPrev >> 3) << 10)
+								                | ((uint16)(gPrev >> 3) <<  5)
+								                | ((uint16)(bPrev >> 3)));
+								rgb16bitAdd = (((uint16)rgb16bitPrev >> 1) & 0xFBEF)
+								             + ((shpColor >> 1) & 0xFBEF);
+								getGameDataColor(rgb16bitAdd, a, r, g, b);
+								newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
+							}
 						}
+					} else {
+						newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
 					}
-				} else {
-					newSurfaceColorRGB = surface.format.RGBToColor(r, g, b);
+					drawPixel(surface, dstPtr, newSurfaceColorRGB);
 				}
-				drawPixel(surface, dstPtr, newSurfaceColorRGB);
 			}
+			src_p += 2 * (_width - rect_w);
 		}
-		src_p += 2 * (_width - rect_w);
 	}
 }
 
diff --git a/engines/bladerunner/shape.h b/engines/bladerunner/shape.h
index cb9249f856d..bebca4c72b4 100644
--- a/engines/bladerunner/shape.h
+++ b/engines/bladerunner/shape.h
@@ -47,10 +47,12 @@ class Shape {
 
 	bool load(Common::SeekableReadStream *stream);
 
+	void drawFilledTriangleAux(Graphics::Surface &surface, const int &dst_x, const int &dst_y, int x1, int y1, int x2, int y2, int x3, int y3, uint32 colorRGB) const;
+
 public:
 	~Shape();
 
-	void draw(Graphics::Surface &surface, int x, int y, uint8 drawModeBitFlags = 0) const;
+	void draw(Graphics::Surface &surface, int x, int y, uint16 drawModeBitFlags = 0) const;
 
 	int getWidth() const { return _width; }
 	int getHeight() const { return _height; }


Commit: 4669227324e66c06c1d4d933c33edbda946ef889
    https://github.com/scummvm/scummvm/commit/4669227324e66c06c1d4d933c33edbda946ef889
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:18:33+03:00

Commit Message:
BLADERUNNER: Fix regression in zbuffer

Spotted in transitions to BB51, cause by bad memcpy size copied

Changed paths:
    engines/bladerunner/zbuffer.cpp


diff --git a/engines/bladerunner/zbuffer.cpp b/engines/bladerunner/zbuffer.cpp
index 843e6c3b6e7..df961ea704c 100644
--- a/engines/bladerunner/zbuffer.cpp
+++ b/engines/bladerunner/zbuffer.cpp
@@ -166,9 +166,9 @@ bool ZBuffer::decodeData(const uint8 *data, int size) {
 		memcpy(_zbuf2, _zbuf1, 2 * _width * _height);
 	} else {
 		clean();
-		decodePartialZBuffer(data, _zbuf1, size);
-		//decodePartialZBuffer(data, _zbuf2, size);
-		memcpy(_zbuf2, _zbuf1, size);
+		int sizeDecodedUint16 = decodePartialZBuffer(data, _zbuf1, size);
+//		decodePartialZBuffer(data, _zbuf2, size);
+		memcpy(_zbuf2, _zbuf1, sizeDecodedUint16 * sizeof(uint16));
 	}
 
 	return true;


Commit: 66a0193cf500047c46a2ef598d58094192162c46
    https://github.com/scummvm/scummvm/commit/66a0193cf500047c46a2ef598d58094192162c46
Author: antoniou79 (a.antoniou79 at gmail.com)
Date: 2023-07-01T13:18:40+03:00

Commit Message:
BLADERUNNER: Fix overlay queuing in BB07

For the computer monitor when turned on

Changed paths:
    engines/bladerunner/script/scene/bb07.cpp


diff --git a/engines/bladerunner/script/scene/bb07.cpp b/engines/bladerunner/script/scene/bb07.cpp
index 7c45387e16e..56039b6ce1d 100644
--- a/engines/bladerunner/script/scene/bb07.cpp
+++ b/engines/bladerunner/script/scene/bb07.cpp
@@ -153,7 +153,12 @@ bool SceneScriptBB07::ClickedOn2DRegion(int region) {
 			Actor_Face_Heading(kActorMcCoy, 229, false);
 			if (!Game_Flag_Query(kFlagBB07ElectricityOn)) {
 				Ambient_Sounds_Play_Sound(kSfxCOMPON1, 40, 20, 20, 99);
+#if BLADERUNNER_ORIGINAL_BUGS
 				Overlay_Play("BB07OVER", 1, false, true, 0);
+#else
+				// Setting loopForever to true enables queuing (even though the loop will only play once)
+				Overlay_Play("BB07OVER", 1, true, true, 0);
+#endif // BLADERUNNER_ORIGINAL_BUGS
 				Overlay_Play("BB07OVER", 2, true, false, 0);
 				Game_Flag_Set(kFlagBB07ElectricityOn);
 				if (!Game_Flag_Query(kFlagBB07PrinterChecked)) {




More information about the Scummvm-git-logs mailing list