aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Fach-Pedersen2015-02-06 15:31:43 +0100
committerEugene Sandulenko2016-09-29 22:33:37 +0200
commit74a8b530f196233b287c9775e9c80774c4811058 (patch)
tree8f18bad0598332da0c39528315dfb6866422f4f2
parentc8f5ded6d94863e3c1deb58961e543703bc934f8 (diff)
downloadscummvm-rg350-74a8b530f196233b287c9775e9c80774c4811058.tar.gz
scummvm-rg350-74a8b530f196233b287c9775e9c80774c4811058.tar.bz2
scummvm-rg350-74a8b530f196233b287c9775e9c80774c4811058.zip
BLADERUNNER: Add support for ambient sounds, game flags and variables, and use VQA z-buffer when rendering.
-rw-r--r--engines/bladerunner/ambient_sounds.cpp216
-rw-r--r--engines/bladerunner/ambient_sounds.h120
-rw-r--r--engines/bladerunner/archive.cpp1
-rw-r--r--engines/bladerunner/archive.h2
-rw-r--r--engines/bladerunner/audio_player.cpp368
-rw-r--r--engines/bladerunner/audio_player.h74
-rw-r--r--engines/bladerunner/bladerunner.cpp41
-rw-r--r--engines/bladerunner/bladerunner.h16
-rw-r--r--engines/bladerunner/gameflags.cpp68
-rw-r--r--engines/bladerunner/gameflags.h47
-rw-r--r--engines/bladerunner/gameinfo.cpp2
-rw-r--r--engines/bladerunner/gameinfo.h10
-rw-r--r--engines/bladerunner/module.mk3
-rw-r--r--engines/bladerunner/scene.cpp8
-rw-r--r--engines/bladerunner/scene.h5
-rw-r--r--engines/bladerunner/script/rc01.cpp131
-rw-r--r--engines/bladerunner/script/script.cpp89
-rw-r--r--engines/bladerunner/script/script.h36
-rw-r--r--engines/bladerunner/slice_renderer.cpp20
-rw-r--r--engines/bladerunner/slice_renderer.h4
-rw-r--r--engines/bladerunner/vqa_decoder.cpp66
-rw-r--r--engines/bladerunner/vqa_decoder.h5
-rw-r--r--engines/bladerunner/vqa_player.cpp6
-rw-r--r--engines/bladerunner/vqa_player.h2
24 files changed, 1259 insertions, 81 deletions
diff --git a/engines/bladerunner/ambient_sounds.cpp b/engines/bladerunner/ambient_sounds.cpp
new file mode 100644
index 0000000000..77b819578f
--- /dev/null
+++ b/engines/bladerunner/ambient_sounds.cpp
@@ -0,0 +1,216 @@
+/* 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/ambient_sounds.h"
+
+#include "bladerunner/audio_player.h"
+#include "bladerunner/bladerunner.h"
+#include "bladerunner/gameinfo.h"
+
+#include "common/debug.h"
+#include "common/system.h"
+
+namespace BladeRunner {
+
+#define NON_LOOPING_SOUNDS 25
+#define LOOPING_SOUNDS 3
+
+AmbientSounds::AmbientSounds(BladeRunnerEngine *vm)
+ : _vm(vm)
+{
+ _nonLoopingSounds = new NonLoopingSound[NON_LOOPING_SOUNDS];
+ _loopingSounds = new LoopingSound[LOOPING_SOUNDS];
+ _ambientVolume = 65;
+
+ for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) {
+ NonLoopingSound &track = _nonLoopingSounds[i];
+ track.isActive = false;
+ }
+
+ for (int i = 0; i != LOOPING_SOUNDS; ++i) {
+ LoopingSound &track = _loopingSounds[i];
+ track.isActive = false;
+ }
+}
+
+AmbientSounds::~AmbientSounds() {
+ delete[] _nonLoopingSounds;
+ delete[] _loopingSounds;
+}
+
+static inline void sort(int &a, int &b) {
+ if (a > b) {
+ int t = a;
+ a = b;
+ b = t;
+ }
+}
+
+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);
+
+ addSoundByName(
+ name,
+ timeRangeBegin, timeRangeEnd,
+ volumeRangeBegin, volumeRangeEnd,
+ unk1RangeBegin, unk1RangeEnd,
+ unk2RangeBegin, unk2RangeEnd,
+ priority, unk3
+ );
+}
+
+void AmbientSounds::addLoopingSound(int sfx_id, int volume, int unk, int fadeInTime) {
+ const char *name = _vm->_gameInfo->getSfxTrack(sfx_id);
+
+ int32 hash = mix_id(name);
+
+ if (findLoopingTrackByHash(hash) >= 0)
+ return;
+
+ int i = findAvailableLoopingTrack();
+ if (i == -1)
+ return;
+
+ int actualVolume = volume * _ambientVolume / 100;
+
+ int balance = 0;
+
+ _vm->_audioPlayer->playAud(name, actualVolume, balance, balance, 100, AudioPlayer::LOOP | AudioPlayer::OVERRIDE_VOLUME);
+}
+
+void AmbientSounds::tick() {
+ uint32 now = g_system->getMillis();
+
+ for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) {
+ NonLoopingSound &track = _nonLoopingSounds[i];
+
+ if (!track.isActive || track.nextPlayTime > now)
+ continue;
+
+ int pan1, pan2;
+
+ pan1 = _vm->_rnd.getRandomNumberRng(track.pan1begin, track.pan1end);
+ if (track.pan2begin == -101) {
+ pan2 = pan1;
+ } else {
+ pan2 = _vm->_rnd.getRandomNumberRng(track.pan2begin, track.pan2end);
+ }
+
+ track.volume = _vm->_rnd.getRandomNumberRng(track.volume1, track.volume2);
+
+ 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);
+
+ }
+}
+
+int AmbientSounds::findAvailableNonLoopingTrack() {
+ for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) {
+ if (!_nonLoopingSounds[i].isActive)
+ return i;
+ }
+
+ return -1;
+}
+
+int AmbientSounds::findNonLoopingTrackByHash(int32 hash) {
+ for (int i = 0; i != NON_LOOPING_SOUNDS; ++i) {
+ NonLoopingSound &track = _nonLoopingSounds[i];
+
+ if (track.isActive && track.hash == hash)
+ return i;
+ }
+
+ return -1;
+}
+
+int AmbientSounds::findAvailableLoopingTrack() {
+ for (int i = 0; i != LOOPING_SOUNDS; ++i) {
+ if (!_loopingSounds[i].isActive)
+ return i;
+ }
+
+ return -1;
+}
+
+int AmbientSounds::findLoopingTrackByHash(int32 hash) {
+ for (int i = 0; i != LOOPING_SOUNDS; ++i) {
+ LoopingSound &track = _loopingSounds[i];
+
+ 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)
+{
+ int i = findAvailableNonLoopingTrack();
+ if (i < 0)
+ return;
+
+ NonLoopingSound &track = _nonLoopingSounds[i];
+
+ uint32 now = g_system->getMillis();
+
+ 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;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/ambient_sounds.h b/engines/bladerunner/ambient_sounds.h
new file mode 100644
index 0000000000..e5428e9f80
--- /dev/null
+++ b/engines/bladerunner/ambient_sounds.h
@@ -0,0 +1,120 @@
+/* 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_AMBIENT_SOUNDS_H
+#define BLADERUNNER_AMBIENT_SOUNDS_H
+
+#include "audio/audiostream.h"
+
+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;
+ uint32 nextPlayTime;
+ int32 volume1;
+ int32 volume2;
+ int32 volume;
+ int32 pan1begin;
+ int32 pan1end;
+ int32 pan2begin;
+ int32 pan2end;
+ int32 priority;
+ };
+
+ struct LoopingSound {
+ bool isActive;
+ char name[13];
+ int32 hash;
+ int32 volume;
+ };
+
+ NonLoopingSound *_nonLoopingSounds;
+ LoopingSound *_loopingSounds;
+ int _ambientVolume;
+
+public:
+ AmbientSounds(BladeRunnerEngine *vm);
+ ~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
+ );
+ // removeSound
+ // addSpeechSound
+ // removeSpeechSound
+ // playSound
+ // playSpeech
+ // removeAllNonLoopingSounds
+
+ // addLoopingSound
+ void addLoopingSound(int sfx_id, int volume, int unk, int fadeInTime);
+ // adjustLoopingSound
+ // removeLoopingSound
+ // removeAllLoopingSounds
+
+ void tick();
+
+ // setVolume
+ // getVolume
+
+private:
+ int findAvailableNonLoopingTrack();
+ int findNonLoopingTrackByHash(int32 hash);
+
+ int findAvailableLoopingTrack();
+ int findLoopingTrackByHash(int32 hash);
+
+ // stopNonLoopingTrack
+ // stopLoopingTrack
+
+ // saveToSaveGame
+ // initFromSaveGame
+ // addSoundByName
+ // playVolumeAdjustSound
+
+ 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);
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/archive.cpp b/engines/bladerunner/archive.cpp
index 4e355e8a9e..051fcd80c3 100644
--- a/engines/bladerunner/archive.cpp
+++ b/engines/bladerunner/archive.cpp
@@ -80,7 +80,6 @@ bool MIXArchive::isOpen() const {
#define ROL(n) ((n << 1) | ((n >> 31) & 1))
-static
int32 mix_id(const Common::String &name) {
char buffer[12] = { 0 };
diff --git a/engines/bladerunner/archive.h b/engines/bladerunner/archive.h
index 1225c71e18..03eda4ea7f 100644
--- a/engines/bladerunner/archive.h
+++ b/engines/bladerunner/archive.h
@@ -60,6 +60,8 @@ private:
uint32 indexForId(int32 id) const;
};
+int32 mix_id(const Common::String &name);
+
} // End of namespace BladeRunner
#endif
diff --git a/engines/bladerunner/audio_player.cpp b/engines/bladerunner/audio_player.cpp
new file mode 100644
index 0000000000..293fc56fb7
--- /dev/null
+++ b/engines/bladerunner/audio_player.cpp
@@ -0,0 +1,368 @@
+/* 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 "audio_player.h"
+
+#include "bladerunner/archive.h"
+#include "bladerunner/aud_decoder.h"
+
+#include "bladerunner/bladerunner.h"
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+
+#include "common/array.h"
+#include "common/debug.h"
+#include "common/mutex.h"
+#include "common/stream.h"
+
+namespace Common {
+ class MemoryReadStream;
+}
+
+namespace BladeRunner {
+
+/*
+ * This is a poor imitation of Bladerunner's resource cache
+ */
+class AudioCache {
+ struct cacheItem {
+ int32 hash;
+ int refs;
+ uint lastAccess;
+ byte *data;
+ uint32 size;
+ };
+
+ Common::Mutex _mutex;
+ Common::Array<cacheItem> _cacheItems;
+
+ uint32 _totalSize;
+ uint32 _maxSize;
+ uint32 _accessCounter;
+public:
+ AudioCache() :
+ _totalSize(0),
+ _maxSize(2457600),
+ _accessCounter(0)
+ {}
+ ~AudioCache();
+
+ bool canAllocate(uint32 size);
+ bool dropOldest();
+ byte *findByHash(int32 hash);
+ void storeByHash(int32 hash, Common::SeekableReadStream *stream);
+
+ void incRef(int32 hash);
+ void decRef(int32 hash);
+};
+
+AudioCache::~AudioCache() {
+ for (uint i = 0; i != _cacheItems.size(); ++i) {
+ free(_cacheItems[i].data);
+ }
+}
+
+bool AudioCache::canAllocate(uint32 size) {
+ Common::StackLock lock(_mutex);
+
+ return _maxSize - _totalSize >= size;
+}
+
+bool AudioCache::dropOldest() {
+ Common::StackLock lock(_mutex);
+
+ if (_cacheItems.size() == 0)
+ return false;
+
+ uint oldest = 0;
+ for (uint i = 1; i != _cacheItems.size(); ++i) {
+ if (_cacheItems[i].refs == 0 && _cacheItems[i].lastAccess < _cacheItems[oldest].lastAccess)
+ oldest = i;
+ }
+
+ free(_cacheItems[oldest].data);
+ _totalSize -= _cacheItems[oldest].size;
+ _cacheItems.remove_at(oldest);
+ return true;
+}
+
+byte *AudioCache::findByHash(int32 hash) {
+ Common::StackLock lock(_mutex);
+
+ for (uint i = 0; i != _cacheItems.size(); ++i) {
+ if (_cacheItems[i].hash == hash) {
+ _cacheItems[i].lastAccess = _accessCounter++;
+ return _cacheItems[i].data;
+ }
+ }
+
+ return NULL;
+}
+
+void AudioCache::storeByHash(int32 hash, Common::SeekableReadStream *stream) {
+ Common::StackLock lock(_mutex);
+
+ uint32 size = stream->size();
+ byte *data = (byte*)malloc(size);
+ stream->read(data, size);
+
+ cacheItem item = {
+ hash,
+ 0,
+ _accessCounter++,
+ data,
+ size
+ };
+
+ _cacheItems.push_back(item);
+ _totalSize += size;
+}
+
+void AudioCache::incRef(int32 hash) {
+ Common::StackLock lock(_mutex);
+
+ for (uint i = 0; i != _cacheItems.size(); ++i) {
+ if (_cacheItems[i].hash == hash) {
+ _cacheItems[i].refs++;
+ return;
+ }
+ }
+ assert(0 && "AudioCache::incRef: hash not found");
+}
+
+void AudioCache::decRef(int32 hash) {
+ Common::StackLock lock(_mutex);
+
+ for (uint i = 0; i != _cacheItems.size(); ++i) {
+ if (_cacheItems[i].hash == hash) {
+ assert(_cacheItems[i].refs > 0);
+ _cacheItems[i].refs--;
+ return;
+ }
+ }
+ assert(0 && "AudioCache::decRef: hash not found");
+}
+
+class AudStream : public Audio::RewindableAudioStream {
+ byte *_data;
+ byte *_p;
+ byte *_end;
+ AudioCache *_cache;
+ int32 _hash;
+ byte _compressionType;
+ uint16 _deafBlockRemain;
+
+ ADPCMWestwoodDecoder _decoder;
+
+public:
+ AudStream(AudioCache *cache, int32 hash)
+ : _cache(cache), _hash(hash)
+ {
+ _data = _cache->findByHash(_hash);
+ _end = _data + READ_LE_UINT32(_data + 2) + 12;
+ _cache->incRef(_hash);
+
+ assert(_end - _data >= 12);
+
+ _compressionType = *(_data + 11);
+
+ _deafBlockRemain = 0;
+ _p = _data + 12;
+ }
+ ~AudStream() {
+ _cache->decRef(_hash);
+ }
+
+ int readBuffer(int16 *buffer, const int numSamples);
+ bool isStereo() const { return false; }
+ int getRate() const { return READ_LE_UINT16(_data); };
+ bool endOfData() const { return _p == _end; }
+ bool rewind();
+};
+
+int AudStream::readBuffer(int16 *buffer, const int numSamples) {
+ int samplesRead = 0;
+
+ assert(numSamples % 2 == 0);
+
+ if (_compressionType == 99) {
+ while (samplesRead < numSamples) {
+ if (_deafBlockRemain == 0) {
+ if (_end - _p == 0)
+ break;
+
+ assert(_end - _p >= 6);
+
+ uint16 blockSize = READ_LE_UINT16(_p);
+ uint16 blockOutSize = READ_LE_UINT16(_p + 2);
+ uint32 sig = READ_LE_UINT32(_p + 4);
+ _p += 8;
+
+ assert(sig == 0xdeaf);
+ assert(_end - _p >= blockSize);
+ assert(blockOutSize = 4 * blockSize);
+
+ _deafBlockRemain = blockSize;
+ }
+
+ assert(_end - _p >= _deafBlockRemain);
+
+ int bytesConsumed = MIN<int>(_deafBlockRemain, (numSamples - samplesRead) / 2);
+
+ _decoder.decode(_p, bytesConsumed, buffer + samplesRead);
+ _p += bytesConsumed;
+ _deafBlockRemain -= bytesConsumed;
+
+ samplesRead += 2 * bytesConsumed;
+ }
+ } else {
+ assert(0 && "readBuffer: Unimplemented");
+ }
+
+ return samplesRead;
+}
+
+bool AudStream::rewind() {
+ _p = _data + 12;
+ _decoder.setParameters(0, 0);
+ return true;
+}
+
+AudioPlayer::AudioPlayer(BladeRunnerEngine *vm)
+ : _vm(vm)
+{
+ _cache = new AudioCache();
+
+ for (int i = 0; i != 6; ++i) {
+ _tracks[i].hash = 0;
+ _tracks[i].priority = 0;
+ }
+}
+
+AudioPlayer::~AudioPlayer() {
+ delete _cache;
+}
+
+bool AudioPlayer::isTrackActive(Track *track)
+{
+ if (!track->isMaybeActive)
+ return false;
+
+ return track->isMaybeActive = _vm->_mixer->isSoundHandleActive(track->soundHandle);
+}
+
+void AudioPlayer::stopAll()
+{
+ for (int i = 0; i != TRACKS; ++i) {
+ _vm->_mixer->stopHandle(_tracks[i].soundHandle);
+ }
+}
+
+void AudioPlayer::fadeAndStopTrack(Track *track, int time)
+{
+ (void)time;
+
+ _vm->_mixer->stopHandle(track->soundHandle);
+}
+
+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 */
+ int trackId;
+ Track *track = NULL;
+ int lowestPriority = 100;
+ Track *lowestPriorityTrack = NULL;
+
+ for (int i = 0; i != 6; ++i) {
+ track = &_tracks[i];
+ if (!isTrackActive(track)) {
+ trackId = 1;
+ break;
+ }
+
+ if (track->priority < lowestPriority) {
+ lowestPriority = track->priority;
+ lowestPriorityTrack = track;
+ }
+ }
+
+ /* 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);
+ track = lowestPriorityTrack;
+ }
+
+ /* If there's still no available track, give up */
+ if (track == NULL)
+ 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)
+ return -1;
+
+ int32 size = r->size();
+ while (!_cache->canAllocate(size)) {
+ if (!_cache->dropOldest()) {
+ delete r;
+ return -1;
+ }
+ }
+ _cache->storeByHash(hash, r);
+ delete r;
+ }
+
+ AudStream *audStream = new AudStream(_cache, hash);
+
+ Audio::AudioStream *audioStream = audStream;
+ if (flags & LOOP) {
+ audioStream = new Audio::LoopingAudioStream(audStream, 0, DisposeAfterUse::YES);
+ }
+
+ Audio::SoundHandle soundHandle;
+
+ debug("PlayStream: %s", name.c_str());
+
+ int balance = panFrom;
+
+ _vm->_mixer->playStream(
+ Audio::Mixer::kPlainSoundType,
+ &soundHandle,
+ audioStream,
+ -1,
+ volume * 255 / 100,
+ balance);
+
+ track->isMaybeActive = true;
+ track->soundHandle = soundHandle;
+ track->priority = priority;
+ track->hash = hash;
+ track->volume = volume;
+
+ return trackId;
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/audio_player.h b/engines/bladerunner/audio_player.h
new file mode 100644
index 0000000000..32c7dbb2d8
--- /dev/null
+++ b/engines/bladerunner/audio_player.h
@@ -0,0 +1,74 @@
+/* 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_H
+#define BLADERUNNER_AUDIO_H
+
+#include "audio/mixer.h"
+#include "common/str.h"
+#include "common/types.h"
+
+namespace BladeRunner {
+
+class BladeRunnerEngine;
+class AudioCache;
+
+#define TRACKS 6
+
+class AudioPlayer {
+ BladeRunnerEngine *_vm;
+ AudioCache *_cache;
+
+ struct Track {
+ bool isMaybeActive;
+ Audio::SoundHandle soundHandle;
+ int priority;
+ int32 hash;
+ int volume;
+
+ Track()
+ : isMaybeActive(false)
+ {}
+ };
+
+ Track _tracks[TRACKS];
+
+ bool isTrackActive(Track *track);
+ void fadeAndStopTrack(Track *track, int time);
+
+public:
+ AudioPlayer(BladeRunnerEngine *vm);
+ ~AudioPlayer();
+
+ enum {
+ LOOP = 1,
+ OVERRIDE_VOLUME = 2
+ };
+
+ int playAud(const Common::String &name, int volume, int panFrom, int panTo, int priority, byte flags = 0);
+
+ void stopAll();
+};
+
+} // End of namespace BladeRunner
+
+#endif
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index 7da46f1f0e..c1c65742dd 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -1,3 +1,4 @@
+
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
@@ -22,8 +23,11 @@
#include "bladerunner/bladerunner.h"
+#include "bladerunner/ambient_sounds.h"
+#include "bladerunner/audio_player.h"
#include "bladerunner/chapters.h"
#include "bladerunner/gameinfo.h"
+#include "bladerunner/gameflags.h"
#include "bladerunner/image.h"
#include "bladerunner/outtake.h"
#include "bladerunner/scene.h"
@@ -43,12 +47,19 @@
namespace BladeRunner {
-BladeRunnerEngine::BladeRunnerEngine(OSystem *syst) : Engine(syst) {
+BladeRunnerEngine::BladeRunnerEngine(OSystem *syst)
+ : Engine(syst),
+ _rnd("bladerunner")
+{
_windowIsActive = true;
_gameIsRunning = true;
+ _ambientSounds = new AmbientSounds(this);
+ _audioPlayer = new AudioPlayer(this);
_chapters = nullptr;
_gameInfo = nullptr;
+ _gameFlags = new GameFlags();
+ _gameVars = nullptr;
_scene = new Scene(this);
_script = new Script(this);
_settings = new Settings(this);
@@ -62,8 +73,12 @@ BladeRunnerEngine::~BladeRunnerEngine() {
delete _settings;
delete _script;
delete _scene;
+ delete _gameVars;
+ delete _gameFlags;
delete _gameInfo;
delete _chapters;
+ delete _audioPlayer;
+ delete _ambientSounds;
_surface1.free();
_surface2.free();
@@ -77,6 +92,8 @@ Common::Error BladeRunnerEngine::run() {
Graphics::PixelFormat format = createRGB555();
initGraphics(640, 480, true, &format);
+ _system->showMouse(true);
+
if (!startup())
return Common::Error(Common::kUnknownError, "Failed to initialize resources");
@@ -111,6 +128,10 @@ bool BladeRunnerEngine::startup() {
if (!r)
return false;
+ _gameFlags->setFlagCount(_gameInfo->getFlagCount());
+
+ _gameVars = new int[_gameInfo->getGlobalVarCount()];
+
_chapters = new Chapters(this);
if (!_chapters)
return false;
@@ -139,6 +160,9 @@ bool BladeRunnerEngine::startup() {
if (!r)
return false;
+ _zBuffer1 = new uint16[640 * 480];
+ _zBuffer2 = new uint16[640 * 480];
+
initChapterAndScene();
return true;
@@ -152,6 +176,8 @@ void BladeRunnerEngine::initChapterAndScene() {
}
void BladeRunnerEngine::shutdown() {
+ _mixer->stopAll();
+
if (_chapters) {
if (_chapters->hasOpenResources())
_chapters->closeResources();
@@ -212,15 +238,18 @@ void BladeRunnerEngine::gameTick() {
// TODO: Call Script_Player_Walked_In if applicable
// TODO: Gun range announcements
// TODO: ZBUF repair dirty rects
- // TODO: Tick Ambient Audio (in Replicant)
+
+ _ambientSounds->tick();
bool backgroundChanged = false;
- int frame = _scene->advanceFrame(_surface1);
+ int frame = _scene->advanceFrame(_surface1, _zBuffer1);
if (frame >= 0) {
_script->SceneFrameAdvanced(frame);
backgroundChanged = true;
}
+ (void)backgroundChanged;
_surface2.copyFrom(_surface1);
+ memcpy(_zBuffer2, _zBuffer1, 640*480*2);
// TODO: Render overlays (mostly in Replicant)
// TODO: Tick Actor AI and Timers (timers in Replicant)
@@ -230,13 +259,13 @@ void BladeRunnerEngine::gameTick() {
// TODO: Tick and draw all actors in current set (drawing works in Replicant)
// Hardcode McCoy in place to test the slice renderer
- Vector3 pos(-151.98f, -0.30f, 318.15f);
+ Vector3 pos = _scene->_actorStartPosition;
Vector3 draw_pos(pos.x, -pos.z, pos.y + 2);
float facing = -1.570796f;
_sliceRenderer->setView(_scene->_view);
_sliceRenderer->setupFrame(19, 1, draw_pos, facing);
- _sliceRenderer->drawFrame(_surface2);
+ _sliceRenderer->drawFrame(_surface2, _zBuffer2);
// TODO: Draw items (drawing works in Replicant)
// TODO: Draw item pickup (understood, drawing works in Replicant)
@@ -264,7 +293,7 @@ void BladeRunnerEngine::outtakePlay(int id, bool noLocalization, int container)
OuttakePlayer player(this);
- player.play(name, noLocalization, -1);
+ player.play(name, noLocalization, container);
}
bool BladeRunnerEngine::openArchive(const Common::String &name) {
diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h
index c3f7eac4d7..5ef23108f4 100644
--- a/engines/bladerunner/bladerunner.h
+++ b/engines/bladerunner/bladerunner.h
@@ -26,6 +26,7 @@
#include "bladerunner/archive.h"
#include "common/array.h"
+#include "common/random.h"
#include "common/stream.h"
#include "common/types.h"
@@ -35,8 +36,11 @@
namespace BladeRunner {
+class AmbientSounds;
+class AudioPlayer;
class Chapters;
class GameInfo;
+class GameFlags;
class Scene;
class Script;
class Settings;
@@ -48,18 +52,26 @@ public:
bool _gameIsRunning;
bool _windowIsActive;
+ AmbientSounds *_ambientSounds;
+ AudioPlayer *_audioPlayer;
Chapters *_chapters;
GameInfo *_gameInfo;
+ GameFlags *_gameFlags;
Scene *_scene;
Script *_script;
Settings *_settings;
SliceAnimations *_sliceAnimations;
SliceRenderer *_sliceRenderer;
+ int *_gameVars;
int in_script_counter;
- Graphics::Surface _surface1;
- Graphics::Surface _surface2;
+ Graphics::Surface _surface1;
+ Graphics::Surface _surface2;
+ uint16 *_zBuffer1;
+ uint16 *_zBuffer2;
+
+ Common::RandomSource _rnd;
private:
static const int kArchiveCount = 10;
diff --git a/engines/bladerunner/gameflags.cpp b/engines/bladerunner/gameflags.cpp
new file mode 100644
index 0000000000..3704271e04
--- /dev/null
+++ b/engines/bladerunner/gameflags.cpp
@@ -0,0 +1,68 @@
+/* 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/gameflags.h"
+
+#include "common/debug.h"
+
+namespace BladeRunner {
+
+GameFlags::GameFlags()
+ : flags(NULL), flagCount(0)
+{
+}
+
+GameFlags::~GameFlags() {
+ delete[] flags;
+}
+
+void GameFlags::setFlagCount(int count) {
+ assert(count > 0);
+
+ debug("flagCount: %d", count);
+
+ flagCount = count;
+ flags = new uint32[count / 32 + 1];
+
+ for (int i = 0; i <= flagCount; ++i)
+ reset(i);
+}
+
+void GameFlags::set(int flag) {
+ assert(flag >= 0 && flag <= flagCount);
+
+ flags[flag / 32] |= (1 << (flag % 32));
+}
+
+void GameFlags::reset(int flag) {
+ assert(flag >= 0 && flag <= flagCount);
+
+ flags[flag / 32] &= ~(1 << (flag % 32));
+}
+
+bool GameFlags::query(int flag) {
+ assert(flag >= 0 && flag <= flagCount);
+
+ return !!(flags[flag / 32] & (1 << (flag % 32)));
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/gameflags.h b/engines/bladerunner/gameflags.h
new file mode 100644
index 0000000000..4df9e5aa80
--- /dev/null
+++ b/engines/bladerunner/gameflags.h
@@ -0,0 +1,47 @@
+/* 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_GAMEFLAGS_H
+#define BLADERUNNER_GAMEFLAGS_H
+
+#include <common/scummsys.h>
+
+namespace BladeRunner {
+
+class GameFlags {
+ uint32 *flags;
+ int flagCount;
+
+public:
+ GameFlags();
+ ~GameFlags();
+
+ void setFlagCount(int count);
+
+ void set(int flag);
+ void reset(int flag);
+ bool query(int flag);
+};
+
+} // End of namespace BladeRunner
+
+#endif \ No newline at end of file
diff --git a/engines/bladerunner/gameinfo.cpp b/engines/bladerunner/gameinfo.cpp
index 712d5484c9..15058c8697 100644
--- a/engines/bladerunner/gameinfo.cpp
+++ b/engines/bladerunner/gameinfo.cpp
@@ -53,7 +53,7 @@ bool GameInfo::open(const Common::String &name) {
uint32 unk;
_actor_count = s->readUint32LE(); /* 00 */
- unk = s->readUint32LE(); /* 01 */
+ _player_id = s->readUint32LE(); /* 01 */
_flag_count = s->readUint32LE(); /* 02 */
unk = s->readUint32LE(); /* 03 */
_global_var_count = s->readUint32LE(); /* 04 */
diff --git a/engines/bladerunner/gameinfo.h b/engines/bladerunner/gameinfo.h
index 094d157949..8c8202b746 100644
--- a/engines/bladerunner/gameinfo.h
+++ b/engines/bladerunner/gameinfo.h
@@ -35,6 +35,7 @@ class GameInfo {
BladeRunnerEngine *_vm;
uint32 _actor_count;
+ uint32 _player_id;
uint32 _flag_count;
uint32 _global_var_count;
uint32 _set_names_count;
@@ -59,6 +60,7 @@ public:
bool open(const Common::String &name);
uint32 getActorCount() { return _actor_count; }
+ uint32 getPlayerId() { return _player_id; }
uint32 getFlagCount() { return _flag_count; }
uint32 getGlobalVarCount() { return _global_var_count; }
uint32 getSetNamesCount() { return _set_names_count; }
@@ -71,10 +73,10 @@ public:
uint32 getCoverWaypointCount() { return _cover_waypoint_count; }
uint32 getFleeWaypointCount() { return _flee_waypoint_count; }
- char *getSetName(int i) { return _set_names[i]; }
- char *getSfxTrack(int i) { return _sfx_tracks[i]; }
- char *getMusicTrack(int i) { return _music_tracks[i]; }
- char *getOuttake(int i) { return _outtakes[i]; }
+ const char *getSetName(int i) { return _set_names[i]; }
+ const char *getSfxTrack(int i) { return _sfx_tracks[i]; }
+ const char *getMusicTrack(int i) { return _music_tracks[i]; }
+ const char *getOuttake(int i) { return _outtakes[i]; }
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk
index 37ba70bd51..080eda93f8 100644
--- a/engines/bladerunner/module.mk
+++ b/engines/bladerunner/module.mk
@@ -1,13 +1,16 @@
MODULE := engines/bladerunner
MODULE_OBJS = \
+ ambient_sounds.o \
archive.o \
aud_decoder.o \
+ audio_player.o \
bladerunner.o \
chapters.o \
decompress_lcw.o \
decompress_lzo.o \
detection.o \
+ gameflags.o \
gameinfo.o \
image.o \
matrix.o \
diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp
index 2f357e2860..8a5870d64f 100644
--- a/engines/bladerunner/scene.cpp
+++ b/engines/bladerunner/scene.cpp
@@ -101,13 +101,19 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
return true;
}
-int Scene::advanceFrame(Graphics::Surface &surface) {
+int Scene::advanceFrame(Graphics::Surface &surface, uint16 *&zBuffer) {
int frame = _vqaPlayer.update();
if (frame >= 0) {
surface.copyFrom(*_vqaPlayer.getSurface());
+ memcpy(zBuffer, _vqaPlayer.getZBuffer(), 640*480*2);
_view = _vqaPlayer.getView();
}
return frame;
}
+void Scene::setActorStart(Vector3 position, int facing) {
+ _actorStartPosition = position;
+ _actorStartFacing = facing;
+}
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/scene.h b/engines/bladerunner/scene.h
index d7904f2190..5856e0b0d3 100644
--- a/engines/bladerunner/scene.h
+++ b/engines/bladerunner/scene.h
@@ -41,6 +41,8 @@ public:
int _nextSetId;
int _nextSceneId;
int _frame;
+ Vector3 _actorStartPosition;
+ int _actorStartFacing;
bool _playerWalkedIn;
View _view;
@@ -58,7 +60,8 @@ public:
}
bool open(int setId, int sceneId, bool isLoadingGame);
- int advanceFrame(Graphics::Surface &surface);
+ int advanceFrame(Graphics::Surface &surface, uint16 *&zBuffer);
+ void setActorStart(Vector3 position, int facing);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/rc01.cpp b/engines/bladerunner/script/rc01.cpp
index 560eb24742..2fa577856f 100644
--- a/engines/bladerunner/script/rc01.cpp
+++ b/engines/bladerunner/script/rc01.cpp
@@ -22,35 +22,99 @@
#include "bladerunner/script/script.h"
+#include "bladerunner/ambient_sounds.h"
+#include "bladerunner/audio_player.h"
#include "bladerunner/bladerunner.h"
namespace BladeRunner {
void ScriptRC01::InitializeScene() {
- _vm->outtakePlay(28, true);
- _vm->outtakePlay(41, true);
- _vm->outtakePlay( 0, false);
-
- _vm->ISez("Blade Runner");
- _vm->ISez("");
- _vm->ISez("From the dark recesses of David Leary's imagination comes a game unlike any");
- _vm->ISez("other. Blade Runner immerses you in the underbelly of future Los Angeles. Right");
- _vm->ISez("from the start, the story pulls you in with graphic descriptions of a");
- _vm->ISez("grandmother doing the shimmy in her underwear, child molestation, brutal");
- _vm->ISez("cold-blooded slaying of innocent animals, vomiting on desks, staring at a");
- _vm->ISez("woman's ass, the list goes on. And when the game starts, the real fun begins -");
- _vm->ISez("shoot down-on-their-luck homeless people and toss them into a dumpster. Watch");
- _vm->ISez("with sadistic glee as a dog gets blown into chunky, bloody, bits by an");
- _vm->ISez("explosive, and even murder a shy little girl who loves you. If you think David");
- _vm->ISez("Leary is sick, and you like sick, this is THE game for you.");
- _vm->ISez("");
- _vm->ISez("JW: Don't forget the wasting of helpless mutated cripples in the underground.");
- _vm->ISez("It's such a beautiful thing!");
- _vm->ISez("");
- _vm->ISez("DL: Go ahead. Just keep beating that snarling pit bull...ignore the foam");
- _vm->ISez("around his jaws. There's room on the top shelf of my fridge for at least one");
- _vm->ISez("more head... - Psychotic Dave");
- _vm->ISez("");
+ if (!Game_Flag_Query(24)) {
+ Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
+ Ambient_Sounds_Remove_All_Looping_Sounds(1);
+ Outtake_Play(28, 1); // WSTLGO_E.VQA
+ Outtake_Play(41, 1); // BRLOGO_E.VQA
+ Outtake_Play( 0, 0); // INTRO_E.VQA
+ Outtake_Play(33, 1); // DSCENT_E.VQA
+ }
+
+ Game_Flag_Set(9); // Force flag 9 so McCoy will be in view
+ if (Game_Flag_Query(9)) {
+ Setup_Scene_Information(-171.16, 5.55, 27.28, 616);
+ } else if (Game_Flag_Query(114)) {
+ Setup_Scene_Information(-471.98, -0.30, 258.15, 616);
+ } else {
+ Setup_Scene_Information( -10.98, -0.30, 318.15, 616);
+ }
+
+ Scene_Exit_Add_2D_Exit(0, 314, 145, 340, 255, 0);
+ if (Game_Flag_Query(249))
+ Scene_Exit_Add_2D_Exit(1, 482, 226, 639, 280, 2);
+ if (Global_Variable_Query(1) > 1 && Game_Flag_Query(710))
+ Scene_Exit_Add_2D_Exit(2, 0, 0, 10, 479, 3);
+ if (!Game_Flag_Query(186))
+ Scene_2D_Region_Add(0, 0, 294, 296, 479);
+
+ Ambient_Sounds_Remove_All_Non_Looping_Sounds(0);
+ Ambient_Sounds_Add_Looping_Sound(54, 30, 0, 1); // CTRAIN1.AUD
+
+ if (!Game_Flag_Query(186)) {
+ Ambient_Sounds_Add_Sound(181, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0470R.AUD
+ Ambient_Sounds_Add_Sound(182, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0480R.AUD
+ Ambient_Sounds_Add_Sound(183, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0500R.AUD
+ Ambient_Sounds_Add_Sound(184, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0540R.AUD
+ Ambient_Sounds_Add_Sound(185, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0560R.AUD
+ Ambient_Sounds_Add_Sound(186, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0870R.AUD
+ Ambient_Sounds_Add_Sound(188, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0900R.AUD
+ Ambient_Sounds_Add_Sound(189, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0940R.AUD
+ Ambient_Sounds_Add_Sound(190, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_0960R.AUD
+ Ambient_Sounds_Add_Sound(191, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1070R.AUD
+ Ambient_Sounds_Add_Sound(192, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1080R.AUD
+ Ambient_Sounds_Add_Sound(193, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1100R.AUD
+ Ambient_Sounds_Add_Sound(194, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1140R.AUD
+ Ambient_Sounds_Add_Sound(195, 5, 70, 12, 12, -100, 100, -101, -101, 0, 0); // 67_1160R.AUD
+ }
+
+ Ambient_Sounds_Add_Looping_Sound(81, 60, 100, 1); // RCAMBR1.AUD
+ Ambient_Sounds_Add_Sound(82, 5, 30, 30, 50, -100, 100, -101, -101, 0, 0); // RCCARBY1.AUD
+ Ambient_Sounds_Add_Sound(83, 5, 30, 30, 55, -100, 100, -101, -101, 0, 0); // RCCARBY2.AUD
+ Ambient_Sounds_Add_Sound(84, 5, 30, 30, 50, -100, 100, -101, -101, 0, 0); // RCCARBY3.AUD
+ Ambient_Sounds_Add_Sound(67, 10, 50, 30, 50, -100, 100, -101, -101, 0, 0); // SPIN2A.AUD
+ Ambient_Sounds_Add_Sound(87, 20, 80, 20, 40, -100, 100, -101, -101, 0, 0); // SIREN2.AUD
+
+ if (Game_Flag_Query(186)) {
+ if (!Game_Flag_Query(9) && !Game_Flag_Query(114))
+ Scene_Loop_Start_Special(0, 5, 0);
+ if (Game_Flag_Query(249))
+ Scene_Loop_Set_Default(6);
+ else
+ Scene_Loop_Set_Default(10);
+ } else {
+ if (!Game_Flag_Query(9) && !Game_Flag_Query(114))
+ Scene_Loop_Start_Special(0, 0, 0);
+ Scene_Loop_Set_Default(1);
+ }
+
+ I_Sez("Blade Runner");
+ I_Sez("");
+ I_Sez("From the dark recesses of David Leary's imagination comes a game unlike any");
+ I_Sez("other. Blade Runner immerses you in the underbelly of future Los Angeles. Right");
+ I_Sez("from the start, the story pulls you in with graphic descriptions of a");
+ I_Sez("grandmother doing the shimmy in her underwear, child molestation, brutal");
+ I_Sez("cold-blooded slaying of innocent animals, vomiting on desks, staring at a");
+ I_Sez("woman's ass, the list goes on. And when the game starts, the real fun begins -");
+ I_Sez("shoot down-on-their-luck homeless people and toss them into a dumpster. Watch");
+ I_Sez("with sadistic glee as a dog gets blown into chunky, bloody, bits by an");
+ I_Sez("explosive, and even murder a shy little girl who loves you. If you think David");
+ I_Sez("Leary is sick, and you like sick, this is THE game for you.");
+ I_Sez("");
+ I_Sez("JW: Don't forget the wasting of helpless mutated cripples in the underground.");
+ I_Sez("It's such a beautiful thing!");
+ I_Sez("");
+ I_Sez("DL: Go ahead. Just keep beating that snarling pit bull...ignore the foam");
+ I_Sez("around his jaws. There's room on the top shelf of my fridge for at least one");
+ I_Sez("more head... - Psychotic Dave");
+ I_Sez("");
}
void ScriptRC01::SceneLoaded() {
@@ -58,7 +122,26 @@ void ScriptRC01::SceneLoaded() {
}
void ScriptRC01::SceneFrameAdvanced(int frame) {
+ if (frame == 1)
+ Sound_Play(118, 40, 0, 0, 50); // CARDOWN3.AUD
+
+ if (frame == 61 || frame == 362)
+ Sound_Play(116, 100, 80, 80, 50); // SPINOPN4.AUD
+
+ if (frame == 108 || frame == 409)
+ Sound_Play(119, 100, 80, 80, 50); // SPINCLS1.AUD
+
+ if (frame == 183 || frame == 484)
+ Sound_Play(116, 100, 80, 80, 50); // SPINOPN4.AUD
+
+ if (frame == 228 || frame == 523)
+ Sound_Play(119, 100, 80, 80, 50); // SPINCLS1.AUD
+
+ if (frame == 243 || frame == 545)
+ Sound_Play(117, 40, 80, 80, 50); // CARUP3.AUD
+ if (frame == 315)
+ Sound_Play(118, 40, 80, 80, 50); // CARDOWN3.AUD
}
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index 540d4313c7..9aca48fcf6 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -24,6 +24,13 @@
#include "bladerunner/bladerunner.h"
+#include "bladerunner/ambient_sounds.h"
+#include "bladerunner/audio_player.h"
+#include "bladerunner/gameinfo.h"
+#include "bladerunner/gameflags.h"
+#include "bladerunner/scene.h"
+#include "bladerunner/vector.h"
+
namespace BladeRunner {
bool Script::open(const Common::String &name) {
@@ -56,4 +63,86 @@ void Script::SceneFrameAdvanced(int frame) {
_inScriptCounter--;
}
+void ScriptBase::Game_Flag_Set(int flag) {
+ _vm->_gameFlags->set(flag);
+}
+
+void ScriptBase::Game_Flag_Reset(int flag) {
+ _vm->_gameFlags->reset(flag);
+}
+
+bool ScriptBase::Game_Flag_Query(int flag) {
+ return _vm->_gameFlags->query(flag);
+}
+
+int ScriptBase::Global_Variable_Set(int var, int value) {
+ return _vm->_gameVars[var] = value;
+}
+
+int ScriptBase::Global_Variable_Reset(int var) {
+ return _vm->_gameVars[var] = 0;
+}
+
+int ScriptBase::Global_Variable_Query(int var) {
+ return _vm->_gameVars[var];
+}
+
+int ScriptBase::Global_Variable_Increment(int var, int inc) {
+ return _vm->_gameVars[var] += inc;
+}
+
+int ScriptBase::Global_Variable_Decrement(int var, int dec) {
+ return _vm->_gameVars[var] -= dec;
+}
+
+void ScriptBase::Sound_Play(int id, int volume, int panFrom, int panTo, int priority) {
+ const char *name = _vm->_gameInfo->getSfxTrack(id);
+ _vm->_audioPlayer->playAud(name, volume, panFrom, panTo, priority);
+}
+
+void ScriptBase::Scene_Loop_Set_Default(int a) {
+ debug("Scene_Loop_Set_Default(%d)", a);
+}
+
+void ScriptBase::Scene_Loop_Start_Special(int a, int b, int c) {
+ debug("Scene_Loop_Start_Special(%d, %d, %d)", a, b, c);
+}
+
+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_Remove_All_Non_Looping_Sounds(int time) {
+ // _vm->_ambientSounds->removeAllNonLoopingSounds(time);
+}
+
+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_Remove_All_Looping_Sounds(int time) {
+ // _vm->_ambientSounds->removeAllLoopingSounds(time);
+}
+
+void ScriptBase::Setup_Scene_Information(float actorX, float actorY, float actorZ, int actorFacing) {
+ _vm->_scene->setActorStart(Vector3(actorX, actorY, actorZ), actorFacing);
+}
+
+void ScriptBase::Scene_Exit_Add_2D_Exit(int a, int b, int c, int d, int e, int f) {
+ debug("Scene_Exit_Add_2D_Exit(%d, %d, %d, %d, %d, %d)", a, b, c, d, e, f);
+}
+
+void ScriptBase::Scene_2D_Region_Add(int a, int b, int c, int d, int e) {
+ debug("Scene_2D_Region_Add(%d, %d, %d, %d, %d)", a, b, c, d, e);
+}
+
+void ScriptBase::I_Sez(const char *str) {
+ _vm->ISez(str);
+}
+
+
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/script.h b/engines/bladerunner/script/script.h
index 83fd78dc39..e8bf1c029e 100644
--- a/engines/bladerunner/script/script.h
+++ b/engines/bladerunner/script/script.h
@@ -65,6 +65,42 @@ public:
virtual void InitializeScene() = 0;
virtual void SceneLoaded() = 0;
virtual void SceneFrameAdvanced(int frame) = 0;
+
+protected:
+
+ void Game_Flag_Set(int flag);
+ void Game_Flag_Reset(int flag);
+ bool Game_Flag_Query(int flag);
+
+ int Global_Variable_Set(int, int);
+ int Global_Variable_Reset(int);
+ int Global_Variable_Query(int);
+ int Global_Variable_Increment(int, int);
+ int Global_Variable_Decrement(int, int);
+
+ void Sound_Play(int id, int volume, int panFrom, int panTo, int priority);
+
+ void Scene_Loop_Set_Default(int);
+ void Scene_Loop_Start_Special(int, int, int);
+
+ 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);
+ // Ambient_Sounds_Remove_Sound
+ // Ambient_Sounds_Add_Speech_Sound
+ // Ambient_Sounds_Remove_Speech_Sound
+ // Ambient_Sounds_Play_Sound
+ // 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);
+ // Ambient_Sounds_Adjust_Looping_Sound
+ // Ambient_Sounds_Remove_Looping_Sound
+ void Ambient_Sounds_Remove_All_Looping_Sounds(int time);
+ void Setup_Scene_Information(float actorX, float actorY, float actorZ, int actorFacing);
+
+ void Scene_Exit_Add_2D_Exit(int, int, int, int, int, int);
+ void Scene_2D_Region_Add(int, int, int, int, int);
+
+ void I_Sez(const char *str);
};
#define DECLARE_SCRIPT(name) \
diff --git a/engines/bladerunner/slice_renderer.cpp b/engines/bladerunner/slice_renderer.cpp
index e8e3ecf894..4e2300ec7f 100644
--- a/engines/bladerunner/slice_renderer.cpp
+++ b/engines/bladerunner/slice_renderer.cpp
@@ -322,7 +322,7 @@ void setupLookupTable(int t[256], int inc) {
}
}
-void SliceRenderer::drawFrame(Graphics::Surface &surface) {
+void SliceRenderer::drawFrame(Graphics::Surface &surface, uint16 *zbuffer) {
assert(_sliceFramePtr);
SliceLineIterator sliceLineIterator;
@@ -340,7 +340,8 @@ void SliceRenderer::drawFrame(Graphics::Surface &surface) {
int frameY = sliceLineIterator._field_18;
- uint16 *frameLinePtr = (uint16*)surface.getPixels() + 640 * frameY;
+ uint16 *frameLinePtr = (uint16*)surface.getPixels() + 640 * frameY;
+ uint16 *zBufferLinePtr = zbuffer + 640 * frameY;
while (sliceLineIterator._field_3C <= sliceLineIterator._field_1C) {
_c3 = sliceLineIterator._field_00[0][2];
@@ -349,16 +350,17 @@ void SliceRenderer::drawFrame(Graphics::Surface &surface) {
float sliceLine = sliceLineIterator.line();
if (frameY >= 0 && frameY < 480)
- drawSlice((int)sliceLine, frameLinePtr);
+ drawSlice((int)sliceLine, frameLinePtr, zBufferLinePtr);
sliceLineIterator.advance();
frameY += 1;
frameLinePtr += 640;
+ zBufferLinePtr += 640;
}
}
-void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr) {
- if (slice < 0 || slice >= _frameSliceCount)
+void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr, uint16 *zbufLinePtr) {
+ if (slice < 0 || (uint32)slice >= _frameSliceCount)
return;
SlicePalette &palette = _vm->_sliceAnimations->getPalette(_framePaletteIndex);
@@ -371,11 +373,6 @@ void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr) {
uint32 polyCount = READ_LE_UINT32(p);
p += 4;
-
- int zbufLinePtr[640];
- for (int i = 0; i != 640; ++i)
- zbufLinePtr[i] = 65535;
-
while (polyCount--) {
uint32 vertexCount = READ_LE_UINT32(p);
p += 4;
@@ -396,9 +393,10 @@ void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr) {
if (vertexZ >= 0 && vertexZ < 65536) {
for (int x = previousVertexX; x != vertexX; ++x) {
+ // debug("\t%04x < %04x", vertexZ, zbufLinePtr[x]);
if (vertexZ < zbufLinePtr[x]) {
frameLinePtr[x] = palette[p[2]];
- zbufLinePtr[x] = (int16)vertexZ;
+ zbufLinePtr[x] = (uint16)vertexZ;
}
}
}
diff --git a/engines/bladerunner/slice_renderer.h b/engines/bladerunner/slice_renderer.h
index 2e0fe93d77..79ebdd8951 100644
--- a/engines/bladerunner/slice_renderer.h
+++ b/engines/bladerunner/slice_renderer.h
@@ -76,7 +76,7 @@ class SliceRenderer {
int _c6;
Matrix3x2 calculateFacingRotationMatrix();
- void drawSlice(int slice, uint16 *frameLinePtr);
+ void drawSlice(int slice, uint16 *frameLinePtr, uint16 *zbufLinePtr);
public:
SliceRenderer(BladeRunnerEngine *vm)
@@ -88,7 +88,7 @@ public:
void setupFrame(int animation, int frame, Vector3 position, float facing, float scale = 1.0f);
void calculateBoundingRect();
- void drawFrame(Graphics::Surface &surface);
+ void drawFrame(Graphics::Surface &surface, uint16 *zbuffer);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp
index f5b8c80037..5c08284f40 100644
--- a/engines/bladerunner/vqa_decoder.cpp
+++ b/engines/bladerunner/vqa_decoder.cpp
@@ -196,6 +196,10 @@ const Graphics::Surface *VQADecoder::decodeVideoFrame() {
return _videoTrack->decodeVideoFrame();
}
+const uint16 *VQADecoder::decodeZBuffer() {
+ return _videoTrack->decodeZBuffer();
+}
+
Audio::SeekableAudioStream *VQADecoder::decodeAudioFrame() {
return _audioTrack->decodeAudioFrame();
}
@@ -295,6 +299,7 @@ bool VQADecoder::readVQHD(Common::SeekableReadStream *s, uint32 size)
debug("_header.unk4 %d", _header.unk4);
debug("_header.maxCBFZSize %d", _header.maxCBFZSize);
debug("_header.unk5 %d", _header.unk5);
+ debug("\n");
}
assert(_header.version == 2);
@@ -538,6 +543,7 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder) {
_maxVPTRSize = header->maxVPTRSize;
_maxCBFZSize = header->maxCBFZSize;
_maxZBUFChunkSize = vqaDecoder->_maxZBUFChunkSize;
+ _zbuffer = nullptr;
_codebookSize = 0;
_codebook = nullptr;
@@ -644,7 +650,7 @@ bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 s
return true;
}
-#if 0
+#if 1
static
int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen)
{
@@ -654,7 +660,7 @@ int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen)
uint16 *curzp = curZBUF;
uint16 *inp = (uint16*)src;
- while (dstRemain && (inp - (uint16*)src) < (ptrdiff_t)srcLen)
+ while (dstRemain && (inp - (uint16*)src) < (std::ptrdiff_t)srcLen)
{
uint32 count = FROM_LE_16(*inp++);
@@ -692,9 +698,9 @@ int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen)
bool VQADecoder::VQAVideoTrack::readZBUF(Common::SeekableReadStream *s, uint32 size)
{
- s->skip(roundup(size));
- return true;
-#if 0
+ // s->skip(roundup(size));
+ // return true;
+#if 1
if (size > _maxZBUFChunkSize) {
debug("VQA ERROR: ZBUF chunk size: %08x > %08x", size, _maxZBUFChunkSize);
s->skip(roundup(size));
@@ -709,43 +715,47 @@ bool VQADecoder::VQAVideoTrack::readZBUF(Common::SeekableReadStream *s, uint32 s
uint32 remain = size - 16;
- if (width != width || height != height)
+ if (_width != width || _height != height)
{
debug("%d, %d, %d, %d", width, height, complete, unk0);
s->skip(roundup(remain));
return false;
}
+ _zbufChunkComplete = complete;
+ _zbufChunkSize = remain;
s->read(_zbufChunk, roundup(remain));
-
- if (!_zbuf)
- {
- if (!complete) {
- s->skip(roundup(remain));
- return false;
- }
- _zbuf = new uint16[width * height];
- }
-
- if (complete) {
- size_t zbufOutSize;
- decompress_lzo1x(_zbufChunk, remain, (uint8*)_zbuf, &zbufOutSize);
- } else {
- decodeZBUF_partial(_zbufChunk, _zbuf, remain);
- }
#endif
return true;
}
-#if 0
-bool VQADecoder::VQAVideoTrack::getZBUF(uint16 *zbuf)
+#if 1
+const uint16 *VQADecoder::VQAVideoTrack::decodeZBuffer()
{
- if (!_zbuf)
- return false;
+ if (_maxZBUFChunkSize == 0)
+ return nullptr;
+
+ if (!_zbuffer)
+ _zbuffer = new uint16[_width * _height];
+ // {
+ // if (!complete) {
+ // return false;
+ // }
+ // }
+
+ if (_zbufChunkComplete) {
+ size_t zbufOutSize;
+ decompress_lzo1x(_zbufChunk, _zbufChunkSize, (uint8*)_zbuffer, &zbufOutSize);
+ } else {
+ decodeZBUF_partial(_zbufChunk, _zbuffer, _zbufChunkSize);
+ }
- memcpy(zbuf, _zbuf, 2 * _header.width * _header.height);
- return true;
+ // if (!_zbuf)
+ // return false;
+
+ // memcpy(zbuf, _zbuffer, 2 * _width * _height);
+ return _zbuffer;
}
#endif
diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h
index 132c18ace2..8b4293dc7b 100644
--- a/engines/bladerunner/vqa_decoder.h
+++ b/engines/bladerunner/vqa_decoder.h
@@ -50,6 +50,7 @@ public:
void readNextPacket();
const Graphics::Surface *decodeVideoFrame();
+ const uint16 *decodeZBuffer();
Audio::SeekableAudioStream *decodeAudioFrame();
const View &getView() { return _videoTrack->getView(); }
@@ -161,6 +162,7 @@ private:
int getCurFrame() const;
int getFrameCount() const;
const Graphics::Surface *decodeVideoFrame();
+ const uint16 *decodeZBuffer();
const View &getView() { return _view; }
bool readVQFR(Common::SeekableReadStream *s, uint32 size);
@@ -179,6 +181,7 @@ private:
private:
Graphics::Surface *_surface;
+ uint16 *_zbuffer;
bool _hasNewFrame;
uint16 _numFrames;
@@ -195,6 +198,8 @@ private:
uint32 _codebookSize;
uint8 *_codebook;
uint8 *_cbfz;
+ bool _zbufChunkComplete;
+ uint32 _zbufChunkSize;
uint8 *_zbufChunk;
uint32 _vpointerSize;
diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp
index 2b79ac7eec..8146c1abf9 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -64,6 +64,7 @@ int VQAPlayer::update() {
if (_hasAudio)
queueAudioFrame(_decoder.decodeAudioFrame());
_surface = _decoder.decodeVideoFrame();
+ _zBuffer = _decoder.decodeZBuffer();
_view = _decoder.getView();
}
@@ -87,6 +88,7 @@ int VQAPlayer::update() {
_curFrame = _decodedFrame;
if (_curFrame >= 0) {
_surface = _decoder.decodeVideoFrame();
+ _zBuffer = _decoder.decodeZBuffer();
_view = _decoder.getView();
}
@@ -109,6 +111,10 @@ const Graphics::Surface *VQAPlayer::getSurface() const {
return _surface;
}
+const uint16 *VQAPlayer::getZBuffer() const {
+ return _zBuffer;
+}
+
void VQAPlayer::setLoopSpecial(int loop, bool wait) {
_loopSpecial = loop;
if (!wait)
diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h
index 4d87b59dee..80ebf19d2f 100644
--- a/engines/bladerunner/vqa_player.h
+++ b/engines/bladerunner/vqa_player.h
@@ -39,6 +39,7 @@ class VQAPlayer {
Common::SeekableReadStream *_s;
VQADecoder _decoder;
const Graphics::Surface *_surface;
+ const uint16 *_zBuffer;
Audio::QueuingAudioStream *_audioStream;
int _curFrame;
@@ -80,6 +81,7 @@ public:
int update();
const Graphics::Surface *getSurface() const;
+ const uint16 *getZBuffer() const;
const View &getView() const { return _view; }
void setLoopSpecial(int loop, bool wait);