aboutsummaryrefslogtreecommitdiff
path: root/engines/bladerunner
diff options
context:
space:
mode:
authorPeter Kohaut2017-08-24 23:43:47 +0200
committerPeter Kohaut2017-08-24 23:43:47 +0200
commit0da18320af79b6ca8a47248442d106674b5ab860 (patch)
tree504d769edcf92fc4cbceddfbcdda038ecc040ced /engines/bladerunner
parentc9b4089ccb0b60389446e07f7f9421e3a7180129 (diff)
downloadscummvm-rg350-0da18320af79b6ca8a47248442d106674b5ab860.tar.gz
scummvm-rg350-0da18320af79b6ca8a47248442d106674b5ab860.tar.bz2
scummvm-rg350-0da18320af79b6ca8a47248442d106674b5ab860.zip
BLADERUNNER: Added audio mixer & various fixes
Audio mixer is supporting fading and pan animation Added support for skipping speech by pressing Return Added proper support for ambient sounds Added more code to the dialogue menu Added tooltips to the Spinner Fixed calculation of volume and pan of walk steps Code cleanup & formatting
Diffstat (limited to 'engines/bladerunner')
-rw-r--r--engines/bladerunner/actor.cpp24
-rw-r--r--engines/bladerunner/actor_clues.cpp2
-rw-r--r--engines/bladerunner/actor_clues.h6
-rw-r--r--engines/bladerunner/actor_combat.h4
-rw-r--r--engines/bladerunner/ambient_sounds.cpp258
-rw-r--r--engines/bladerunner/ambient_sounds.h79
-rw-r--r--engines/bladerunner/archive.cpp2
-rw-r--r--engines/bladerunner/aud_stream.cpp22
-rw-r--r--engines/bladerunner/aud_stream.h9
-rw-r--r--engines/bladerunner/audio_mixer.cpp191
-rw-r--r--engines/bladerunner/audio_mixer.h80
-rw-r--r--engines/bladerunner/audio_player.cpp164
-rw-r--r--engines/bladerunner/audio_player.h38
-rw-r--r--engines/bladerunner/audio_speech.cpp48
-rw-r--r--engines/bladerunner/audio_speech.h12
-rw-r--r--engines/bladerunner/bladerunner.cpp125
-rw-r--r--engines/bladerunner/bladerunner.h10
-rw-r--r--engines/bladerunner/color.h1
-rw-r--r--engines/bladerunner/dialogue_menu.cpp127
-rw-r--r--engines/bladerunner/dialogue_menu.h31
-rw-r--r--engines/bladerunner/elevator.cpp95
-rw-r--r--engines/bladerunner/font.cpp4
-rw-r--r--engines/bladerunner/font.h1
-rw-r--r--engines/bladerunner/gameflags.cpp2
-rw-r--r--engines/bladerunner/module.mk1
-rw-r--r--engines/bladerunner/mouse.cpp2
-rw-r--r--engines/bladerunner/scene.cpp110
-rw-r--r--engines/bladerunner/scene.h49
-rw-r--r--engines/bladerunner/script/init.cpp20
-rw-r--r--engines/bladerunner/script/script.cpp74
-rw-r--r--engines/bladerunner/script/script.h28
-rw-r--r--engines/bladerunner/settings.h8
-rw-r--r--engines/bladerunner/spinner.cpp144
-rw-r--r--engines/bladerunner/spinner.h18
-rw-r--r--engines/bladerunner/ui_image_picker.cpp148
-rw-r--r--engines/bladerunner/ui_image_picker.h34
-rw-r--r--engines/bladerunner/view.cpp4
-rw-r--r--engines/bladerunner/vqa_player.cpp60
38 files changed, 1390 insertions, 645 deletions
diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp
index 85c5d89240..c29956ca8b 100644
--- a/engines/bladerunner/actor.cpp
+++ b/engines/bladerunner/actor.cpp
@@ -23,7 +23,6 @@
#include "bladerunner/actor.h"
#include "bladerunner/bladerunner.h"
-
#include "bladerunner/actor_clues.h"
#include "bladerunner/actor_combat.h"
#include "bladerunner/actor_walk.h"
@@ -37,6 +36,7 @@
#include "bladerunner/scene_objects.h"
#include "bladerunner/script/scene.h"
#include "bladerunner/script/ai.h"
+#include "bladerunner/set.h"
#include "bladerunner/slice_animations.h"
#include "bladerunner/slice_renderer.h"
#include "bladerunner/waypoints.h"
@@ -767,7 +767,7 @@ void Actor::setBoundingBox(const Vector3 &position, bool retired) {
float Actor::distanceFromView(View *view) const{
float xDist = this->_position.x - view->_cameraPosition.x;
- float zDist = this->_position.z - view->_cameraPosition.z;
+ float zDist = this->_position.z + view->_cameraPosition.z;
return sqrt(xDist * xDist + zDist * zDist);
}
@@ -863,7 +863,7 @@ void Actor::faceHeading(int heading, bool animate) {
}
void Actor::modifyFriendlinessToOther(int otherActorId, signed int change) {
- _friendlinessToOther[otherActorId] = MIN(MAX(_friendlinessToOther[otherActorId] + change, 0), 100);
+ _friendlinessToOther[otherActorId] = CLIP(_friendlinessToOther[otherActorId] + change, 0, 100);
}
void Actor::setFriendlinessToOther(int otherActorId, int friendliness) {
@@ -895,29 +895,29 @@ void Actor::setImmunityToObstacles(bool isImmune) {
}
void Actor::modifyCurrentHP(signed int change) {
- _currentHP = MIN(MAX(_currentHP + change, 0), 100);
+ _currentHP = CLIP(_currentHP + change, 0, 100);
if (_currentHP > 0)
retire(false, 0, 0, -1);
}
void Actor::modifyMaxHP(signed int change) {
- _maxHP = MIN(MAX(_maxHP + change, 0), 100);
+ _maxHP = CLIP(_maxHP + change, 0, 100);
}
void Actor::modifyCombatAggressiveness(signed int change) {
- _combatAggressiveness = MIN(MAX(_combatAggressiveness + change, 0), 100);
+ _combatAggressiveness = CLIP(_combatAggressiveness + change, 0, 100);
}
void Actor::modifyHonesty(signed int change) {
- _honesty = MIN(MAX(_honesty + change, 0), 100);
+ _honesty = CLIP(_honesty + change, 0, 100);
}
void Actor::modifyIntelligence(signed int change) {
- _intelligence = MIN(MAX(_intelligence + change, 0), 100);
+ _intelligence = CLIP(_intelligence + change, 0, 100);
}
void Actor::modifyStability(signed int change) {
- _stability = MIN(MAX(_stability + change, 0), 100);
+ _stability = CLIP(_stability + change, 0, 100);
}
void Actor::setFlagDamageAnimIfMoving(bool value) {
@@ -1043,7 +1043,7 @@ void Actor::speechPlay(int sentenceId, bool voiceOver) {
int screenX = 320; //, screenY = 0;
//TODO: transform to screen space using fov;
balance = 127 * (2 * screenX - 640) / 640;
- balance = MIN(127, MAX(-127, balance));
+ balance = CLIP<int>(balance, -127, 127);
}
_vm->_audioSpeech->playSpeech(name, balance);
@@ -1092,12 +1092,12 @@ void Actor::copyClues(int actorId) {
int Actor::soundVolume() const {
float dist = distanceFromView(_vm->_view);
- return 255.0f * MAX(MIN(dist / 1200.0f, 1.0f), 0.0f);
+ return 35.0f * CLIP(1.0f - (dist / 1200.0f), 0.0f, 1.0f);
}
int Actor::soundBalance() const {
Vector3 screenPosition = _vm->_view->calculateScreenPosition(_position);
- return 127.0f * (MAX(MIN(screenPosition.x / 640.0f, 1.0f), 0.0f) * 2.0f - 1.0f);
+ return 35.0f * (CLIP(screenPosition.x / 640.0f, 0.0f, 1.0f) * 2.0f - 1.0f);
}
bool Actor::walkFindU1(const Vector3 &startPosition, const Vector3 &targetPosition, float size, Vector3 *newDestination) {
diff --git a/engines/bladerunner/actor_clues.cpp b/engines/bladerunner/actor_clues.cpp
index 749dda2b15..cd848f9fbf 100644
--- a/engines/bladerunner/actor_clues.cpp
+++ b/engines/bladerunner/actor_clues.cpp
@@ -22,6 +22,8 @@
#include "bladerunner/actor_clues.h"
+#include "bladerunner/bladerunner.h"
+#include "bladerunner/gameinfo.h"
#include "bladerunner/crimes_database.h"
#include "common/debug.h"
diff --git a/engines/bladerunner/actor_clues.h b/engines/bladerunner/actor_clues.h
index f7ec877ad2..d053ef532b 100644
--- a/engines/bladerunner/actor_clues.h
+++ b/engines/bladerunner/actor_clues.h
@@ -23,12 +23,10 @@
#ifndef BLADERUNNER_ACTOR_CLUES_H
#define BLADERUNNER_ACTOR_CLUES_H
-#include "bladerunner/bladerunner.h"
-
-#include "bladerunner/gameinfo.h"
-
namespace BladeRunner {
+class BladeRunnerEngine;
+
struct ActorClue {
int _clueId;
int _weight;
diff --git a/engines/bladerunner/actor_combat.h b/engines/bladerunner/actor_combat.h
index ee29bf4f0e..3763f46be8 100644
--- a/engines/bladerunner/actor_combat.h
+++ b/engines/bladerunner/actor_combat.h
@@ -23,12 +23,12 @@
#ifndef BLADERUNNER_ACTOR_COMBAT_H
#define BLADERUNNER_ACTOR_COMBAT_H
-#include "bladerunner/bladerunner.h"
-
#include "bladerunner/vector.h"
namespace BladeRunner {
+class BladeRunnerEngine;
+
class ActorCombat {
BladeRunnerEngine *_vm;
diff --git a/engines/bladerunner/ambient_sounds.cpp b/engines/bladerunner/ambient_sounds.cpp
index aaf6c016d3..7790b03506 100644
--- a/engines/bladerunner/ambient_sounds.cpp
+++ b/engines/bladerunner/ambient_sounds.cpp
@@ -34,7 +34,7 @@ namespace BladeRunner {
#define NON_LOOPING_SOUNDS 25
#define LOOPING_SOUNDS 3
-AmbientSounds::AmbientSounds(BladeRunnerEngine *vm) : _vm(vm) {
+AmbientSounds::AmbientSounds(BladeRunnerEngine *vm) : _vm(vm) {
_nonLoopingSounds = new NonLoopingSound[NON_LOOPING_SOUNDS];
_loopingSounds = new LoopingSound[LOOPING_SOUNDS];
_ambientVolume = 65;
@@ -64,45 +64,133 @@ static inline void sort(int &a, int &b) {
}
void AmbientSounds::addSound(
- int id,
- int timeRangeBegin, int timeRangeEnd,
- int volumeRangeBegin, int volumeRangeEnd,
- int unk1RangeBegin, int unk1RangeEnd,
- int unk2RangeBegin, int unk2RangeEnd,
- int priority, int unk3) {
- const char *name = _vm->_gameInfo->getSfxTrack(id);
-
- sort(volumeRangeBegin, volumeRangeEnd);
- sort(unk1RangeBegin, unk1RangeEnd);
- sort(unk2RangeBegin, unk2RangeEnd);
+ int sfxId,
+ int timeMin, int timeMax,
+ int volumeMin, int volumeMax,
+ int panStartMin, int panStartMax,
+ int panEndMin, int panEndMax,
+ int priority, int unk) {
+ const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
+
+ sort(volumeMin, volumeMax);
+ sort(panStartMin, panStartMax);
+ sort(panEndMin, panEndMax);
addSoundByName(
- name,
- timeRangeBegin, timeRangeEnd,
- volumeRangeBegin, volumeRangeEnd,
- unk1RangeBegin, unk1RangeEnd,
- unk2RangeBegin, unk2RangeEnd,
- priority, unk3
- );
+ name,
+ timeMin, timeMax,
+ volumeMin, volumeMax,
+ panStartMin, panStartMax,
+ panEndMin, panEndMax,
+ priority, unk
+ );
}
-void AmbientSounds::addLoopingSound(int sfx_id, int volume, int unk, int fadeInTime) {
- const char *name = _vm->_gameInfo->getSfxTrack(sfx_id);
+void AmbientSounds::removeNonLoopingSound(int sfxId, bool stopPlaying) {
+ const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
+ int32 hash = mix_id(name);
+ int index = findNonLoopingTrackByHash(hash);
+ if (index >= 0) {
+ removeNonLoopingSoundByIndex(index, stopPlaying);
+ }
+}
+
+void AmbientSounds::removeAllNonLoopingSounds(bool stopPlaying) {
+ for (int i = 0; i < NON_LOOPING_SOUNDS; i++) {
+ removeNonLoopingSoundByIndex(i, stopPlaying);
+ }
+}
+
+void AmbientSounds::addSpeech(int actorId, int sentenceId, int timeMin, int timeMax, int volumeMin, int volumeMax, int panStartMin, int panStartMax, int panEndMin, int panEndMax, int priority, int unk) {
+ sort(volumeMin, volumeMax);
+ sort(panStartMin, panStartMax);
+ sort(panEndMin, panEndMax);
+
+ char name[13];
+ sprintf(name, "%02d-%04d.AUD", actorId, sentenceId); //TODO somewhere here should be also language code
+ addSoundByName(name,
+ timeMin, timeMax,
+ volumeMin, volumeMax,
+ panStartMin, panStartMax,
+ panEndMin, panEndMax,
+ priority, unk);
+}
+
+void AmbientSounds::playSound(int sfxId, int volume, int panStart, int panEnd, int priority) {
+ const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
+
+ _vm->_audioPlayer->playAud(name, volume * _ambientVolume / 100, panStart, panEnd, priority, AudioPlayer::OVERRIDE_VOLUME);
+}
+
+void AmbientSounds::addLoopingSound(int sfxId, int volume, int pan, int delay) {
+ const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
int32 hash = mix_id(name);
- if (findLoopingTrackByHash(hash) >= 0)
+ if (findLoopingTrackByHash(hash) >= 0) {
return;
+ }
int i = findAvailableLoopingTrack();
- if (i == -1)
+ if (i == -1) {
return;
+ }
+ LoopingSound &track = _loopingSounds[i];
+
+ track.isActive = true;
+ strcpy(track.name, name);
+ track.hash = hash;
+ track.pan = pan;
+ track.volume = volume;
+
+ int actualVolumeStart = volume * _ambientVolume / 100;
+ int actualVolumeEnd = actualVolumeStart;
+
+ if (delay > 0) {
+ actualVolumeStart = 0;
+ }
+
+ track.audioPlayerTrack = _vm->_audioPlayer->playAud(name, actualVolumeStart, pan, pan, 99, AudioPlayer::LOOP | AudioPlayer::OVERRIDE_VOLUME);
+
+ if (track.audioPlayerTrack == -1) {
+ removeLoopingSoundByIndex(i, 0);
+ } else {
+ if (delay) {
+ _vm->_audioPlayer->adjustVolume(track.audioPlayerTrack, actualVolumeEnd, delay, false);
+ }
+ }
+}
+
+void AmbientSounds::adjustLoopingSound(int sfxId, int volume, int pan, int delay) {
+ const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
+ int32 hash = mix_id(name);
+ int index = findLoopingTrackByHash(hash);
- int actualVolume = volume * _ambientVolume / 100;
+ 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, delay, false);
+ }
+ if (pan != -101) {
+ _loopingSounds[index].pan = pan;
+ _vm->_audioPlayer->adjustPan(_loopingSounds[index].audioPlayerTrack, pan, delay);
+ }
+ }
+}
- int balance = 0;
+void AmbientSounds::removeLoopingSound(int sfxId, int delay) {
+ const char *name = _vm->_gameInfo->getSfxTrack(sfxId);
+ int32 hash = mix_id(name);
+ int index = findLoopingTrackByHash(hash);
+ if (index >= 0) {
+ removeLoopingSoundByIndex(index, delay);
+ }
+}
- _vm->_audioPlayer->playAud(name, actualVolume, balance, balance, 100, AudioPlayer::LOOP | AudioPlayer::OVERRIDE_VOLUME);
+void AmbientSounds::removeAllLoopingSounds(int delay) {
+ for (int i = 0; i < LOOPING_SOUNDS; i++) {
+ removeLoopingSoundByIndex(i, delay);
+ }
}
void AmbientSounds::tick() {
@@ -111,37 +199,38 @@ void AmbientSounds::tick() {
for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) {
NonLoopingSound &track = _nonLoopingSounds[i];
- if (!track.isActive || track.nextPlayTime > now)
+ if (!track.isActive || track.nextPlayTime > now) {
continue;
+ }
- int pan1, pan2;
-
- pan1 = _vm->_rnd.getRandomNumberRng(track.pan1begin, track.pan1end);
- if (track.pan2begin == -101) {
- pan2 = pan1;
+ int panEnd;
+ int panStart = _vm->_rnd.getRandomNumberRng(track.panStartMin, track.panStartMax);
+ if (track.panEndMin == -101) {
+ panEnd = panStart;
} else {
- pan2 = _vm->_rnd.getRandomNumberRng(track.pan2begin, track.pan2end);
+ panEnd = _vm->_rnd.getRandomNumberRng(track.panEndMin, track.panEndMax);
}
- track.volume = _vm->_rnd.getRandomNumberRng(track.volume1, track.volume2);
+ track.volume = _vm->_rnd.getRandomNumberRng(track.volumeMin, track.volumeMax);
- track.audio_player_track = _vm->_audioPlayer->playAud(
- track.name,
- track.volume * _ambientVolume / 100,
- pan1, pan2,
- track.priority,
- AudioPlayer::OVERRIDE_VOLUME
- );
-
- track.nextPlayTime = now + _vm->_rnd.getRandomNumberRng(track.time1, track.time2);
+ track.audioPlayerTrack = _vm->_audioPlayer->playAud(
+ track.name,
+ track.volume * _ambientVolume / 100,
+ panStart,
+ panEnd,
+ track.priority,
+ AudioPlayer::OVERRIDE_VOLUME
+ );
+ track.nextPlayTime = now + _vm->_rnd.getRandomNumberRng(track.timeMin, track.timeMax);
}
}
int AmbientSounds::findAvailableNonLoopingTrack() {
for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) {
- if (!_nonLoopingSounds[i].isActive)
+ if (!_nonLoopingSounds[i].isActive) {
return i;
+ }
}
return -1;
@@ -151,8 +240,9 @@ int AmbientSounds::findNonLoopingTrackByHash(int32 hash) {
for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) {
NonLoopingSound &track = _nonLoopingSounds[i];
- if (track.isActive && track.hash == hash)
+ if (track.isActive && track.hash == hash) {
return i;
+ }
}
return -1;
@@ -160,8 +250,9 @@ int AmbientSounds::findNonLoopingTrackByHash(int32 hash) {
int AmbientSounds::findAvailableLoopingTrack() {
for (int i = 0; i != LOOPING_SOUNDS; ++i) {
- if (!_loopingSounds[i].isActive)
+ if (!_loopingSounds[i].isActive) {
return i;
+ }
}
return -1;
@@ -171,46 +262,77 @@ int AmbientSounds::findLoopingTrackByHash(int32 hash) {
for (int i = 0; i != LOOPING_SOUNDS; ++i) {
LoopingSound &track = _loopingSounds[i];
- if (track.isActive && track.hash == hash)
+ if (track.isActive && track.hash == hash) {
return i;
+ }
}
return -1;
}
void AmbientSounds::addSoundByName(
- const char *name,
- int timeRangeBegin, int timeRangeEnd,
- int volumeRangeBegin, int volumeRangeEnd,
- int pan1begin, int pan1end,
- int pan2begin, int pan2end,
- int priority, int unk3) {
+ const char *name,
+ int timeMin, int timeMax,
+ int volumeMin, int volumeMax,
+ int panStartMin, int panStartMax,
+ int panEndMin, int panEndMax,
+ int priority, int unk) {
if (strlen(name) > 12) {
error("AmbientSounds::addSoundByName: Overlong name '%s'", name);
}
int i = findAvailableNonLoopingTrack();
- if (i < 0)
+ if (i < 0) {
return;
+ }
NonLoopingSound &track = _nonLoopingSounds[i];
- uint32 now = g_system->getMillis();
+ uint32 now = _vm->getTotalPlayTime();
- track.isActive = true;
+ track.isActive = true;
strcpy(track.name, name);
- track.hash = mix_id(name);
- track.time1 = 1000 * timeRangeBegin;
- track.time2 = 1000 * timeRangeEnd;
- track.nextPlayTime = now + _vm->_rnd.getRandomNumberRng(track.time1, track.time2);
- track.volume1 = volumeRangeBegin;
- track.volume2 = volumeRangeEnd;
- track.volume = 0;
- track.pan1begin = pan1begin;
- track.pan1end = pan1end;
- track.pan2begin = pan2begin;
- track.pan2end = pan2end;
- track.priority = priority;
+ track.hash = mix_id(name);
+ track.timeMin = 1000 * timeMin;
+ track.timeMax = 1000 * timeMax;
+ track.nextPlayTime = now + _vm->_rnd.getRandomNumberRng(track.timeMin, track.timeMax);
+ track.volumeMin = volumeMin;
+ track.volumeMax = volumeMax;
+ track.volume = 0;
+ track.panStartMin = panStartMin;
+ track.panStartMax = panStartMax;
+ track.panEndMin = panEndMin;
+ track.panEndMax = panEndMax;
+ track.priority = priority;
+}
+
+void AmbientSounds::removeNonLoopingSoundByIndex(int index, bool stopPlaying) {
+ NonLoopingSound &track = _nonLoopingSounds[index];
+ if (stopPlaying) {
+ if (track.isActive && track.audioPlayerTrack != -1 && _vm->_audioPlayer->isActive(track.audioPlayerTrack)) {
+ _vm->_audioPlayer->stop(track.audioPlayerTrack, stopPlaying);
+ }
+ }
+ track.isActive = false;
+ track.audioPlayerTrack = -1;
+ // track.field_45 = 0;
+}
+
+void AmbientSounds::removeLoopingSoundByIndex(int index, int delay) {
+ LoopingSound &track = _loopingSounds[index];
+ if (track.isActive && track.audioPlayerTrack != -1 && _vm->_audioPlayer->isActive(track.audioPlayerTrack)) {
+ if (delay > 0) {
+ _vm->_audioPlayer->adjustVolume(track.audioPlayerTrack, 0, delay, false);
+ } else {
+ _vm->_audioPlayer->stop(track.audioPlayerTrack, false);
+ }
+ }
+ track.isActive = false;
+ track.name[0] = 0;
+ track.hash = 0;
+ track.audioPlayerTrack = -1;
+ track.volume = 0;
+ track.pan = 0;
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/ambient_sounds.h b/engines/bladerunner/ambient_sounds.h
index e5428e9f80..292d8173f2 100644
--- a/engines/bladerunner/ambient_sounds.h
+++ b/engines/bladerunner/ambient_sounds.h
@@ -30,23 +30,21 @@ namespace BladeRunner {
class BladeRunnerEngine;
class AmbientSounds {
- BladeRunnerEngine *_vm;
-
struct NonLoopingSound {
bool isActive;
char name[13];
int32 hash;
- int32 audio_player_track;
- int32 time1;
- int32 time2;
+ int32 audioPlayerTrack;
+ int32 timeMin;
+ int32 timeMax;
uint32 nextPlayTime;
- int32 volume1;
- int32 volume2;
+ int32 volumeMin;
+ int32 volumeMax;
int32 volume;
- int32 pan1begin;
- int32 pan1end;
- int32 pan2begin;
- int32 pan2end;
+ int32 panStartMin;
+ int32 panStartMax;
+ int32 panEndMin;
+ int32 panEndMax;
int32 priority;
};
@@ -54,9 +52,13 @@ class AmbientSounds {
bool isActive;
char name[13];
int32 hash;
+ int audioPlayerTrack;
int32 volume;
+ int pan;
};
+ BladeRunnerEngine *_vm;
+
NonLoopingSound *_nonLoopingSounds;
LoopingSound *_loopingSounds;
int _ambientVolume;
@@ -66,25 +68,31 @@ public:
~AmbientSounds();
void addSound(
- int id,
- int timeRangeBegin, int timeRangeEnd,
- int volumeRangeBegin, int volumeRangeEnd,
- int pan1begin, int pan1end,
- int pan2begin, int pan2end,
- int priority, int unk3
+ int sfxId,
+ int timeMin, int timeMax,
+ int volumeMin, int volumeMax,
+ int panStartMin, int panStartMax,
+ int panEndMin, int panEndMax,
+ int priority, int unk
);
- // removeSound
- // addSpeechSound
- // removeSpeechSound
- // playSound
- // playSpeech
- // removeAllNonLoopingSounds
-
- // addLoopingSound
- void addLoopingSound(int sfx_id, int volume, int unk, int fadeInTime);
- // adjustLoopingSound
- // removeLoopingSound
- // removeAllLoopingSounds
+ void removeNonLoopingSound(int sfxId, bool stopPlaying);
+ void removeAllNonLoopingSounds(bool stopPlaying);
+
+ void addSpeech(
+ int actorId, int sentenceId,
+ int timeMin, int timeMax,
+ 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);
+
+ void addLoopingSound(int sfxId, int volume, int pan, int delay);
+ void adjustLoopingSound(int sfxId, int volume, int pan, int delay);
+ // it seems there is little confusion in original code about delay parameter,
+ // sometimes it is used as boolean in same way as stopPlaying from non looping
+ void removeLoopingSound(int sfxId, int delay);
+ void removeAllLoopingSounds(int delay);
void tick();
@@ -108,11 +116,14 @@ private:
void addSoundByName(
const char *name,
- int timeRangeBegin, int timeRangeEnd,
- int volumeRangeBegin, int volumeRangeEnd,
- int unk1RangeBegin, int unk1RangeEnd,
- int unk2RangeBegin, int unk2RangeEnd,
- int priority, int unk3);
+ int timeMin, int timeMax,
+ 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, int delay);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/archive.cpp b/engines/bladerunner/archive.cpp
index 005145599d..9c19ced88c 100644
--- a/engines/bladerunner/archive.cpp
+++ b/engines/bladerunner/archive.cpp
@@ -145,7 +145,7 @@ Common::SeekableReadStream *MIXArchive::createReadStreamForMember(const Common::
uint32 i = indexForId(id);
if (i == _entry_count)
- return NULL;
+ return nullptr;
uint32 start = _entries[i].offset + 6 + 12 * _entry_count;
uint32 end = _entries[i].length + start;
diff --git a/engines/bladerunner/aud_stream.cpp b/engines/bladerunner/aud_stream.cpp
index e859b3347e..c74421bbd0 100644
--- a/engines/bladerunner/aud_stream.cpp
+++ b/engines/bladerunner/aud_stream.cpp
@@ -41,11 +41,15 @@ AudStream::AudStream(AudioCache *cache, int32 hash)
void AudStream::init(byte *data) {
_data = data;
- _end = _data + READ_LE_UINT32(_data + 2) + 12;
- assert(_end - _data >= 12);
-
+ _frequency = READ_LE_UINT16(_data);
+ _size = READ_LE_UINT32(_data + 2);
+ _sizeDecompressed = READ_LE_UINT32(_data + 6);
+ _flags = *(_data + 10);
_compressionType = *(_data + 11);
+ _end = _data + _size + 12;
+ assert(_end - _data >= 12);
+
_deafBlockRemain = 0;
_p = _data + 12;
}
@@ -113,4 +117,16 @@ bool AudStream::rewind() {
return true;
}
+int AudStream::getLength()
+{
+ int bytesPerSecond = _frequency;
+ if (_flags & 1) { // 16 bit
+ bytesPerSecond *= 2;
+ }
+ if (_flags & 2) { // stereo
+ bytesPerSecond *= 2;
+ }
+ return (1000 * _sizeDecompressed) / bytesPerSecond;
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/aud_stream.h b/engines/bladerunner/aud_stream.h
index 3279bdada3..f3117d7072 100644
--- a/engines/bladerunner/aud_stream.h
+++ b/engines/bladerunner/aud_stream.h
@@ -39,8 +39,12 @@ class AudStream : public Audio::RewindableAudioStream {
byte *_end;
AudioCache *_cache;
int32 _hash;
- byte _compressionType;
uint16 _deafBlockRemain;
+ uint16 _frequency;
+ uint32 _size;
+ uint32 _sizeDecompressed;
+ byte _flags;
+ byte _compressionType;
ADPCMWestwoodDecoder _decoder;
@@ -53,9 +57,10 @@ public:
int readBuffer(int16 *buffer, const int numSamples);
bool isStereo() const { return false; }
- int getRate() const { return READ_LE_UINT16(_data); };
+ int getRate() const { return _frequency; };
bool endOfData() const { return _p == _end; }
bool rewind();
+ int getLength();
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/audio_mixer.cpp b/engines/bladerunner/audio_mixer.cpp
new file mode 100644
index 0000000000..0bd7b04b89
--- /dev/null
+++ b/engines/bladerunner/audio_mixer.cpp
@@ -0,0 +1,191 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "bladerunner/audio_mixer.h"
+
+#include "bladerunner/bladerunner.h"
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+
+#include "common/timer.h"
+
+namespace BladeRunner {
+AudioMixer::AudioMixer(BladeRunnerEngine *vm):
+ _vm(vm)
+{
+ for (int i = 0; i < kAudioMixerChannels; i++) {
+ _channels[i].isPresent = false;
+ }
+ _vm->getTimerManager()->installTimerProc(timerCallback, 25 * 1000 , this, "BladeRunnerAudioMixerTimer");
+}
+
+AudioMixer::~AudioMixer() {
+ for (int i = 0; i < kAudioMixerChannels; i++) {
+ stop(i, 0);
+ }
+ _vm->getTimerManager()->removeTimerProc(timerCallback);
+}
+
+int AudioMixer::playStream(Audio::Mixer::SoundType type, Audio::RewindableAudioStream *stream, int priority, bool loop, int volume, int pan, void (*endCallback)(int, void*), void *callbackData) {
+ Common::StackLock lock(_mutex);
+
+ int channel = -1;
+ int lowestPriority = 1000000;
+ int lowestPriorityChannel = -1;
+ for (int i = 0; i < kAudioMixerChannels; i++) {
+ if (!_channels[i].isPresent) {
+ channel = i;
+ break;
+ }
+ if (_channels[i].priority < lowestPriority) {
+ lowestPriority = _channels[i].priority;
+ lowestPriorityChannel = i;
+ }
+ }
+ if (channel == -1) {
+ if (priority < lowestPriority) {
+ return -1;
+ }
+ stop(lowestPriorityChannel, 0);
+ channel = lowestPriorityChannel;
+ }
+
+ _channels[channel].isPresent = true;
+ _channels[channel].stream = stream;
+ _channels[channel].priority = priority;
+ _channels[channel].loop = loop;
+ _channels[channel].volume = volume;
+ _channels[channel].volumeTarget = 0;
+ _channels[channel].volumeDelta = 0;
+ _channels[channel].pan = pan;
+ _channels[channel].panTarget = 0;
+ _channels[channel].panDelta = 0;
+ _channels[channel].endCallback = endCallback;
+ _channels[channel].callbackData = callbackData;
+
+
+ Audio::AudioStream* audioStream = stream;
+
+ if (loop) {
+ audioStream = new Audio::LoopingAudioStream(stream, 0, DisposeAfterUse::YES);
+ }
+
+ _vm->_mixer->playStream(
+ type,
+ &_channels[channel].handle,
+ audioStream,
+ -1,
+ volume * 255 / 100,
+ pan * 127 / 100);
+
+ return channel;
+}
+
+void AudioMixer::stop(int channel, int time) {
+ Common::StackLock lock(_mutex);
+
+ if (_channels[channel].isPresent) {
+ if (time) {
+ adjustVolume(channel, 0, time);
+ } else {
+ _channels[channel].isPresent = false;
+ _vm->_mixer->stopHandle(_channels[channel].handle);
+ if (_channels[channel].endCallback != nullptr) {
+ _channels[channel].endCallback(channel, _channels[channel].callbackData);
+ }
+ }
+ }
+}
+
+bool AudioMixer::isActive(int channel) {
+ Common::StackLock lock(_mutex);
+
+ return _channels[channel].isPresent && _vm->_mixer->isSoundHandleActive(_channels[channel].handle);
+}
+
+void AudioMixer::timerCallback(void *self) {
+ ((AudioMixer*)self)->tick();
+}
+
+void AudioMixer::adjustVolume(int channel, int newVolume, int time)
+{
+ Common::StackLock lock(_mutex);
+
+ if (_channels[channel].isPresent) {
+ _channels[channel].volumeTarget = newVolume;
+ _channels[channel].volumeDelta = ((newVolume - _channels[channel].volume) / (time / 60.0f)) / 40.0f;
+ }
+}
+
+void AudioMixer::adjustPan(int channel, int newPan, int 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)) / 40.0f;
+ }
+}
+
+void AudioMixer::tick()
+{
+ Common::StackLock lock(_mutex);
+
+ for (int i = 0; i < kAudioMixerChannels; i++) {
+ Channel *channel = &_channels[i];
+ if (!channel->isPresent) {
+ continue;
+ }
+
+ if (channel->volumeDelta != 0.0f) {
+ channel->volume = CLIP(channel->volume + channel->volumeDelta, 0.0f, 100.0f);
+
+ if ((channel->volumeDelta < 0 && channel->volume <= channel->volumeTarget) || (channel->volumeDelta > 0 && channel->volume >= channel->volumeTarget)) {
+ channel->volumeDelta = 0.0f;
+ }
+
+ _vm->_mixer->setChannelVolume(channel->handle, channel->volume * 255 / 100);
+
+ if (channel->volume <= 0.0f) {
+ stop(i, 0);
+ }
+ }
+
+ if (channel->panDelta != 0.0) {
+ channel->pan = CLIP(channel->pan + channel->panDelta, -100.0f, 100.0f);
+
+ if ((channel->panDelta < 0 && channel->pan <= channel->panTarget) || (channel->panDelta > 0 && channel->pan >= channel->panTarget)) {
+ channel->panDelta = 0.0f;
+ }
+
+ _vm->_mixer->setChannelBalance(channel->handle, channel->pan * 127 / 100);
+ }
+
+ if (!_vm->_mixer->isSoundHandleActive(channel->handle) || channel->stream->endOfStream()) {
+ stop(i, 0);
+ }
+ }
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/audio_mixer.h b/engines/bladerunner/audio_mixer.h
new file mode 100644
index 0000000000..75a0f08201
--- /dev/null
+++ b/engines/bladerunner/audio_mixer.h
@@ -0,0 +1,80 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BLADERUNNER_AUDIO_MIXER_H
+#define BLADERUNNER_AUDIO_MIXER_H
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+
+#include "common/mutex.h"
+
+namespace BladeRunner {
+
+class BladeRunnerEngine;
+
+class AudioMixer {
+ static const int kAudioMixerChannels = 9;
+
+ struct Channel {
+ bool isPresent;
+ int priority;
+ bool loop;
+ Audio::SoundHandle handle;
+ Audio::AudioStream *stream;
+ float volume;
+ float volumeDelta;
+ float volumeTarget;
+ float pan;
+ float panDelta;
+ float panTarget;
+ void (*endCallback)(int channel, void *data);
+ void *callbackData;
+ };
+
+ BladeRunnerEngine *_vm;
+
+ Channel _channels[kAudioMixerChannels];
+ Common::Mutex _mutex;
+
+public:
+ AudioMixer(BladeRunnerEngine *vm);
+ ~AudioMixer();
+
+ int playStream(Audio::Mixer::SoundType type, Audio::RewindableAudioStream *stream, int priority, bool loop, int volume, int pan, void(*onEndCallback)(int, void *), void *callbackData);
+ void stop(int channel, int delay);
+
+ void adjustVolume(int channel, int newVolume, int time);
+ void adjustPan(int channel, int newPan, int time);
+
+ void resume(int channel, int delay);
+ void pause(int channel, int delay);
+
+private:
+ bool isActive(int channel);
+ void tick();
+ static void timerCallback(void *refCon);
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/audio_player.cpp b/engines/bladerunner/audio_player.cpp
index 0c2b747c32..f5ba83c4b3 100644
--- a/engines/bladerunner/audio_player.cpp
+++ b/engines/bladerunner/audio_player.cpp
@@ -20,15 +20,13 @@
*
*/
-#include "audio_player.h"
-
-#include "bladerunner/archive.h"
-#include "bladerunner/aud_stream.h"
+#include "bladerunner/audio_player.h"
#include "bladerunner/bladerunner.h"
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
+#include "bladerunner/archive.h"
+#include "bladerunner/aud_stream.h"
+#include "bladerunner/audio_mixer.h"
#include "common/debug.h"
#include "common/stream.h"
@@ -79,7 +77,7 @@ byte *AudioCache::findByHash(int32 hash) {
}
}
- return NULL;
+ return nullptr;
}
void AudioCache::storeByHash(int32 hash, Common::SeekableReadStream *stream) {
@@ -110,7 +108,7 @@ void AudioCache::incRef(int32 hash) {
return;
}
}
- assert(0 && "AudioCache::incRef: hash not found");
+ assert(false && "AudioCache::incRef: hash not found");
}
void AudioCache::decRef(int32 hash) {
@@ -123,7 +121,7 @@ void AudioCache::decRef(int32 hash) {
return;
}
}
- assert(0 && "AudioCache::decRef: hash not found");
+ assert(false && "AudioCache::decRef: hash not found");
}
AudioPlayer::AudioPlayer(BladeRunnerEngine *vm) : _vm(vm) {
@@ -133,68 +131,111 @@ AudioPlayer::AudioPlayer(BladeRunnerEngine *vm) : _vm(vm) {
_tracks[i].hash = 0;
_tracks[i].priority = 0;
}
+
+ _sfxVolume = 65;
}
AudioPlayer::~AudioPlayer() {
+ stopAll();
delete _cache;
}
-bool AudioPlayer::isTrackActive(Track *track) {
- if (!track->isMaybeActive)
- return false;
+void AudioPlayer::stopAll() {
+ for (int i = 0; i != kTracks; ++i) {
+ stop(i, false);
+ }
+ for (int i = 0; i != kTracks; ++i) {
+ while (isActive(i)) {
+ // wait for all tracks to finish
+ }
+ }
+}
+
+void AudioPlayer::adjustVolume(int track, int volume, int delay, bool overrideVolume) {
+ if (track < 0 || track >= kTracks || !_tracks[track].isActive || _tracks[track].channel == -1) {
+ return;
+ }
+
+ int actualVolume = volume;
+ if (!overrideVolume) {
+ actualVolume = actualVolume * _sfxVolume / 100;
+ }
- return track->isMaybeActive = _vm->_mixer->isSoundHandleActive(track->soundHandle);
+ _tracks[track].volume = volume;
+ _vm->_audioMixer->adjustVolume(_tracks[track].channel, volume, 60 * delay);
}
-void AudioPlayer::stopAll() {
- for (int i = 0; i != TRACKS; ++i) {
- _vm->_mixer->stopHandle(_tracks[i].soundHandle);
+void AudioPlayer::adjustPan(int track, int pan, int delay) {
+ if (track < 0 || track >= kTracks || !_tracks[track].isActive || _tracks[track].channel == -1) {
+ return;
}
+
+ _tracks[track].pan = pan;
+ _vm->_audioMixer->adjustPan(_tracks[track].channel, pan, 60 * delay);
}
-void AudioPlayer::fadeAndStopTrack(Track *track, int time) {
- (void)time;
+//void AudioPlayer::tick() {
+// for (int i = 0; i != 6; ++i) {
+// Track *ti = &_tracks[i];
+// }
+//}
- _vm->_mixer->stopHandle(track->soundHandle);
+void AudioPlayer::remove(int channel) {
+ Common::StackLock lock(_mutex);
+ for (int i = 0; i != kTracks; ++i) {
+ if (_tracks[i].channel == channel) {
+ _tracks[i].isActive = false;
+ _tracks[i].priority = 0;
+ _tracks[i].channel = -1;
+ //_cache->decRef(_tracks[i].hash);
+ break;
+ }
+ }
+}
+
+void AudioPlayer::mixerChannelEnded(int channel, void *data) {
+ AudioPlayer *audioPlayer = (AudioPlayer *)data;
+ audioPlayer->remove(channel);
}
int AudioPlayer::playAud(const Common::String &name, int volume, int panFrom, int panTo, int priority, byte flags) {
/* Find first available track or, alternatively, the lowest priority playing track */
- Track *track = NULL;
- int lowestPriority = 1000000;
- Track *lowestPriorityTrack = NULL;
+ int track = -1;
+ int lowestPriority = 1000000;
+ int lowestPriorityTrack = -1;
for (int i = 0; i != 6; ++i) {
- Track *ti = &_tracks[i];
- if (!isTrackActive(ti)) {
- track = ti;
+ if (!isActive(i)) {
+ track = i;
break;
}
- if (lowestPriorityTrack == NULL || ti->priority < lowestPriority) {
- lowestPriority = ti->priority;
- lowestPriorityTrack = ti;
+ if (lowestPriorityTrack == -1 || _tracks[i].priority < lowestPriority) {
+ lowestPriority = _tracks[i].priority;
+ lowestPriorityTrack = i;
}
}
/* If there's no available track, stop the lowest priority track if it's lower than
* the new priority
*/
- if (track == NULL && lowestPriority < priority) {
- fadeAndStopTrack(lowestPriorityTrack, 1);
+ if (track == -1 && lowestPriority < priority) {
+ stop(lowestPriorityTrack, true);
track = lowestPriorityTrack;
}
/* If there's still no available track, give up */
- if (track == NULL)
+ if (track == -1) {
return -1;
+ }
/* Load audio resource and store in cache. Playback will happen directly from there. */
int32 hash = mix_id(name);
if (!_cache->findByHash(hash)) {
Common::SeekableReadStream *r = _vm->getResourceStream(name);
- if (!r)
+ if (!r) {
return -1;
+ }
int32 size = r->size();
while (!_cache->canAllocate(size)) {
@@ -207,34 +248,55 @@ int AudioPlayer::playAud(const Common::String &name, int volume, int panFrom, in
delete r;
}
- AudStream *audStream = new AudStream(_cache, hash);
+ AudStream *audioStream = new AudStream(_cache, hash);
- Audio::AudioStream *audioStream = audStream;
- if (flags & LOOP) {
- audioStream = new Audio::LoopingAudioStream(audStream, 0, DisposeAfterUse::YES);
+ int actualVolume = volume;
+ if (!(flags & OVERRIDE_VOLUME)) {
+ actualVolume = _sfxVolume * volume / 100;
}
- Audio::SoundHandle soundHandle;
-
// debug("PlayStream: %s", name.c_str());
- int balance = panFrom;
-
- _vm->_mixer->playStream(
+ int channel = _vm->_audioMixer->playStream(
Audio::Mixer::kPlainSoundType,
- &soundHandle,
audioStream,
- -1,
- volume * 255 / 100,
- balance);
+ priority,
+ flags & LOOP,
+ actualVolume,
+ panFrom,
+ mixerChannelEnded,
+ this);
+
+ if (channel == -1) {
+ return -1;
+ }
+
+ if (panFrom != panTo) {
+ _vm->_audioMixer->adjustPan(channel, panTo, (60 * audioStream->getLength()) / 1000);
+ }
+
+ _tracks[track].isActive = true;
+ _tracks[track].channel = channel;
+ _tracks[track].priority = priority;
+ _tracks[track].hash = hash;
+ _tracks[track].volume = actualVolume;
+
+ return track;
+}
+
+bool AudioPlayer::isActive(int track) {
+ Common::StackLock lock(_mutex);
+ if (track < 0 || track >= kTracks) {
+ return false;
+ }
- track->isMaybeActive = true;
- track->soundHandle = soundHandle;
- track->priority = priority;
- track->hash = hash;
- track->volume = volume;
+ return _tracks[track].isActive;
+}
- return track - &_tracks[0];
+void AudioPlayer::stop(int track, bool immediately) {
+ if (isActive(track)) {
+ _vm->_audioMixer->stop(_tracks[track].channel, immediately ? 0 : 60);
+ }
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/audio_player.h b/engines/bladerunner/audio_player.h
index 4260a7b32b..c573c64840 100644
--- a/engines/bladerunner/audio_player.h
+++ b/engines/bladerunner/audio_player.h
@@ -20,22 +20,18 @@
*
*/
-#ifndef BLADERUNNER_AUDIO_H
-#define BLADERUNNER_AUDIO_H
+#ifndef BLADERUNNER_AUDIO_PLAYER_H
+#define BLADERUNNER_AUDIO_PLAYER_H
-#include "audio/mixer.h"
#include "common/array.h"
#include "common/mutex.h"
#include "common/str.h"
-#include "common/types.h"
namespace BladeRunner {
class BladeRunnerEngine;
class AudioCache;
-#define TRACKS 6
-
/*
* This is a poor imitation of Bladerunner's resource cache
*/
@@ -54,6 +50,7 @@ class AudioCache {
uint32 _totalSize;
uint32 _maxSize;
uint32 _accessCounter;
+
public:
AudioCache() :
_totalSize(0),
@@ -72,23 +69,25 @@ public:
};
class AudioPlayer {
- BladeRunnerEngine *_vm;
- AudioCache *_cache;
+ static const int kTracks = 6;
struct Track {
- bool isMaybeActive;
- Audio::SoundHandle soundHandle;
+ bool isActive;
+ int channel;
int priority;
int32 hash;
int volume;
+ int pan;
- Track() : isMaybeActive(false) {}
+ Track() : isActive(false) {}
};
- Track _tracks[TRACKS];
+ BladeRunnerEngine *_vm;
- bool isTrackActive(Track *track);
- void fadeAndStopTrack(Track *track, int time);
+ Common::Mutex _mutex;
+ AudioCache *_cache;
+ Track _tracks[kTracks];
+ int _sfxVolume;
public:
AudioPlayer(BladeRunnerEngine *vm);
@@ -99,9 +98,16 @@ public:
OVERRIDE_VOLUME = 2
};
- int playAud(const Common::String &name, int volume, int panFrom, int panTo, int priority, byte flags = 0);
-
+ int playAud(const Common::String &name, int volume, int panStart, int panEnd, int priority, byte flags = 0);
+ bool isActive(int track);
+ void stop(int track, bool immediately);
void stopAll();
+ void adjustVolume(int track, int volume, int delay, bool overrideVolume);
+ void adjustPan(int track, int pan, int delay);
+
+private:
+ void remove(int channel);
+ static void mixerChannelEnded(int channel, void *data);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/audio_speech.cpp b/engines/bladerunner/audio_speech.cpp
index 2d06025892..7177cf0f9c 100644
--- a/engines/bladerunner/audio_speech.cpp
+++ b/engines/bladerunner/audio_speech.cpp
@@ -23,6 +23,7 @@
#include "bladerunner/audio_speech.h"
#include "bladerunner/aud_stream.h"
+#include "bladerunner/audio_mixer.h"
#include "bladerunner/bladerunner.h"
#include "common/debug.h"
@@ -31,17 +32,29 @@ namespace BladeRunner {
#define BUFFER_SIZE 200000
+void AudioSpeech::ended() {
+ //Common::StackLock lock(_mutex);
+ _isActive = false;
+ _channel = -1;
+}
+
+void AudioSpeech::mixerChannelEnded(int channel, void *data) {
+ AudioSpeech *audioSpeech = (AudioSpeech*)data;
+ audioSpeech->ended();
+}
+
AudioSpeech::AudioSpeech(BladeRunnerEngine *vm) : _vm(vm) {
_volume = 50;
- _isMaybeActive = false;
+ _isActive = false;
_data = new byte[BUFFER_SIZE];
+ _channel = -1;
}
AudioSpeech::~AudioSpeech() {
delete[] _data;
}
-bool AudioSpeech::playSpeech(const char *name, int balance) {
+bool AudioSpeech::playSpeech(const char *name, int pan) {
// debug("AudioSpeech::playSpeech(\"%s\")", name);
Common::ScopedPtr<Common::SeekableReadStream> r(_vm->getResourceStream(name));
@@ -67,28 +80,35 @@ bool AudioSpeech::playSpeech(const char *name, int balance) {
AudStream *audioStream = new AudStream(_data);
- _vm->_mixer->playStream(
- Audio::Mixer::kPlainSoundType,
- &_soundHandle,
+ // TODO: shorty mode - set rate of sound to 33khz
+
+ _channel = _vm->_audioMixer->playStream(
+ Audio::Mixer::kSpeechSoundType,
audioStream,
- -1,
- _volume * 255 / 100,
- balance);
+ 100,
+ false,
+ _volume,
+ pan,
+ mixerChannelEnded,
+ this);
- _isMaybeActive = true;
+ _isActive = true;
return true;
}
void AudioSpeech::stopSpeech() {
- _vm->_mixer->stopHandle(_soundHandle);
+ //Common::StackLock lock(_mutex);
+ if (_channel != -1) {
+ _vm->_audioMixer->stop(_channel, 0);
+ }
}
bool AudioSpeech::isPlaying() {
- if (!_isMaybeActive)
- return false;
-
- return _isMaybeActive = _vm->_mixer->isSoundHandleActive(_soundHandle);
+ if (_channel == -1) {
+ return false;
+ }
+ return _isActive;
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/audio_speech.h b/engines/bladerunner/audio_speech.h
index ae7065865b..f3e4395d5d 100644
--- a/engines/bladerunner/audio_speech.h
+++ b/engines/bladerunner/audio_speech.h
@@ -23,18 +23,18 @@
#ifndef BLADERUNNER_AUDIO_SPEECH_H
#define BLADERUNNER_AUDIO_SPEECH_H
-#include "audio/mixer.h"
+#include "common/types.h"
namespace BladeRunner {
class BladeRunnerEngine;
class AudioSpeech {
-private:
BladeRunnerEngine *_vm;
+
int _volume;
- bool _isMaybeActive;
- Audio::SoundHandle _soundHandle;
+ bool _isActive;
+ int _channel;
byte *_data;
public:
@@ -45,6 +45,10 @@ public:
void stopSpeech();
bool isPlaying();
void setVolume(int volume) { _volume = volume; }
+
+private:
+ void ended();
+ static void mixerChannelEnded(int channel, void *data);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index a3ac82df0e..7fe3f9ed2e 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -25,6 +25,7 @@
#include "bladerunner/actor.h"
#include "bladerunner/adq.h"
#include "bladerunner/ambient_sounds.h"
+#include "bladerunner/audio_mixer.h"
#include "bladerunner/audio_player.h"
#include "bladerunner/audio_speech.h"
#include "bladerunner/chapters.h"
@@ -42,6 +43,7 @@
#include "bladerunner/mouse.h"
#include "bladerunner/outtake.h"
#include "bladerunner/obstacles.h"
+#include "bladerunner/regions.h"
#include "bladerunner/scene.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/script/init.h"
@@ -52,6 +54,7 @@
#include "bladerunner/slice_animations.h"
#include "bladerunner/slice_renderer.h"
#include "bladerunner/spinner.h"
+#include "bladerunner/suspects_database.h"
#include "bladerunner/text_resource.h"
#include "bladerunner/vqa_decoder.h"
#include "bladerunner/waypoints.h"
@@ -65,7 +68,7 @@
#include "engines/util.h"
#include "graphics/pixelformat.h"
-#include "suspects_database.h"
+
namespace BladeRunner {
@@ -207,7 +210,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
_items = new Items(this);
- // Setup sound output
+ _audioMixer = new AudioMixer(this);
_audioPlayer = new AudioPlayer(this);
@@ -290,7 +293,6 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
// TODO: KIA
- // TODO: Spinner Interface
_spinner = new Spinner(this);
_elevator = new Elevator(this);
@@ -436,7 +438,7 @@ void BladeRunnerEngine::shutdown() {
delete _audioPlayer;
- // Shutdown sound output
+ delete _audioMixer;
if (isArchiveOpen("MUSIC.MIX"))
closeArchive("MUSIC.MIX");
@@ -485,7 +487,8 @@ void BladeRunnerEngine::shutdown() {
// TODO: Delete Elevators
- // TODO: Delete Spinner Interface
+ delete _spinner;
+ _spinner = nullptr;
// TODO: Delete KIA
@@ -586,9 +589,15 @@ void BladeRunnerEngine::gameTick() {
if (_gameIsRunning && _windowIsActive) {
// TODO: Only run if not in Kia, script, nor AI
- _settings->openNewScene();
+ if (!_sceneScript->IsInsideScript() && !_aiScripts->IsInsideScript()) {
+ _settings->openNewScene();
+ }
// TODO: Autosave
+
+ //probably not needed, this version of tick is just loading data from buffer
+ //_audioMixer->tick();
+
// TODO: Kia
if (_spinner->isOpen()) {
@@ -664,14 +673,13 @@ void BladeRunnerEngine::gameTick() {
if (_dialogueMenu->isVisible()) {
_dialogueMenu->tick(p.x, p.y);
- _dialogueMenu->draw();
+ _dialogueMenu->draw(_surfaceGame);
}
_mouse->tick(p.x, p.y);
_mouse->draw(_surfaceGame, p.x, p.y);
// TODO: Process AUD
- // TODO: Footstep sound
if (_walkSoundId >= 0) {
const char *name = _gameInfo->getSfxTrack(_walkSoundId);
@@ -824,21 +832,41 @@ void BladeRunnerEngine::handleEvents() {
Common::EventManager *eventMan = _system->getEventManager();
while (eventMan->pollEvent(event)) {
switch (event.type) {
+ case Common::EVENT_KEYUP:
+ handleKeyUp(event);
+ break;
+ case Common::EVENT_KEYDOWN:
+ handleKeyDown(event);
+ break;
+ case Common::EVENT_LBUTTONUP:
+ handleMouseAction(event.mouse.x, event.mouse.y, true, false);
+ break;
+ case Common::EVENT_RBUTTONUP:
+ case Common::EVENT_MBUTTONUP:
+ handleMouseAction(event.mouse.x, event.mouse.y, false, false);
+ break;
case Common::EVENT_LBUTTONDOWN:
+ handleMouseAction(event.mouse.x, event.mouse.y, true, true);
+ break;
case Common::EVENT_RBUTTONDOWN:
- case Common::EVENT_LBUTTONUP:
- case Common::EVENT_RBUTTONUP: {
- bool buttonLeft = event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP;
- bool buttonDown = event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_RBUTTONDOWN;
-
- handleMouseAction(event.mouse.x, event.mouse.y, buttonLeft, buttonDown);
- }
+ case Common::EVENT_MBUTTONDOWN:
+ handleMouseAction(event.mouse.x, event.mouse.y, false, true);
+ break;
default:
- ;
+ ; // nothing to do
}
}
}
+void BladeRunnerEngine::handleKeyUp(Common::Event &event) {
+ if (event.kbd.keycode == Common::KEYCODE_RETURN) {
+ _speechSkipped = true;
+ }
+}
+
+void BladeRunnerEngine::handleKeyDown(Common::Event &event) {
+}
+
void BladeRunnerEngine::handleMouseAction(int x, int y, bool buttonLeft, bool buttonDown) {
if (!playerHasControl() || _mouse->isDisabled())
return;
@@ -868,40 +896,42 @@ void BladeRunnerEngine::handleMouseAction(int x, int y, bool buttonLeft, bool bu
return;
}
- Vector3 mousePosition = _mouse->getXYZ(x, y);
+ if (buttonLeft && !buttonDown) {
+ Vector3 mousePosition = _mouse->getXYZ(x, y);
- int isClickable;
- int isObstacle;
- int isTarget;
+ int isClickable;
+ int isObstacle;
+ int isTarget;
- int sceneObjectId = _sceneObjects->findByXYZ(&isClickable, &isObstacle, &isTarget, mousePosition.x, mousePosition.y, mousePosition.z, 1, 0, 1);
- int exitIndex = _scene->_exits->getRegionAtXY(x, y);
+ int sceneObjectId = _sceneObjects->findByXYZ(&isClickable, &isObstacle, &isTarget, mousePosition.x, mousePosition.y, mousePosition.z, true, false, true);
+ int exitIndex = _scene->_exits->getRegionAtXY(x, y);
- if ((sceneObjectId < 0 || sceneObjectId > 73) && exitIndex >= 0) {
- handleMouseClickExit(x, y, exitIndex);
- return;
- }
+ if ((sceneObjectId < 0 || sceneObjectId > 73) && exitIndex >= 0) {
+ handleMouseClickExit(x, y, exitIndex);
+ return;
+ }
- int regionIndex = _scene->_regions->getRegionAtXY(x, y);
- if (regionIndex >= 0) {
- handleMouseClickRegion(x, y, regionIndex);
- return;
- }
+ int regionIndex = _scene->_regions->getRegionAtXY(x, y);
+ if (regionIndex >= 0) {
+ handleMouseClickRegion(x, y, regionIndex);
+ return;
+ }
- if (sceneObjectId == -1) {
- bool isRunning;
- _playerActor->loopWalkToXYZ(mousePosition, 0, false, false, false, &isRunning);
- debug("Clicked on nothing %f, %f, %f", mousePosition.x, mousePosition.y, mousePosition.z);
- return;
- } else if (sceneObjectId >= 0 && sceneObjectId <= 73) {
- handleMouseClickActor(x, y, sceneObjectId);
- return;
- } else if (sceneObjectId >= 74 && sceneObjectId <= 197) {
- handleMouseClickItem(x, y, sceneObjectId - 74);
- return;
- } else if (sceneObjectId >= 198 && sceneObjectId <= 293) {
- handleMouseClick3DObject(x, y, sceneObjectId - 198, isClickable, isTarget);
- return;
+ if (sceneObjectId == -1) {
+ bool isRunning;
+ _playerActor->loopWalkToXYZ(mousePosition, 0, false, false, false, &isRunning);
+ debug("Clicked on nothing %f, %f, %f", mousePosition.x, mousePosition.y, mousePosition.z);
+ return;
+ } else if (sceneObjectId >= 0 && sceneObjectId <= 73) {
+ handleMouseClickActor(x, y, sceneObjectId);
+ return;
+ } else if (sceneObjectId >= 74 && sceneObjectId <= 197) {
+ handleMouseClickItem(x, y, sceneObjectId - 74);
+ return;
+ } else if (sceneObjectId >= 198 && sceneObjectId <= 293) {
+ handleMouseClick3DObject(x, y, sceneObjectId - 198, isClickable, isTarget);
+ return;
+ }
}
}
@@ -939,8 +969,9 @@ void BladeRunnerEngine::gameWaitForActive() {
}
void BladeRunnerEngine::loopActorSpeaking() {
- if (!_audioSpeech->isPlaying())
+ if (!_audioSpeech->isPlaying()) {
return;
+ }
playerLosesControl();
@@ -1019,7 +1050,7 @@ Common::SeekableReadStream *BladeRunnerEngine::getResourceStream(const Common::S
}
debug("getResource: Resource %s not found.", name.c_str());
- return 0;
+ return nullptr;
}
bool BladeRunnerEngine::playerHasControl() {
diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h
index d58f9a5601..5164f353dd 100644
--- a/engines/bladerunner/bladerunner.h
+++ b/engines/bladerunner/bladerunner.h
@@ -32,7 +32,10 @@
#include "engines/engine.h"
#include "graphics/surface.h"
-#include "suspects_database.h"
+
+namespace Common {
+struct Event;
+}
namespace BladeRunner {
@@ -49,6 +52,7 @@ class Actor;
class ADQ;
class AIScripts;
class AmbientSounds;
+class AudioMixer;
class AudioPlayer;
class AudioSpeech;
class Chapters;
@@ -72,6 +76,7 @@ class Shape;
class SliceAnimations;
class SliceRenderer;
class Spinner;
+class SuspectsDatabase;
class TextResource;
class View;
class Waypoints;
@@ -89,6 +94,7 @@ public:
ADQ *_adq;
AIScripts *_aiScripts;
AmbientSounds *_ambientSounds;
+ AudioMixer *_audioMixer;
AudioPlayer *_audioPlayer;
AudioSpeech *_audioSpeech;
Chapters *_chapters;
@@ -176,6 +182,8 @@ public:
void gameTick();
void actorsUpdate();
void handleEvents();
+ void handleKeyUp(Common::Event &event);
+ void handleKeyDown(Common::Event &event);
void handleMouseAction(int x, int y, bool buttonLeft, bool buttonDown);
void handleMouseClickExit(int x, int y, int exitIndex);
void handleMouseClickRegion(int x, int y, int regionIndex);
diff --git a/engines/bladerunner/color.h b/engines/bladerunner/color.h
index a93d79b34a..f9796526cb 100644
--- a/engines/bladerunner/color.h
+++ b/engines/bladerunner/color.h
@@ -32,7 +32,6 @@ struct Color {
float g;
float b;
-
Color() {
}
diff --git a/engines/bladerunner/dialogue_menu.cpp b/engines/bladerunner/dialogue_menu.cpp
index 2ef137f9d4..40ec3aee00 100644
--- a/engines/bladerunner/dialogue_menu.cpp
+++ b/engines/bladerunner/dialogue_menu.cpp
@@ -23,13 +23,14 @@
#include "bladerunner/dialogue_menu.h"
#include "bladerunner/bladerunner.h"
-
#include "bladerunner/font.h"
#include "bladerunner/mouse.h"
+#include "bladerunner/settings.h"
#include "bladerunner/shape.h"
#include "bladerunner/text_resource.h"
#include "common/debug.h"
+#include "common/rect.h"
#include "common/util.h"
#define LINE_HEIGHT 9
@@ -87,7 +88,7 @@ bool DialogueMenu::showAt(int x, int y) {
}
bool DialogueMenu::hide() {
- _waitingForInput = 0;
+ _waitingForInput = false;
if (!_isVisible) {
return false;
}
@@ -102,24 +103,27 @@ bool DialogueMenu::clearList() {
return true;
}
-bool DialogueMenu::addToList(int answer, int a3, int a4, int a5, int a6) {
- if (_listSize >= 10)
+bool DialogueMenu::addToList(int answer, bool done, int priorityPolite, int priorityNormal, int prioritySurly) {
+ if (_listSize >= 10) {
return false;
- if (getAnswerIndex(answer) != -1)
+ }
+ if (getAnswerIndex(answer) != -1) {
return false;
+ }
const char *text = _textResource->getText(answer);
- if (!text || strlen(text) >= 50)
+ if (!text || strlen(text) >= 50) {
return false;
+ }
int index = _listSize++;
- strcpy(_items[index].text, text);
+ _items[index].text = text;
_items[index].answerValue = answer;
- _items[index].field_36 = 0;
- _items[index].field_46 = a3;
- _items[index].field_3A = a4;
- _items[index].field_3E = a5;
- _items[index].field_42 = a6;
+ _items[index].colorIntensity = 0;
+ _items[index].isDone = done;
+ _items[index].priorityPolite = priorityPolite;
+ _items[index].priorityNormal = priorityNormal;
+ _items[index].prioritySurly = prioritySurly;
// CHECK(madmoose): BLADE.EXE calls this needlessly
// calculatePosition();
@@ -127,7 +131,7 @@ bool DialogueMenu::addToList(int answer, int a3, int a4, int a5, int a6) {
return true;
}
-bool DialogueMenu::addToListNeverRepeatOnceSelected(int answer, int a3, int a4, int a5) {
+bool DialogueMenu::addToListNeverRepeatOnceSelected(int answer, int priorityPolite, int priorityNormal, int prioritySurly) {
for (int i = 0; i != _neverRepeatListSize; ++i) {
if (answer == _neverRepeatValues[i] && _neverRepeatWasSelected[i]) {
return true;
@@ -137,7 +141,7 @@ bool DialogueMenu::addToListNeverRepeatOnceSelected(int answer, int a3, int a4,
_neverRepeatValues[_neverRepeatListSize] = answer;
_neverRepeatWasSelected[_neverRepeatListSize] = false;
++_neverRepeatListSize;
- return addToList(answer, 0, a3, a4, a5);
+ return addToList(answer, false, priorityPolite, priorityNormal, prioritySurly);
}
int DialogueMenu::queryInput() {
@@ -149,20 +153,22 @@ int DialogueMenu::queryInput() {
_selectedItemIndex = 0;
answer = _items[0].answerValue;
} else if (_listSize == 2) {
- if (_items[0].field_46) {
+ if (_items[0].isDone) {
_selectedItemIndex = 1;
answer = _items[0].answerValue;
- } else if (_items[0].field_46) {
+ } else if (_items[0].isDone) {
_selectedItemIndex = 0;
answer = _items[1].answerValue;
}
}
if (answer == -1) {
- int agenda = 4; //_vm->_settings.getPlayerAgenda();
- if (agenda == 4) {
+ int agenda = _vm->_settings->getPlayerAgenda();
+ agenda = kPlayerAgendaUserChoice;
+ if (agenda == kPlayerAgendaUserChoice) {
_waitingForInput = true;
do {
+ // TODO: game resuming
// if (!_vm->_gameRunning)
// break;
@@ -176,14 +182,13 @@ int DialogueMenu::queryInput() {
_vm->gameTick();
} while (_waitingForInput);
-
- } else if (agenda == 3) {
+ } else if (agenda == kPlayerAgendaErratic) {
int tries = 0;
bool searching = true;
int i;
do {
i = _vm->_rnd.getRandomNumber(_listSize - 1);
- if (!_items[i].field_46) {
+ if (!_items[i].isDone) {
searching = false;
} else if (++tries > 1000) {
searching = false;
@@ -192,7 +197,21 @@ int DialogueMenu::queryInput() {
} while (searching);
_selectedItemIndex = i;
} else {
- error("unimplemented...");
+ int priority = -1;
+ for (int i = 0; i < _listSize; i++) {
+ int priorityCompare = -1;
+ if (agenda == kPlayerAgendaPolite) {
+ priorityCompare = _items[i].priorityPolite;
+ } else if (agenda == kPlayerAgendaNormal) {
+ priorityCompare = _items[i].priorityNormal;
+ } else if (agenda == kPlayerAgendaSurly) {
+ priorityCompare = _items[i].prioritySurly;
+ }
+ if (priority < priorityCompare) {
+ priority = priorityCompare;
+ _selectedItemIndex = i;
+ }
+ }
}
}
@@ -205,7 +224,7 @@ int DialogueMenu::queryInput() {
}
if (_selectedItemIndex >= 0) {
- debug("DM Query Input: %d %s", answer, _items[_selectedItemIndex].text);
+ debug("DM Query Input: %d %s", answer, _items[_selectedItemIndex].text.c_str());
}
return answer;
@@ -234,18 +253,38 @@ void DialogueMenu::tick(int x, int y) {
_selectedItemIndex = line;
}
-void DialogueMenu::draw() {
- if (!_isVisible || _listSize == 0)
+void DialogueMenu::draw(Graphics::Surface &s) {
+ if (!_isVisible || _listSize == 0) {
return;
+ }
+
+ int fadeInItemIndex = _fadeInItemIndex;
+ if (fadeInItemIndex < listSize()) {
+ ++_fadeInItemIndex;
+ }
for (int i = 0; i != _listSize; ++i) {
+ int targetColorIntensity = 0;
if (i == _selectedItemIndex) {
- _items[i].field_36 = 31;
+ targetColorIntensity = 31;
} else {
- _items[i].field_36 = 16;
+ targetColorIntensity = 16;
+ }
+ if (i > fadeInItemIndex) {
+ targetColorIntensity = 0;
}
- // TODO(madmoose): There's more logic here
+ if (_items[i].colorIntensity < targetColorIntensity) {
+ _items[i].colorIntensity += 4;
+ if(_items[i].colorIntensity > targetColorIntensity) {
+ _items[i].colorIntensity = targetColorIntensity;
+ }
+ } else if (_items[i].colorIntensity > targetColorIntensity) {
+ _items[i].colorIntensity -= 2;
+ if (_items[i].colorIntensity < targetColorIntensity) {
+ _items[i].colorIntensity = targetColorIntensity;
+ }
+ }
}
const int x1 = _screenX;
@@ -253,21 +292,28 @@ void DialogueMenu::draw() {
const int x2 = _screenX + BORDER_SIZE + _maxItemWidth;
const int y2 = _screenY + BORDER_SIZE + _listSize * LINE_HEIGHT;
- Graphics::Surface &s = _vm->_surfaceGame;
-
darkenRect(s, x1 + 8, y1 + 8, x2 + 2, y2 + 2);
+ int x = x1 + BORDER_SIZE;
+ int y = y1 + BORDER_SIZE;
+
+ Common::Point mouse = _vm->getMousePos();
+ if (mouse.x >= x && mouse.x < x2) {
+ s.vLine(mouse.x, y1 + 8, y2 + 2, 0x2108);
+ }
+ if (mouse.y >= y && mouse.y < y2) {
+ s.hLine(x1 + 8, mouse.y, x2 + 2, 0x2108);
+ }
+
_shapes[0].draw(s, x1, y1);
_shapes[3].draw(s, x2, y1);
_shapes[2].draw(s, x1, y2);
_shapes[5].draw(s, x2, y2);
- int x = x1 + BORDER_SIZE;
- int y = y1 + BORDER_SIZE;
for (int i = 0; i != _listSize; ++i) {
_shapes[1].draw(s, x1, y);
_shapes[4].draw(s, x2, y);
- uint16 color = ((_items[i].field_36 >> 1) << 10) | ((_items[i].field_36 >> 1) << 6) | _items[i].field_36;
+ uint16 color = ((_items[i].colorIntensity >> 1) << 10) | ((_items[i].colorIntensity >> 1) << 6) | _items[i].colorIntensity;
_vm->_mainFont->drawColor(_items[i].text, s, x, y, color);
y += LINE_HEIGHT;
}
@@ -307,6 +353,7 @@ void DialogueMenu::calculatePosition(int unusedX, int unusedY) {
_screenX = CLIP(_screenX, 0, 640 - w);
_screenY = CLIP(_screenY, 0, 480 - h);
+ _fadeInItemIndex = 0;
debug("calculatePosition: %d %d %d %d %d", _screenX, _screenY, _centerX, _centerY, _maxItemWidth);
}
@@ -324,13 +371,13 @@ void DialogueMenu::clear() {
_selectedItemIndex = 0;
_listSize = 0;
for (int i = 0; i != 10; ++i) {
- _items[0].text[0] = '\0';
- _items[0].answerValue = -1;
- _items[0].field_36 = 0;
- _items[0].field_42 = -1;
- _items[0].field_3A = -1;
- _items[0].field_3E = -1;
- _items[0].field_46 = 0;
+ _items[i].text.clear();
+ _items[i].answerValue = -1;
+ _items[i].isDone = 0;
+ _items[i].priorityPolite = -1;
+ _items[i].priorityNormal = -1;
+ _items[i].prioritySurly = -1;
+ _items[i].colorIntensity = 0;
}
_neverRepeatListSize = 0;
for (int i = 0; i != 100; ++i) {
diff --git a/engines/bladerunner/dialogue_menu.h b/engines/bladerunner/dialogue_menu.h
index 7a6b99e967..1ab90fdac0 100644
--- a/engines/bladerunner/dialogue_menu.h
+++ b/engines/bladerunner/dialogue_menu.h
@@ -26,7 +26,7 @@
#include "bladerunner/shape.h"
#include "common/array.h"
-
+#include "common/str.h"
#include "graphics/surface.h"
namespace BladeRunner {
@@ -35,13 +35,13 @@ class BladeRunnerEngine;
class TextResource;
struct DialogueItem {
- char text[50];
+ Common::String text;
int answerValue;
- int field_36;
- int field_3A;
- int field_3E;
- int field_42;
- int field_46;
+ int colorIntensity;
+ int priorityPolite;
+ int priorityNormal;
+ int prioritySurly;
+ int isDone;
};
class DialogueMenu {
@@ -67,6 +67,8 @@ class DialogueMenu {
int _maxItemWidth;
DialogueItem _items[10];
+ int _fadeInItemIndex;
+
public:
DialogueMenu(BladeRunnerEngine *vm);
~DialogueMenu();
@@ -74,23 +76,26 @@ public:
bool loadText(const char *name);
bool show();
- bool showAt(int x, int y);
bool hide();
+ bool addToList(int answer, bool done, int priorityPolite, int priorityNormal, int prioritySurly);
+ bool addToListNeverRepeatOnceSelected(int answer, int priorityPolite, int priorityNormal, int prioritySurly);
bool clearList();
- bool addToList(int answer, int a3, int a4, int a5, int a6);
- bool addToListNeverRepeatOnceSelected(int answer, int a3, int a4, int a5);
int queryInput();
int listSize();
bool isVisible();
bool isOpen();
void tick(int x, int y);
- void draw();
+ void draw(Graphics::Surface &s);
+
+ void mouseUp();
+ bool waitingForInput();
+
+private:
+ bool showAt(int x, int y);
int getAnswerIndex(int answer);
const char *getText(int id);
void calculatePosition(int unusedX = 0, int unusedY = 0);
- void mouseUp();
- bool waitingForInput();
void clear();
void reset();
diff --git a/engines/bladerunner/elevator.cpp b/engines/bladerunner/elevator.cpp
index e9b731e17b..99f3160141 100644
--- a/engines/bladerunner/elevator.cpp
+++ b/engines/bladerunner/elevator.cpp
@@ -29,10 +29,12 @@
#include "bladerunner/gameinfo.h"
#include "bladerunner/mouse.h"
#include "bladerunner/shape.h"
+#include "bladerunner/script/script.h"
#include "bladerunner/ui_image_picker.h"
#include "bladerunner/vqa_player.h"
#include "common/rect.h"
+#include "common/str.h"
#include "common/system.h"
namespace BladeRunner {
@@ -73,7 +75,7 @@ int Elevator::activate(int elevatorId) {
return 0;
}
- _vqaPlayer->setLoop(1, -1, 0, nullptr, nullptr);
+ _vqaPlayer->setLoop(1, -1, kLoopSetModeJustStart, nullptr, nullptr);
_vm->_mouse->setCursor(0);
for (int i = 0; i != 16; ++i) {
@@ -86,21 +88,21 @@ int Elevator::activate(int elevatorId) {
if (elevatorId == 1) {
_imagePicker->defineImage(
0,
- 220, 298, 308, 392,
+ Common::Rect(220, 298, 308, 392),
nullptr,
_shapes[11],
_shapes[14],
nullptr);
_imagePicker->defineImage(
1,
- 259, 259, 302, 292,
+ Common::Rect(259, 259, 302, 292),
nullptr,
_shapes[10],
_shapes[13],
nullptr);
_imagePicker->defineImage(
2,
- 227, 398, 301, 434,
+ Common::Rect(227, 398, 301, 434),
nullptr,
_shapes[12],
_shapes[15],
@@ -108,7 +110,7 @@ int Elevator::activate(int elevatorId) {
} else {
_imagePicker->defineImage(
4,
- 395, 131, 448, 164,
+ Common::Rect(395, 131, 448, 164),
nullptr,
_shapes[0],
_shapes[5],
@@ -116,7 +118,7 @@ int Elevator::activate(int elevatorId) {
);
_imagePicker->defineImage(
3,
- 395, 165, 448, 198,
+ Common::Rect(395, 165, 448, 198),
nullptr,
_shapes[1],
_shapes[6],
@@ -124,7 +126,7 @@ int Elevator::activate(int elevatorId) {
);
_imagePicker->defineImage(
5,
- 395, 199, 448, 232,
+ Common::Rect(395, 199, 448, 232),
nullptr,
_shapes[2],
_shapes[7],
@@ -132,7 +134,7 @@ int Elevator::activate(int elevatorId) {
);
_imagePicker->defineImage(
6,
- 395, 233, 448, 264,
+ Common::Rect(395, 233, 448, 264),
nullptr,
_shapes[3],
_shapes[8],
@@ -140,7 +142,7 @@ int Elevator::activate(int elevatorId) {
);
_imagePicker->defineImage(
7,
- 395, 265, 448, 295,
+ Common::Rect(395, 265, 448, 295),
nullptr,
_shapes[4],
_shapes[9],
@@ -148,7 +150,7 @@ int Elevator::activate(int elevatorId) {
);
}
- _imagePicker->setCallbacks(
+ _imagePicker->activate(
elevator_mouseInCallback,
elevator_mouseOutCallback,
elevator_mouseDownCallback,
@@ -165,11 +167,14 @@ int Elevator::activate(int elevatorId) {
_vm->gameTick();
} while (_buttonClicked == -1);
+ _imagePicker->deactivate();
+
_vqaPlayer->close();
delete _vqaPlayer;
- for (int i = 0; i != (int)_shapes.size(); ++i)
+ for (int i = 0; i != (int)_shapes.size(); ++i) {
delete _shapes[i];
+ }
_shapes.clear();
_vm->closeArchive("MODE.MIX");
@@ -191,18 +196,19 @@ bool Elevator::isOpen() const {
}
int Elevator::handleMouseUp(int x, int y) {
- _imagePicker->handleMouseAction(x, y, false, true, 0);
+ _imagePicker->handleMouseAction(x, y, false, true, false);
return false;
}
int Elevator::handleMouseDown(int x, int y) {
- _imagePicker->handleMouseAction(x, y, true, false, 0);
+ _imagePicker->handleMouseAction(x, y, true, false, false);
return false;
}
void Elevator::tick() {
- if (!_vm->_gameIsRunning)
+ if (!_vm->_gameIsRunning) {
return;
+ }
int frame = _vqaPlayer->update();
assert(frame >= -1);
@@ -234,8 +240,8 @@ void Elevator::buttonClick(int buttonId) {
void Elevator::reset() {
_isOpen = false;
- _vqaPlayer = 0;
- _imagePicker = 0;
+ _vqaPlayer = nullptr;
+ _imagePicker = nullptr;
_actorId = -1;
_sentenceId = -1;
_timeSpeakDescription = 0;
@@ -243,33 +249,33 @@ void Elevator::reset() {
void Elevator::buttonFocus(int buttonId) {
switch (buttonId) {
- case 7:
- setupDescription(39, 140);
- break;
- case 6:
- setupDescription(39, 130);
- break;
- case 5:
- setupDescription(39, 120);
- break;
- case 4:
- setupDescription(39, 100);
- break;
- case 3:
- setupDescription(39, 110);
- break;
- case 2:
- setupDescription(39, 130);
- break;
- case 1:
- setupDescription(39, 100);
- break;
- case 0:
- setupDescription(39, 150);
- break;
- default:
- resetDescription();
- break;
+ case 7:
+ setupDescription(kActorAnsweringMachine, 140);
+ break;
+ case 6:
+ setupDescription(kActorAnsweringMachine, 130);
+ break;
+ case 5:
+ setupDescription(kActorAnsweringMachine, 120);
+ break;
+ case 4:
+ setupDescription(kActorAnsweringMachine, 100);
+ break;
+ case 3:
+ setupDescription(kActorAnsweringMachine, 110);
+ break;
+ case 2:
+ setupDescription(kActorAnsweringMachine, 130);
+ break;
+ case 1:
+ setupDescription(kActorAnsweringMachine, 100);
+ break;
+ case 0:
+ setupDescription(kActorAnsweringMachine, 150);
+ break;
+ default:
+ resetDescription();
+ break;
}
}
@@ -289,8 +295,9 @@ void Elevator::resetDescription() {
void Elevator::tickDescription() {
int now = _vm->getTotalPlayTime();
- if (_actorId <= 0 || now < _timeSpeakDescription)
+ if (_actorId <= 0 || now < _timeSpeakDescription) {
return;
+ }
_vm->_actors[_actorId]->speechPlay(_sentenceId, false);
_actorId = -1;
diff --git a/engines/bladerunner/font.cpp b/engines/bladerunner/font.cpp
index 8ab5cfab13..2f56b3f12d 100644
--- a/engines/bladerunner/font.cpp
+++ b/engines/bladerunner/font.cpp
@@ -136,6 +136,10 @@ int Font::getTextWidth(const Common::String &text) {
return totalWidth - _spacing1;
}
+int Font::getTextHeight(const Common::String &text) {
+ return _maxHeight;
+}
+
void Font::reset() {
_maxWidth = 0;
_maxHeight = 0;
diff --git a/engines/bladerunner/font.h b/engines/bladerunner/font.h
index de790b0244..91a8184e4b 100644
--- a/engines/bladerunner/font.h
+++ b/engines/bladerunner/font.h
@@ -71,6 +71,7 @@ public:
void drawColor(const Common::String &text, Graphics::Surface &surface, int x, int y, uint16 color);
int getTextWidth(const Common::String &text);
+ int getTextHeight(const Common::String &text);
private:
void reset();
diff --git a/engines/bladerunner/gameflags.cpp b/engines/bladerunner/gameflags.cpp
index 0e04a1c49d..261eff9547 100644
--- a/engines/bladerunner/gameflags.cpp
+++ b/engines/bladerunner/gameflags.cpp
@@ -27,7 +27,7 @@
namespace BladeRunner {
GameFlags::GameFlags()
- : flags(NULL), flagCount(0) {
+ : flags(nullptr), flagCount(0) {
}
GameFlags::~GameFlags() {
diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk
index 5c995984de..61a95352bf 100644
--- a/engines/bladerunner/module.mk
+++ b/engines/bladerunner/module.mk
@@ -10,6 +10,7 @@ MODULE_OBJS = \
ambient_sounds.o \
archive.o \
aud_stream.o \
+ audio_mixer.o \
audio_player.o \
audio_speech.o \
bladerunner.o \
diff --git a/engines/bladerunner/mouse.cpp b/engines/bladerunner/mouse.cpp
index 4c5a9b91a0..42d6ffef09 100644
--- a/engines/bladerunner/mouse.cpp
+++ b/engines/bladerunner/mouse.cpp
@@ -23,9 +23,11 @@
#include "bladerunner/mouse.h"
#include "bladerunner/bladerunner.h"
+#include "bladerunner/regions.h"
#include "bladerunner/scene.h"
#include "bladerunner/scene_objects.h"
#include "bladerunner/shape.h"
+#include "bladerunner/view.h"
#include "bladerunner/zbuffer.h"
#include "graphics/surface.h"
diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp
index f73d0d9882..54bc97abe4 100644
--- a/engines/bladerunner/scene.cpp
+++ b/engines/bladerunner/scene.cpp
@@ -22,23 +22,53 @@
#include "bladerunner/scene.h"
-#include "bladerunner/bladerunner.h"
-
#include "bladerunner/actor.h"
#include "bladerunner/adq.h"
+#include "bladerunner/bladerunner.h"
#include "bladerunner/chapters.h"
#include "bladerunner/gameinfo.h"
#include "bladerunner/items.h"
-#include "bladerunner/settings.h"
#include "bladerunner/scene_objects.h"
-#include "bladerunner/script/scene.h"
+#include "bladerunner/set.h"
+#include "bladerunner/settings.h"
#include "bladerunner/slice_renderer.h"
+#include "bladerunner/regions.h"
+#include "bladerunner/vqa_player.h"
+#include "bladerunner/script/scene.h"
#include "bladerunner/spinner.h"
#include "common/str.h"
namespace BladeRunner {
+Scene::Scene(BladeRunnerEngine *vm)
+ : _vm(vm),
+ _setId(-1),
+ _sceneId(-1),
+ _vqaPlayer(nullptr),
+ _defaultLoop(0),
+ _defaultLoopSet(false),
+ _specialLoopMode(0),
+ _specialLoop(0),
+ _specialLoopAtEnd(false),
+ _introFinished(false),
+ _nextSetId(-1),
+ _nextSceneId(-1),
+ _frame(0),
+ _actorStartFacing(0),
+ _playerWalkedIn(false),
+ _set(new Set(vm)),
+ _regions(new Regions()),
+ _exits(new Regions()) {
+}
+
+Scene::~Scene() {
+ delete _set;
+ delete _regions;
+ delete _exits;
+ delete _vqaPlayer;
+}
+
bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
if (!isLoadingGame) {
_vm->_adq->flush(1, false);
@@ -73,21 +103,25 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
vqaName = Common::String::format("%s_%d.VQA", setName.c_str(), MIN(currentResourceId, 3));
}
- if (_vqaPlayer != nullptr)
+ if (_vqaPlayer != nullptr) {
delete _vqaPlayer;
+ }
_vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceInterface);
Common::String sceneName = _vm->_gameInfo->getSceneName(sceneId);
- if (!_vm->_sceneScript->Open(sceneName))
+ if (!_vm->_sceneScript->Open(sceneName)) {
return false;
+ }
- if (!isLoadingGame)
+ if (!isLoadingGame) {
_vm->_sceneScript->InitializeScene();
+ }
Common::String setResourceName = Common::String::format("%s-MIN.SET", sceneName.c_str());
- if (!_set->open(setResourceName))
+ if (!_set->open(setResourceName)) {
return false;
+ }
_vm->_sliceRenderer->setView(*_vm->_view);
@@ -98,11 +132,12 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
return true;
}
- if (!_vqaPlayer->open(vqaName))
+ if (!_vqaPlayer->open(vqaName)) {
return false;
+ }
if (_specialLoop == -1) {
- _vqaPlayer->setLoop(_defaultLoop, -1, 2, nullptr, nullptr);
+ _vqaPlayer->setLoop(_defaultLoop, -1, kLoopSetModeImmediate, nullptr, nullptr);
_defaultLoopSet = true;
_specialLoopAtEnd = false;
}
@@ -177,21 +212,20 @@ int Scene::advanceFrame() {
_vqaPlayer->updateView(_vm->_view);
_vqaPlayer->updateLights(_vm->_lights);
}
-
- if (_specialLoopMode && _specialLoopMode != 2 && _specialLoopMode != 3) {
- if (_specialLoopMode == 1) {
+ if (_specialLoopMode && _specialLoopMode != kSceneLoopMode2 && _specialLoopMode != kSceneLoopModeSpinner) {
+ if (_specialLoopMode == kSceneLoopModeChangeSet) {
if (frame == -3) { // TODO: when will this happen? bad data in/eof of vqa
_vm->_settings->setNewSetAndScene(_nextSetId, _nextSceneId);
_vm->playerGainsControl();
}
} else if (!_specialLoopAtEnd) {
- _vqaPlayer->setLoop(_defaultLoop + 1, -1, 0, &Scene::loopEndedStatic, this);
+ _vqaPlayer->setLoop(_defaultLoop + 1, -1, kLoopSetModeJustStart, &Scene::loopEndedStatic, this);
_specialLoopAtEnd = true;
}
- } else if (!this->_defaultLoopSet) {
- _vqaPlayer->setLoop(_defaultLoop, -1, 1, &Scene::loopEndedStatic, this);
+ } else if (!_defaultLoopSet) {
+ _vqaPlayer->setLoop(_defaultLoop, -1, kLoopSetModeEnqueue, &Scene::loopEndedStatic, this);
_defaultLoopSet = true;
- if (_specialLoopMode == 0) {
+ if (_specialLoopMode == kSceneLoopModeLoseControl) {
_vm->playerLosesControl();
}
}
@@ -212,27 +246,27 @@ void Scene::loopSetDefault(int loopId) {
_defaultLoop = loopId;
}
-void Scene::loopStartSpecial(int specialLoopMode, int loopId, int flags) {
+void Scene::loopStartSpecial(int specialLoopMode, int loopId, bool immediately) {
_specialLoopMode = specialLoopMode;
_specialLoop = loopId;
- int unknown = -1;
- if (_specialLoopMode == 1) {
- unknown = 0;
+ int repeats = -1;
+ if (_specialLoopMode == kSceneLoopModeChangeSet) {
+ repeats = 0;
}
- int loopMode = 1;
- if (flags) {
- loopMode = 2;
+ int loopMode = kLoopSetModeEnqueue;
+ if (immediately) {
+ loopMode = kLoopSetModeImmediate;
}
- _vqaPlayer->setLoop(_specialLoop, unknown, loopMode, &Scene::loopEndedStatic, this);
- if (_specialLoopMode == 1) {
- this->_nextSetId = _vm->_settings->getNewSet();
- this->_nextSceneId = _vm->_settings->getNewScene();
+ _vqaPlayer->setLoop(_specialLoop, repeats, loopMode, &Scene::loopEndedStatic, this);
+ if (_specialLoopMode == kSceneLoopModeChangeSet) {
+ _nextSetId = _vm->_settings->getNewSet();
+ _nextSceneId = _vm->_settings->getNewScene();
}
- if (flags) {
- this->_specialLoopAtEnd = true;
+ if (immediately) {
+ _specialLoopAtEnd = true;
loopEnded(0, _specialLoop);
}
}
@@ -288,30 +322,30 @@ const char *Scene::objectGetName(int objectId) {
}
void Scene::loopEnded(int frame, int loopId) {
- if (_specialLoopMode && _specialLoopMode != 2 && _specialLoopMode != 3) {
- if (_specialLoopMode == 1) {
+ if (_specialLoopMode && _specialLoopMode != kSceneLoopMode2 && _specialLoopMode != kSceneLoopModeSpinner) {
+ if (_specialLoopMode == kSceneLoopModeChangeSet) {
_defaultLoopSet = true;
_specialLoopAtEnd = false;
_vm->playerLosesControl();
}
} else if (_specialLoopAtEnd) {
- _vqaPlayer->setLoop(_defaultLoop, -1, 1, &Scene::loopEndedStatic, this);
+ _vqaPlayer->setLoop(_defaultLoop, -1, kLoopSetModeEnqueue, &Scene::loopEndedStatic, this);
_defaultLoopSet = true;
_specialLoopAtEnd = false;
- if (_specialLoopMode == 0) {
+ if (_specialLoopMode == kSceneLoopModeLoseControl) {
_vm->playerLosesControl();
}
} else {
- if (_specialLoopMode == 0) {
+ if (_specialLoopMode == kSceneLoopModeLoseControl) {
_vm->playerGainsControl();
_playerWalkedIn = true;
}
- if (_specialLoopMode == 3) {
- _vm->_spinner->setIsOpen();
+ if (_specialLoopMode == kSceneLoopModeSpinner) {
+ _vm->_spinner->open();
}
_specialLoopMode = -1;
_specialLoop = -1;
- _vqaPlayer->setLoop(_defaultLoop + 1, -1, 0, nullptr, nullptr);
+ _vqaPlayer->setLoop(_defaultLoop + 1, -1, kLoopSetModeJustStart, nullptr, nullptr);
_specialLoopAtEnd = true;
}
}
diff --git a/engines/bladerunner/scene.h b/engines/bladerunner/scene.h
index c90258ce53..65ad5bf431 100644
--- a/engines/bladerunner/scene.h
+++ b/engines/bladerunner/scene.h
@@ -23,16 +23,22 @@
#ifndef BLADERUNNER_SCENE_H
#define BLADERUNNER_SCENE_H
-#include "bladerunner/bladerunner.h"
-
-#include "bladerunner/regions.h"
-#include "bladerunner/set.h"
-#include "bladerunner/view.h"
-#include "bladerunner/vqa_player.h"
+#include "bladerunner/vector.h"
namespace BladeRunner {
class BladeRunnerEngine;
+class BoundingBox;
+class Regions;
+class Set;
+class VQAPlayer;
+
+enum SceneLoopMode {
+ kSceneLoopModeLoseControl = 0,
+ kSceneLoopModeChangeSet = 1,
+ kSceneLoopMode2 = 2,
+ kSceneLoopModeSpinner = 3
+};
class Scene {
BladeRunnerEngine *_vm;
@@ -58,42 +64,23 @@ private:
public:
Set *_set;
- Regions* _regions;
- Regions* _exits;
+ Regions *_regions;
+ Regions *_exits;
// _default_loop_id = 0;
// _scene_vqa_frame_number = -1;
public:
- Scene(BladeRunnerEngine *vm)
- : _vm(vm),
- _setId(-1),
- _sceneId(-1),
- _vqaPlayer(nullptr),
- _defaultLoop(0),
- _introFinished(false),
- _nextSetId(-1),
- _nextSceneId(-1),
- _playerWalkedIn(false),
- _set(new Set(vm)),
- _regions(new Regions()),
- _exits(new Regions())
- {}
-
- ~Scene() {
- delete _set;
- delete _regions;
- delete _exits;
- delete _vqaPlayer;
- }
+ Scene(BladeRunnerEngine *vm);
+ ~Scene();
bool open(int setId, int sceneId, bool isLoadingGame);
bool close(bool isLoadingGame);
int advanceFrame();
void setActorStart(Vector3 position, int facing);
- void loopSetDefault(int a);
- void loopStartSpecial(int a, int b, int c);
+ void loopSetDefault(int loopId);
+ void loopStartSpecial(int specialLoopMode, int loopId, bool immediately);
int getSetId() const { return _setId; }
int getSceneId() const { return _sceneId; }
diff --git a/engines/bladerunner/script/init.cpp b/engines/bladerunner/script/init.cpp
index 76f68edee3..ed1140582d 100644
--- a/engines/bladerunner/script/init.cpp
+++ b/engines/bladerunner/script/init.cpp
@@ -2642,16 +2642,16 @@ void ScriptInit::Init_CDB() {
}
void ScriptInit::Init_Spinner() {
- Spinner_Set_Selectable_Destination_Flag(0, 1);
- Spinner_Set_Selectable_Destination_Flag(1, 1);
- Spinner_Set_Selectable_Destination_Flag(2, 1);
- Spinner_Set_Selectable_Destination_Flag(3, 0);
- Spinner_Set_Selectable_Destination_Flag(4, 0);
- Spinner_Set_Selectable_Destination_Flag(5, 0);
- Spinner_Set_Selectable_Destination_Flag(6, 0);
- Spinner_Set_Selectable_Destination_Flag(7, 0);
- Spinner_Set_Selectable_Destination_Flag(8, 0);
- Spinner_Set_Selectable_Destination_Flag(9, 0);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationPoliceStation, true);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationMcCoysApartment, true);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationRuncitersAnimals, true);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationChinatown, false);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationAnimoidRow, false);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationTyrellBuilding, false);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationDNARow, false);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationBradburyBuilding, false);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationNightclubRow, false);
+ Spinner_Set_Selectable_Destination_Flag(kSpinnerDestinationHysteriaHall, false);
}
void ScriptInit::Init_Actor_Friendliness() {
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index c4352706f5..72f4e50a53 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -22,14 +22,13 @@
#include "bladerunner/script/script.h"
-#include "bladerunner/bladerunner.h"
-
#include "bladerunner/actor.h"
#include "bladerunner/actor_combat.h"
#include "bladerunner/adq.h"
#include "bladerunner/ambient_sounds.h"
#include "bladerunner/audio_player.h"
#include "bladerunner/audio_speech.h"
+#include "bladerunner/bladerunner.h"
#include "bladerunner/crimes_database.h"
#include "bladerunner/combat.h"
#include "bladerunner/dialogue_menu.h"
@@ -39,6 +38,8 @@
#include "bladerunner/items.h"
#include "bladerunner/item_pickup.h"
#include "bladerunner/movement_track.h"
+#include "bladerunner/regions.h"
+#include "bladerunner/set.h"
#include "bladerunner/settings.h"
#include "bladerunner/set_effects.h"
#include "bladerunner/scene.h"
@@ -46,6 +47,7 @@
#include "bladerunner/slice_animations.h"
#include "bladerunner/slice_renderer.h"
#include "bladerunner/spinner.h"
+#include "bladerunner/suspects_database.h"
#include "bladerunner/text_resource.h"
#include "bladerunner/vector.h"
#include "bladerunner/waypoints.h"
@@ -499,7 +501,7 @@ bool ScriptBase::Loop_Actor_Walk_To_XYZ(int actorId, float x, float y, float z,
//TODO:
//PlayerActorIdle = 0;
bool isRunning;
- bool result = _vm->_actors[actorId]->loopWalkToXYZ(Vector3(x, y, z), destinationOffset, a5, run, 1, &isRunning);
+ bool result = _vm->_actors[actorId]->loopWalkToXYZ(Vector3(x, y, z), destinationOffset, a5, run, true, &isRunning);
// if (PlayerActorIdle == 1) {
// result = 1;
@@ -829,12 +831,12 @@ void ScriptBase::Scene_Loop_Set_Default(int loopId) {
_vm->_scene->loopSetDefault(loopId);
}
-void ScriptBase::Scene_Loop_Start_Special(int sceneLoopMode, int loopId, int c) {
- if (sceneLoopMode == 1) {
- c = 1;
+void ScriptBase::Scene_Loop_Start_Special(int sceneLoopMode, int loopId, bool immediately) {
+ if (sceneLoopMode == kSceneLoopModeChangeSet) {
+ immediately = true;
}
- _vm->_scene->loopStartSpecial(sceneLoopMode, loopId, c);
- if (sceneLoopMode == 1) {
+ _vm->_scene->loopStartSpecial(sceneLoopMode, loopId, immediately);
+ if (sceneLoopMode == kSceneLoopModeChangeSet) {
_vm->_settings->clearNewSetAndScene();
}
}
@@ -843,54 +845,44 @@ void ScriptBase::Outtake_Play(int id, int noLocalization, int container) {
_vm->outtakePlay(id, noLocalization, container);
}
-void ScriptBase::Ambient_Sounds_Add_Sound(int id, int time1, int time2, int volume1, int volume2, int pan1begin, int pan1end, int pan2begin, int pan2end, int priority, int unk) {
- _vm->_ambientSounds->addSound(id, time1, time2, volume1, volume2, pan1begin, pan1end, pan2begin, pan2end, priority, unk);
+void ScriptBase::Ambient_Sounds_Add_Sound(int sfxId, int timeMin, int timeMax, int volumeMin, int volumeMax, int panStartMin, int panStartMax, int panEndMin, int panEndMax, int priority, int unk) {
+ _vm->_ambientSounds->addSound(sfxId, timeMin, timeMax, volumeMin, volumeMax, panStartMin, panStartMax, panEndMin, panEndMax, priority, unk);
}
-void ScriptBase::Ambient_Sounds_Remove_Sound(int id, bool a2) {
- //TODO
- warning("Ambient_Sounds_Remove_Sound(%d, %d)", id, a2);
+void ScriptBase::Ambient_Sounds_Remove_Sound(int sfxId, bool stopPlaying) {
+ _vm->_ambientSounds->removeNonLoopingSound(sfxId, stopPlaying);
}
-void ScriptBase::Ambient_Sounds_Add_Speech_Sound(int id, int unk1, int time1, int time2, int volume1, int volume2, int pan1begin, int pan1end, int pan2begin, int pan2end, int priority, int unk2){
- //TODO
- warning("Ambient_Sounds_Add_Speech_Sound(%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", id, unk1, time1, time2, volume1, volume2, pan1begin, pan1end, pan2begin, pan2end, priority, unk2);
+void ScriptBase::Ambient_Sounds_Add_Speech_Sound(int actorId, int sentenceId, int timeMin, int timeMax, int volumeMin, int volumeMax, int panStartMin, int panStartMax, int panEndMin, int panEndMax, int priority, int unk){
+ _vm->_ambientSounds->addSpeech(actorId, sentenceId, timeMin, timeMax, volumeMin, volumeMax, panStartMin, panStartMax, panEndMin, panEndMax, priority, unk);
}
// ScriptBase::Ambient_Sounds_Remove_Speech_Sound
-int ScriptBase::Ambient_Sounds_Play_Sound(int a1, int a2, int a3, int a4, int a5) {
- //TODO
- warning("Ambient_Sounds_Remove_Sound(%d, %d, %d, %d, %d)", a1, a2, a3, a4, a5);
- return -1;
+void ScriptBase::Ambient_Sounds_Play_Sound(int sfxId, int volume, int panStart, int panEnd, int priority) {
+ _vm->_ambientSounds->playSound(sfxId, volume, panStart, panEnd, priority);
}
// ScriptBase::Ambient_Sounds_Play_Speech_Sound
-void ScriptBase::Ambient_Sounds_Remove_All_Non_Looping_Sounds(int time) {
- //TODO
- warning("Ambient_Sounds_Remove_All_Non_Looping_Sounds(%d)", time);
- // _vm->_ambientSounds->removeAllNonLoopingSounds(time);
+void ScriptBase::Ambient_Sounds_Remove_All_Non_Looping_Sounds(bool stopPlaying) {
+ _vm->_ambientSounds->removeAllNonLoopingSounds(stopPlaying);
}
-void ScriptBase::Ambient_Sounds_Add_Looping_Sound(int id, int volume, int pan, int fadeInTime) {
- _vm->_ambientSounds->addLoopingSound(id, volume, pan, fadeInTime);
+void ScriptBase::Ambient_Sounds_Add_Looping_Sound(int sfxId, int volume, int pan, int delay) {
+ _vm->_ambientSounds->addLoopingSound(sfxId, volume, pan, delay);
}
-void ScriptBase::Ambient_Sounds_Adjust_Looping_Sound(int id, int panBegin, int panEnd, int a4) {
- //TODO
- warning("Ambient_Sounds_Adjust_Looping_Sound(%d, %d, %d, %d)", id, panBegin, panEnd, a4);
+void ScriptBase::Ambient_Sounds_Adjust_Looping_Sound(int sfxId, int volume, int pan, int delay) {
+ _vm->_ambientSounds->adjustLoopingSound(sfxId, volume, pan, delay);
}
-void ScriptBase::Ambient_Sounds_Remove_Looping_Sound(int id, bool a2){
- //TODO
- warning("Ambient_Sounds_Remove_Looping_Sound(%d, %d)", id, a2);
+void ScriptBase::Ambient_Sounds_Remove_Looping_Sound(int sfxId, int delay){
+ _vm->_ambientSounds->removeLoopingSound(sfxId, delay);
}
-void ScriptBase::Ambient_Sounds_Remove_All_Looping_Sounds(int time) {
- //TODO
- warning("Ambient_Sounds_Remove_All_Looping_Sounds(%d)", time);
- // _vm->_ambientSounds->removeAllLoopingSounds(time);
+void ScriptBase::Ambient_Sounds_Remove_All_Looping_Sounds(int delay) {
+ _vm->_ambientSounds->removeAllLoopingSounds(delay);
}
void ScriptBase::Setup_Scene_Information(float actorX, float actorY, float actorZ, int actorFacing) {
@@ -1067,14 +1059,14 @@ bool ScriptBase::SDB_Add_Other_Clue(int suspectId, int clueId) {
return _vm->_suspectsDatabase->get(suspectId)->addOtherClue(clueId);
}
-void ScriptBase::Spinner_Set_Selectable_Destination_Flag(int a1, int a2) {
- _vm->_spinner->setSelectableDestinationFlag(a1, a2);
+void ScriptBase::Spinner_Set_Selectable_Destination_Flag(int destination, bool selectable) {
+ _vm->_spinner->setSelectableDestinationFlag(destination, selectable);
}
// ScriptBase::Spinner_Query_Selectable_Destination_Flag
-int ScriptBase::Spinner_Interface_Choose_Dest(int a1, int a2) {
- return _vm->_spinner->interfaceChooseDest(a1, a2);
+int ScriptBase::Spinner_Interface_Choose_Dest(int loopId, bool immediately) {
+ return _vm->_spinner->chooseDestination(loopId, immediately);
}
void ScriptBase::ESPER_Flag_To_Activate() {
@@ -1131,7 +1123,7 @@ void ScriptBase::Actor_Retired_Here(int actorId, int width, int height, int reti
Vector3 actorPosition;
actor->getXYZ(&actorPosition.x, &actorPosition.y, &actorPosition.z);
actor->retire(retired, width, height, retiredByActorId);
- actor->setAtXYZ(actorPosition, actor->getFacing(), true, 0, true);
+ actor->setAtXYZ(actorPosition, actor->getFacing(), true, false, true);
_vm->_sceneObjects->setRetired(actorId + SCENE_OBJECTS_ACTORS_OFFSET, true);
}
diff --git a/engines/bladerunner/script/script.h b/engines/bladerunner/script/script.h
index 61cee3aa9b..c282bccd1d 100644
--- a/engines/bladerunner/script/script.h
+++ b/engines/bladerunner/script/script.h
@@ -567,20 +567,20 @@ protected:
bool Music_Is_Playing();
void Overlay_Play(const char *overlay, int a2, int a3, int a4, int a5);
void Overlay_Remove(const char *overlay);
- void Scene_Loop_Set_Default(int);
- void Scene_Loop_Start_Special(int, int, int);
+ void Scene_Loop_Set_Default(int loopId);
+ void Scene_Loop_Start_Special(int sceneLoopMode, int loopId, bool immediately);
void Outtake_Play(int id, int noLocalization = false, int container = -1);
- void Ambient_Sounds_Add_Sound(int id, int time1, int time2, int volume1, int volume2, int pan1begin, int pan1end, int pan2begin, int pan2end, int priority, int unk);
- void Ambient_Sounds_Remove_Sound(int id, bool a2);
- void Ambient_Sounds_Add_Speech_Sound(int id, int unk1, int time1, int time2, int volume1, int volume2, int pan1begin, int pan1end, int pan2begin, int pan2end, int priority, int unk2);
+ void Ambient_Sounds_Add_Sound(int sfxId, int timeMin, int timeMax, int volumeMin, int volumeMax, int panStartMin, int panStartMax, int panEndMin, int panEndMax, int priority, int unk);
+ void Ambient_Sounds_Remove_Sound(int sfxId, bool stopPlaying);
+ void Ambient_Sounds_Add_Speech_Sound(int actorId, int sentenceId, int timeMin, int timeMax, int volumeMin, int volumeMax, int panStartMin, int panStartMax, int panEndMin, int panEndMax, int priority, int unk);
// Ambient_Sounds_Remove_Speech_Sound
- int Ambient_Sounds_Play_Sound(int a1, int a2, int a3, int a4, int a5);
+ void Ambient_Sounds_Play_Sound(int sfxId, int volume, int panStart, int panEnd, int priority);
// Ambient_Sounds_Play_Speech_Sound
- void Ambient_Sounds_Remove_All_Non_Looping_Sounds(int time);
- void Ambient_Sounds_Add_Looping_Sound(int id, int volume, int pan, int fadeInTime);
- void Ambient_Sounds_Adjust_Looping_Sound(int id, int panBegin, int panEnd, int a4);
- void Ambient_Sounds_Remove_Looping_Sound(int id, bool a2);
- void Ambient_Sounds_Remove_All_Looping_Sounds(int time);
+ void Ambient_Sounds_Remove_All_Non_Looping_Sounds(bool stopPlaying);
+ void Ambient_Sounds_Add_Looping_Sound(int sfxId, int volume, int pan, int delay);
+ void Ambient_Sounds_Adjust_Looping_Sound(int sfxId, int volume, int pan, int delay);
+ void Ambient_Sounds_Remove_Looping_Sound(int sfxId, int delay);
+ void Ambient_Sounds_Remove_All_Looping_Sounds(int delay);
void Setup_Scene_Information(float actorX, float actorY, float actorZ, int actorFacing);
bool Dialogue_Menu_Appear(int x, int y);
bool Dialogue_Menu_Disappear();
@@ -625,9 +625,9 @@ protected:
bool SDB_Add_Replicant_Clue(int suspectId, int clueId);
bool SDB_Add_Non_Replicant_Clue(int suspectId, int clueId);
bool SDB_Add_Other_Clue(int suspectId, int clueId);
- void Spinner_Set_Selectable_Destination_Flag(int a1, int a2);
- // Spinner_Query_Selectable_Destination_Flag
- int Spinner_Interface_Choose_Dest(int a1, int a2);
+ void Spinner_Set_Selectable_Destination_Flag(int destination, bool selectable);
+ // Spinner_Query_Selectable_Destination_Flag(int destination);
+ int Spinner_Interface_Choose_Dest(int loopId, bool immediately);
void ESPER_Flag_To_Activate();
bool Voight_Kampff_Activate(int a1, int a2);
int Elevator_Activate(int elevatorId);
diff --git a/engines/bladerunner/settings.h b/engines/bladerunner/settings.h
index de9846a854..105c8fcdca 100644
--- a/engines/bladerunner/settings.h
+++ b/engines/bladerunner/settings.h
@@ -27,6 +27,14 @@ namespace BladeRunner {
class BladeRunnerEngine;
+enum PlayerAgenda {
+ kPlayerAgendaPolite = 0,
+ kPlayerAgendaNormal = 1,
+ kPlayerAgendaSurly = 2,
+ kPlayerAgendaErratic = 3,
+ kPlayerAgendaUserChoice = 4,
+};
+
class Settings {
BladeRunnerEngine *_vm;
diff --git a/engines/bladerunner/spinner.cpp b/engines/bladerunner/spinner.cpp
index 40650cbc22..acee0cb262 100644
--- a/engines/bladerunner/spinner.cpp
+++ b/engines/bladerunner/spinner.cpp
@@ -38,12 +38,19 @@ namespace BladeRunner {
Spinner::Spinner(BladeRunnerEngine *vm) : _vm(vm) {
reset();
- _imagePicker = new UIImagePicker(vm, SPINNER_DESTINATIONS);
+ _imagePicker = new UIImagePicker(vm, kSpinnerDestinations);
+ _vqaPlayer = nullptr;
}
Spinner::~Spinner() {
delete _imagePicker;
+
reset();
+
+ if (_vqaPlayer != nullptr) {
+ _vqaPlayer->close();
+ delete _vqaPlayer;
+ }
}
void Spinner::setSelectableDestinationFlag(int destination, bool selectable) {
@@ -55,38 +62,39 @@ bool Spinner::querySelectableDestinationFlag(int destination) const {
}
SpinnerDestination SpinnerDestinationsNear[] = {
- { 0, 0x0D2, 0x107, 0x107, 0x14C },
- { 1, 0x133, 0x14A, 0x169, 0x17D },
- { 2, 0x152, 0x089, 0x16A, 0x0A9 },
- { 3, 0x0F8, 0x087, 0x121, 0x0A8 },
- { 4, 0x160, 0x0DE, 0x17B, 0x0EE },
- { -1, -1, -1, -1, -1 }
+ { 0, { 210, 263, 263, 332 } },
+ { 1, { 307, 330, 361, 381 } },
+ { 2, { 338, 137, 362, 169 } },
+ { 3, { 248, 135, 289, 168 } },
+ { 4, { 352, 222, 379, 238 } },
+ { -1, { -1,-1,-1,-1 } }
+
};
SpinnerDestination SpinnerDestinationsMedium[] = {
- { 0, 0x0FC, 0x0F2, 0x117, 0x11B },
- { 1, 0x12D, 0x111, 0x148, 0x130 },
- { 2, 0x13F, 0x0B6, 0x150, 0x0C8 },
- { 3, 0x10D, 0x0B5, 0x125, 0x0C8 },
- { 4, 0x145, 0x0E3, 0x159, 0x0F0 },
- { 5, 0x103, 0x04A, 0x17C, 0x077 },
- { 6, 0x0CB, 0x07C, 0x0E0, 0x088 },
- { 7, 0x0C8, 0x093, 0x0DE, 0x0AA },
- { -1, -1, -1, -1, -1 }
+ { 0, { 252, 242, 279, 283 } },
+ { 1, { 301, 273, 328, 304 } },
+ { 2, { 319, 182, 336, 200 } },
+ { 3, { 269, 181, 293, 200 } },
+ { 4, { 325, 227, 345, 240 } },
+ { 5, { 259, 74, 380, 119 } },
+ { 6, { 203, 124, 224, 136 } },
+ { 7, { 200, 147, 222, 170 } },
+ { -1, { -1,-1,-1,-1 } }
};
SpinnerDestination SpinnerDestinationsFar[] = {
- { 0, 0x0DC, 0x0E3, 0x0F6, 0x106 },
- { 1, 0x104, 0x0FC, 0x11E, 0x117 },
- { 2, 0x11E, 0x0B2, 0x12E, 0x0C4 },
- { 3, 0x0F4, 0x0B2, 0x107, 0x0C3 },
- { 4, 0x120, 0x0D8, 0x132, 0x0E4 },
- { 5, 0x0F9, 0x04D, 0x161, 0x07C },
- { 6, 0x0BE, 0x07F, 0x0D0, 0x08A },
- { 7, 0x0B9, 0x095, 0x0CE, 0x0AA },
- { 8, 0x18E, 0x0F9, 0x1A3, 0x10C },
- { 9, 0x186, 0x0DA, 0x1A3, 0x0EC },
- { -1, -1, -1, -1, -1 }
+ { 0, { 220, 227, 246, 262 } },
+ { 1, { 260, 252, 286, 279 } },
+ { 2, { 286, 178, 302, 196 } },
+ { 3, { 244, 178, 263, 195 } },
+ { 4, { 288, 216, 306, 228 } },
+ { 5, { 249, 77, 353, 124 } },
+ { 6, { 190, 127, 208, 138 } },
+ { 7, { 185, 149, 206, 170 } },
+ { 8, { 398, 249, 419, 268 } },
+ { 9, { 390, 218, 419, 236 } },
+ { -1, { -1, -1, -1, -1 } }
};
static void spinner_mouseInCallback(int, void*);
@@ -94,16 +102,17 @@ static void spinner_mouseOutCallback(int, void*);
static void spinner_mouseDownCallback(int, void*);
static void spinner_mouseUpCallback(int, void*);
-int Spinner::interfaceChooseDest(int loopId, int loopFlag) {
+int Spinner::chooseDestination(int loopId, bool immediately) {
_selectedDestination = 0;
- if (!_vm->openArchive("MODE.MIX"))
+ if (!_vm->openArchive("MODE.MIX")) {
return 0;
+ }
if (loopId < 0) {
_isOpen = true;
} else {
_vm->playerLosesControl();
- _vm->_scene->loopStartSpecial(3, loopId, loopFlag);
+ _vm->_scene->loopStartSpecial(kSceneLoopModeSpinner, loopId, immediately);
while (!_isOpen) {
_vm->gameTick();
}
@@ -119,10 +128,11 @@ int Spinner::interfaceChooseDest(int loopId, int loopFlag) {
// Determine which map we need to show to include the active destinations
uint8 mapmask = 0;
- uint8 mapmaskv[SPINNER_DESTINATIONS] = { 1, 1, 1, 1, 1, 3, 3, 3, 7, 7 };
- for (int i = 0; i != SPINNER_DESTINATIONS; ++i) {
- if (_isDestinationSelectable[i])
+ uint8 mapmaskv[kSpinnerDestinations] = { 1, 1, 1, 1, 1, 3, 3, 3, 7, 7 };
+ for (int i = 0; i != kSpinnerDestinations; ++i) {
+ if (_isDestinationSelectable[i]) {
mapmask |= mapmaskv[i];
+ }
}
_destinations = nullptr;
@@ -151,8 +161,8 @@ int Spinner::interfaceChooseDest(int loopId, int loopFlag) {
return -1;
}
- _vqaPlayer->setLoop(spinnerLoopId, -1, 2, nullptr, nullptr);
- _vqaPlayer->setLoop(spinnerLoopId + 1, -1, 0, nullptr, nullptr);
+ _vqaPlayer->setLoop(spinnerLoopId, -1, kLoopSetModeImmediate, nullptr, nullptr);
+ _vqaPlayer->setLoop(spinnerLoopId + 1, -1, kLoopSetModeJustStart, nullptr, nullptr);
for (int j = 0; j != shapeCount; ++j) {
_shapes.push_back(new Shape(_vm));
@@ -162,17 +172,15 @@ int Spinner::interfaceChooseDest(int loopId, int loopFlag) {
_imagePicker->resetImages();
for (SpinnerDestination *dest = _destinations; dest->id != -1; ++dest) {
- if (!_isDestinationSelectable[dest->id])
+ if (!_isDestinationSelectable[dest->id]) {
continue;
+ }
const char *tooltip = _vm->_textSpinnerDestinations->getText(dest->id);
_imagePicker->defineImage(
dest->id,
- dest->left,
- dest->top,
- dest->right,
- dest->bottom,
+ dest->rect,
_shapes[dest->id],
_shapes[dest->id + _shapes.size() / 2],
_shapes[dest->id + _shapes.size() / 2],
@@ -180,7 +188,7 @@ int Spinner::interfaceChooseDest(int loopId, int loopFlag) {
);
}
- _imagePicker->setCallbacks(
+ _imagePicker->activate(
spinner_mouseInCallback,
spinner_mouseOutCallback,
spinner_mouseDownCallback,
@@ -194,14 +202,26 @@ int Spinner::interfaceChooseDest(int loopId, int loopFlag) {
_vm->gameTick();
} while (_selectedDestination == -1);
- // TODO: Unfreeze game time
- _isOpen = false;
- // TODO: _vm->_scene->resume();
+ _imagePicker->deactivate();
- for (int i = 0; i != (int)_shapes.size(); ++i)
+ for (int i = 0; i != (int)_shapes.size(); ++i) {
delete _shapes[i];
+ }
_shapes.clear();
+ if (_vqaPlayer != nullptr) {
+ _vqaPlayer->close();
+ delete _vqaPlayer;
+ _vqaPlayer = nullptr;
+ }
+
+ _vm->closeArchive("MODE.MIX");
+
+ _isOpen = false;
+
+ // TODO: Unfreeze game time
+ // TODO: _vm->_scene->resume();
+
return _selectedDestination;
}
@@ -214,14 +234,13 @@ static void spinner_mouseOutCallback(int, void*) {
static void spinner_mouseDownCallback(int, void*) {
}
-static void spinner_mouseUpCallback(int image, void *data) {
+static void spinner_mouseUpCallback(int image, void *self) {
if (image >= 0 && image < 10) {
- Spinner *spinner = (Spinner *)data;
- spinner->setSelectedDestination(image);
+ ((Spinner *)self)->setSelectedDestination(image);
}
}
-void Spinner::setIsOpen() {
+void Spinner::open() {
_isOpen = true;
}
@@ -230,18 +249,19 @@ bool Spinner::isOpen() const {
}
int Spinner::handleMouseUp(int x, int y) {
- _imagePicker->handleMouseAction(x, y, false, true, 0);
+ _imagePicker->handleMouseAction(x, y, false, true, false);
return false;
}
int Spinner::handleMouseDown(int x, int y) {
- _imagePicker->handleMouseAction(x, y, true, false, 0);
+ _imagePicker->handleMouseAction(x, y, true, false, false);
return false;
}
void Spinner::tick() {
- if (!_vm->_gameIsRunning)
+ if (!_vm->_gameIsRunning) {
return;
+ }
int frame = _vqaPlayer->update();
assert(frame >= -1);
@@ -249,8 +269,6 @@ void Spinner::tick() {
// vqaPlayer renders to _surfaceInterface
blit(_vm->_surfaceInterface, _vm->_surfaceGame);
- _imagePicker->draw(_vm->_surfaceGame);
-
Common::Point p = _vm->getMousePos();
_imagePicker->handleMouseAction(p.x, p.y, false, false, false);
if (_imagePicker->hasHoveredImage()) {
@@ -258,7 +276,9 @@ void Spinner::tick() {
} else {
_vm->_mouse->setCursor(0);
}
+ _imagePicker->draw(_vm->_surfaceGame);
_vm->_mouse->draw(_vm->_surfaceGame, p.x, p.y);
+ _imagePicker->drawTooltip(_vm->_surfaceGame, p.x, p.y);
_vm->blitToScreen(_vm->_surfaceGame);
_vm->_system->delayMillis(10);
@@ -269,8 +289,8 @@ void Spinner::setSelectedDestination(int destination) {
}
void Spinner::reset() {
- for (int i = 0; i != SPINNER_DESTINATIONS; ++i) {
- _isDestinationSelectable[i] = 0;
+ for (int i = 0; i != kSpinnerDestinations; ++i) {
+ _isDestinationSelectable[i] = false;
}
_isOpen = false;
@@ -278,13 +298,21 @@ void Spinner::reset() {
_selectedDestination = -1;
_imagePicker = nullptr;
- for (int i = 0; i != (int)_shapes.size(); ++i)
+ for (int i = 0; i != (int)_shapes.size(); ++i) {
delete _shapes[i];
+ }
_shapes.clear();
}
void Spinner::resume() {
- // TODO
+ if(_vqaPlayer == nullptr) {
+ return;
+ }
+
+ //_vqa->clear();
+ _vqaPlayer->setLoop(0, -1, kLoopSetModeImmediate, nullptr, nullptr);
+ tick();
+ _vqaPlayer->setLoop(1, -1, kLoopSetModeJustStart, nullptr, nullptr);
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/spinner.h b/engines/bladerunner/spinner.h
index 19021fac1a..cfa593b1fb 100644
--- a/engines/bladerunner/spinner.h
+++ b/engines/bladerunner/spinner.h
@@ -24,6 +24,7 @@
#define BLADERUNNER_SPINNER_H
#include "common/array.h"
+#include "common/rect.h"
namespace BladeRunner {
@@ -32,19 +33,16 @@ class Shape;
class VQAPlayer;
class UIImagePicker;
-#define SPINNER_DESTINATIONS 10
-
struct SpinnerDestination {
- int id;
- int left;
- int top;
- int right;
- int bottom;
+ int id;
+ Common::Rect rect;
};
class Spinner {
+ static const int kSpinnerDestinations = 10;
+
BladeRunnerEngine *_vm;
- bool _isDestinationSelectable[SPINNER_DESTINATIONS];
+ bool _isDestinationSelectable[kSpinnerDestinations];
bool _isOpen;
VQAPlayer *_vqaPlayer;
SpinnerDestination *_destinations;
@@ -59,9 +57,9 @@ public:
void setSelectableDestinationFlag(int destination, bool selectable);
bool querySelectableDestinationFlag(int destination) const;
- int interfaceChooseDest(int vqaLoopId, int loopFlag);
+ int chooseDestination(int vqaLoopId, bool immediately);
- void setIsOpen();
+ void open();
bool isOpen() const;
int handleMouseUp(int x, int y);
diff --git a/engines/bladerunner/ui_image_picker.cpp b/engines/bladerunner/ui_image_picker.cpp
index 654129754c..eb0b57505c 100644
--- a/engines/bladerunner/ui_image_picker.cpp
+++ b/engines/bladerunner/ui_image_picker.cpp
@@ -23,33 +23,25 @@
#include "bladerunner/ui_image_picker.h"
#include "bladerunner/bladerunner.h"
-
+#include "bladerunner/font.h"
+#include "bladerunner/mouse.h"
#include "bladerunner/shape.h"
#include "common/rect.h"
+#include "common/str.h"
#include "graphics/surface.h"
namespace BladeRunner {
-struct UIImagePickerImage {
- int active;
- Common::Rect rect;
- Shape *shapeUp;
- Shape *shapeHovered;
- Shape *shapeDown;
- const char *tooltip;
-};
-
UIImagePicker::UIImagePicker(BladeRunnerEngine *vm, int imageCount) : _vm(vm) {
reset();
- _images = new UIImagePickerImage[imageCount];
+ _images.resize(imageCount);
_imageCount = imageCount;
resetImages();
}
UIImagePicker::~UIImagePicker() {
- delete[] _images;
- _images = nullptr;
+ _images.clear();
reset();
}
@@ -59,28 +51,35 @@ void UIImagePicker::resetImages() {
}
}
-bool UIImagePicker::defineImage(int i, int left, int top, int right, int bottom, Shape *shapeUp, Shape *shapeHovered, Shape *shapeDown, const char *tooltip) {
- if (i < 0 || i >= _imageCount || _images[i].active)
+bool UIImagePicker::defineImage(int i, Common::Rect rect, Shape *shapeUp, Shape *shapeHovered, Shape *shapeDown, const char *tooltip) {
+ if (i < 0 || i >= _imageCount || _images[i].active) {
return false;
+ }
UIImagePickerImage &img = _images[i];
- img.rect.left = left;
- img.rect.top = top;
- img.rect.right = right + 1;
- img.rect.bottom = bottom + 1;
+ img.rect = rect;
+ // for rect to be inclusive
+ img.rect.right += 1;
+ img.rect.bottom += 1;
img.shapeUp = shapeUp;
img.shapeHovered = shapeHovered;
img.shapeDown = shapeDown;
img.active = true;
- img.tooltip = tooltip;
+
+ if (tooltip != nullptr) {
+ img.tooltip = tooltip;
+ } else {
+ img.tooltip.clear();
+ }
return true;
}
bool UIImagePicker::setImageTop(int i, int top) {
- if (i < 0 || i >= _imageCount || !_images[i].active)
+ if (i < 0 || i >= _imageCount || !_images[i].active) {
return false;
+ }
UIImagePickerImage &img = _images[i];
@@ -90,8 +89,9 @@ bool UIImagePicker::setImageTop(int i, int top) {
}
bool UIImagePicker::setImageLeft(int i, int left) {
- if (i < 0 || i >= _imageCount || !_images[i].active)
+ if (i < 0 || i >= _imageCount || !_images[i].active) {
return false;
+ }
UIImagePickerImage &img = _images[i];
@@ -101,8 +101,9 @@ bool UIImagePicker::setImageLeft(int i, int left) {
}
bool UIImagePicker::setImageShapeUp(int i, Shape *shapeUp) {
- if (i < 0 || i >= _imageCount || !_images[i].active)
+ if (i < 0 || i >= _imageCount || !_images[i].active) {
return false;
+ }
_images[i].shapeUp = shapeUp;
@@ -110,8 +111,9 @@ bool UIImagePicker::setImageShapeUp(int i, Shape *shapeUp) {
}
bool UIImagePicker::setImageShapeHovered(int i, Shape *shapeHovered) {
- if (i < 0 || i >= _imageCount || !_images[i].active)
+ if (i < 0 || i >= _imageCount || !_images[i].active) {
return false;
+ }
_images[i].shapeHovered = shapeHovered;
@@ -119,8 +121,9 @@ bool UIImagePicker::setImageShapeHovered(int i, Shape *shapeHovered) {
}
bool UIImagePicker::setImageShapeDown(int i, Shape *shapeDown) {
- if (i < 0 || i >= _imageCount || !_images[i].active)
+ if (i < 0 || i >= _imageCount || !_images[i].active) {
return false;
+ }
_images[i].shapeDown = shapeDown;
@@ -128,8 +131,9 @@ bool UIImagePicker::setImageShapeDown(int i, Shape *shapeDown) {
}
bool UIImagePicker::setImageTooltip(int i, const char *tooltip) {
- if (i < 0 || i >= _imageCount || !_images[i].active)
+ if (i < 0 || i >= _imageCount || !_images[i].active) {
return false;
+ }
_images[i].tooltip = tooltip;
@@ -137,18 +141,19 @@ bool UIImagePicker::setImageTooltip(int i, const char *tooltip) {
}
bool UIImagePicker::resetActiveImage(int i) {
- if (i < 0 || i >= _imageCount || !_images[i].active)
+ if (i < 0 || i >= _imageCount || !_images[i].active) {
return false;
+ }
resetImage(i);
return true;
}
-void UIImagePicker::setCallbacks(UIImagePickerCallback *mouseInCallback,
- UIImagePickerCallback *mouseOutCallback,
- UIImagePickerCallback *mouseDownCallback,
- UIImagePickerCallback *mouseUpCallback,
- void *callbackData)
+void UIImagePicker::activate(UIImagePickerCallback *mouseInCallback,
+ UIImagePickerCallback *mouseOutCallback,
+ UIImagePickerCallback *mouseDownCallback,
+ UIImagePickerCallback *mouseUpCallback,
+ void *callbackData)
{
_isButtonDown = false;
_mouseInCallback = mouseInCallback;
@@ -162,19 +167,29 @@ void UIImagePicker::setCallbacks(UIImagePickerCallback *mouseInCallback,
_pressedImageIndex = -1;
}
-void UIImagePicker::resetCallbacks() {}
-
-// TODO
-void UIImagePicker::drawTooltip() {}
+void UIImagePicker::deactivate() {
+ _isButtonDown = false;
+ _mouseInCallback = nullptr;
+ _mouseOutCallback = nullptr;
+ _mouseDownCallback = nullptr;
+ _mouseUpCallback = nullptr;
+ _callbackData = nullptr;
+ _hoverStartTimestamp = 0;
+ _isVisible = false;
+ _hoveredImageIndex = -1;
+ _pressedImageIndex = -1;
+}
void UIImagePicker::draw(Graphics::Surface &surface) {
- if (!_isVisible)
+ if (!_isVisible) {
return;
+ }
for (int i = 0; i != _imageCount; ++i) {
UIImagePickerImage &img = _images[i];
- if (!img.active)
+ if (!img.active) {
continue;
+ }
// TODO: Check interaction with Mouse::isDisabled
if (i == _hoveredImageIndex && i == _pressedImageIndex && _isButtonDown) {
@@ -193,6 +208,47 @@ void UIImagePicker::draw(Graphics::Surface &surface) {
}
}
+void UIImagePicker::drawTooltip(Graphics::Surface &surface, int x, int y) {
+ if (!_isVisible) {
+ return;
+ }
+
+ if (_hoveredImageIndex == -1 || _vm->_mouse->isDisabled() || !_images[_hoveredImageIndex].active || _vm->getTotalPlayTime() < _hoverStartTimestamp + 1000) {
+ return;
+ }
+
+ Common::String &tooltip = _images[_hoveredImageIndex].tooltip;
+ int width = _vm->_mainFont->getTextWidth(tooltip) + 1;
+ int height = _vm->_mainFont->getTextHeight(tooltip) + 1;
+
+ Common::Rect rect;
+ rect.left = x - ((width / 2) + 1);
+ if (rect.left < 0) {
+ rect.left = 0;
+ }
+
+ rect.top = y - 10;
+ if (rect.top < 0) {
+ rect.top = 0;
+ }
+
+ rect.right = width + rect.left + 3;
+ if (rect.right >= 640) {
+ rect.right = 639;
+ rect.left = 636 - width;
+ }
+
+ rect.bottom = height + rect.top + 1;
+ if (rect.bottom >= 480) {
+ rect.bottom = 479;
+ rect.top = 478 - height;
+ }
+
+ surface.fillRect(rect, 0);
+ surface.frameRect(rect, 0x7FFF);
+ _vm->_mainFont->drawColor(tooltip, surface, rect.left + 2, rect.top, 0x7FFF);
+}
+
void UIImagePicker::handleMouseAction(int x, int y, bool down, bool up, bool ignore) {
if (!_isVisible || ignore) {
return;
@@ -210,13 +266,16 @@ void UIImagePicker::handleMouseAction(int x, int y, bool down, bool up, bool ign
if (hoveredImageIndex != _hoveredImageIndex) {
if (!_isButtonDown) {
if (hoveredImageIndex == -1) {
- if (_mouseOutCallback)
+ if (_mouseOutCallback) {
_mouseOutCallback(hoveredImageIndex, _callbackData);
+ }
} else {
- if (_mouseInCallback)
+ if (_mouseInCallback) {
_mouseInCallback(hoveredImageIndex, _callbackData);
+ }
}
}
+ _hoverStartTimestamp = _vm->getTotalPlayTime();
_hoveredImageIndex = hoveredImageIndex;
}
@@ -224,8 +283,11 @@ void UIImagePicker::handleMouseAction(int x, int y, bool down, bool up, bool ign
if (down && !_isButtonDown) {
_isButtonDown = true;
_pressedImageIndex = _hoveredImageIndex;
- if (_mouseDownCallback)
- _mouseDownCallback(_hoveredImageIndex, _callbackData);
+ if (_hoveredImageIndex != 1) {
+ if (_mouseDownCallback) {
+ _mouseDownCallback(_hoveredImageIndex, _callbackData);
+ }
+ }
}
// If mouse button changed to released
@@ -253,7 +315,7 @@ void UIImagePicker::resetImage(int i) {
img.shapeUp = nullptr;
img.shapeHovered = nullptr;
img.shapeDown = nullptr;
- img.tooltip = nullptr;
+ img.tooltip.clear();
}
bool UIImagePicker::hasHoveredImage() {
diff --git a/engines/bladerunner/ui_image_picker.h b/engines/bladerunner/ui_image_picker.h
index c55aa48a64..c06b556c14 100644
--- a/engines/bladerunner/ui_image_picker.h
+++ b/engines/bladerunner/ui_image_picker.h
@@ -23,6 +23,10 @@
#ifndef BLADERUNNER_UI_IMAGE_PICKER_H
#define BLADERUNNER_UI_IMAGE_PICKER_H
+#include "common/array.h"
+#include "common/rect.h"
+#include "common/str.h"
+
namespace Graphics {
struct Surface;
}
@@ -31,10 +35,18 @@ namespace BladeRunner {
class BladeRunnerEngine;
class Shape;
-struct UIImagePickerImage;
typedef void UIImagePickerCallback(int, void*);
+struct UIImagePickerImage {
+ int active;
+ Common::Rect rect;
+ Shape *shapeUp;
+ Shape *shapeHovered;
+ Shape *shapeDown;
+ Common::String tooltip;
+};
+
class UIImagePicker {
BladeRunnerEngine *_vm;
@@ -42,9 +54,9 @@ class UIImagePicker {
int _imageCount;
int _hoveredImageIndex;
int _pressedImageIndex;
- int _hoverStartTimestamp;
+ uint32 _hoverStartTimestamp;
int _isButtonDown;
- UIImagePickerImage *_images;
+ Common::Array<UIImagePickerImage> _images;
UIImagePickerCallback *_mouseInCallback;
UIImagePickerCallback *_mouseOutCallback;
@@ -57,7 +69,7 @@ public:
~UIImagePicker();
void resetImages();
- bool defineImage(int i, int left, int top, int right, int bottom, Shape *shapeUp, Shape *shapeHovered, Shape *shapeDown, const char *tooltip);
+ bool defineImage(int i, Common::Rect rect, Shape *shapeUp, Shape *shapeHovered, Shape *shapeDown, const char *tooltip);
bool setImageTop(int i, int top);
bool setImageLeft(int i, int left);
@@ -68,16 +80,16 @@ public:
bool resetActiveImage(int i);
- void setCallbacks(UIImagePickerCallback *mouseInCallback,
- UIImagePickerCallback *mouseOutCallback,
- UIImagePickerCallback *mouseDownCallback,
- UIImagePickerCallback *mouseUpCallback,
- void *callbackData);
+ void activate(UIImagePickerCallback *mouseInCallback,
+ UIImagePickerCallback *mouseOutCallback,
+ UIImagePickerCallback *mouseDownCallback,
+ UIImagePickerCallback *mouseUpCallback,
+ void *callbackData);
- void resetCallbacks();
+ void deactivate();
- void drawTooltip();
void draw(Graphics::Surface &surface);
+ void drawTooltip(Graphics::Surface &surface, int x, int y);
void handleMouseAction(int x, int y, bool down, bool up, bool ignore = false);
diff --git a/engines/bladerunner/view.cpp b/engines/bladerunner/view.cpp
index ab9eb3e2e6..ed5cef9e3d 100644
--- a/engines/bladerunner/view.cpp
+++ b/engines/bladerunner/view.cpp
@@ -72,8 +72,8 @@ void View::calculateCameraPosition() {
Matrix4x3 invertedMatrix = invertMatrix(_sliceViewMatrix);
_cameraPosition.x = invertedMatrix(0, 3);
- _cameraPosition.y = invertedMatrix(1, 3);
- _cameraPosition.z = invertedMatrix(2, 3);
+ _cameraPosition.z = invertedMatrix(1, 3); // this is not a bug, it Z & Y are inverted in original source
+ _cameraPosition.y = invertedMatrix(2, 3);
}
Vector3 View::calculateScreenPosition(Vector3 worldPosition) {
diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp
index f6eecc85ed..12baa26d76 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -108,42 +108,40 @@ int VQAPlayer::update() {
return -3;
}
+ if (now < _frameNextTime) {
+ return -1;
+ }
+
+ int frame = _frameNext;
+ _decoder.readFrame(_frameNext, 0x2);
+ _decoder.decodeVideoFrame();
-// TODO: preload audio in better way
- int audioPreloadFrames = 3;
-
- if (now >= _frameNextTime) {
- int frame = _frameNext;
- _decoder.readFrame(_frameNext, 0x2);
- _decoder.decodeVideoFrame();
-
- if (_hasAudio) {
- if (!_audioStarted) {
- for (int i = 0; i < audioPreloadFrames; i++) {
- if (_frameNext + i < _frameEnd) {
- _decoder.readFrame(_frameNext + i, 0x1);
- queueAudioFrame(_decoder.decodeAudioFrame());
- }
+ int audioPreloadFrames = 14;
+
+ if (_hasAudio) {
+ if (!_audioStarted) {
+ for (int i = 0; i < audioPreloadFrames; i++) {
+ if (_frameNext + i < _frameEnd) {
+ _decoder.readFrame(_frameNext + i, 0x1);
+ queueAudioFrame(_decoder.decodeAudioFrame());
}
- _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream);
- _audioStarted = true;
- }
- if (_frameNext + audioPreloadFrames < _frameEnd) {
- _decoder.readFrame(_frameNext + audioPreloadFrames, 0x1);
- queueAudioFrame(_decoder.decodeAudioFrame());
}
+ _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _audioStream);
+ _audioStarted = true;
}
- if (_frameNextTime == 0) {
- _frameNextTime = now + 60000 / 15;
- } else {
- _frameNextTime += 60000 / 15;
+ if (_frameNext + audioPreloadFrames < _frameEnd) {
+ _decoder.readFrame(_frameNext + audioPreloadFrames, 0x1);
+ queueAudioFrame(_decoder.decodeAudioFrame());
}
-
- _frameNext++;
- return frame;
+ }
+ if (_frameNextTime == 0) {
+ _frameNextTime = now + 60000 / 15;
+ } else {
+ _frameNextTime += 60000 / 15;
}
- return -1;
+ _frameNext++;
+ return frame;
}
void VQAPlayer::updateZBuffer(ZBuffer *zbuffer) {
@@ -159,7 +157,9 @@ void VQAPlayer::updateLights(Lights *lights) {
}
bool VQAPlayer::setLoop(int loop, int repeatsCount, int loopSetMode, void (*callback)(void *, int, int), void *callbackData) {
+#if 0
debug("VQAPlayer::setBeginAndEndFrameFromLoop(%i, %i, %i), streamLoaded = %i", loop, repeatsCount, loopSetMode, _s != nullptr);
+#endif
if (_s == nullptr) {
_loopInitial = loop;
_repeatsCountInitial = repeatsCount;
@@ -178,7 +178,9 @@ bool VQAPlayer::setLoop(int loop, int repeatsCount, int loopSetMode, void (*call
}
bool VQAPlayer::setBeginAndEndFrame(int begin, int end, int repeatsCount, int loopSetMode, void (*callback)(void *, int, int), void *callbackData) {
+#if 0
debug("VQAPlayer::setBeginAndEndFrame(%i, %i, %i, %i), streamLoaded = %i", begin, end, repeatsCount, loopSetMode, _s != nullptr);
+#endif
if (repeatsCount < 0) {
repeatsCount = -1;