aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;