[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