aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/bladerunner/actor.cpp30
-rw-r--r--engines/bladerunner/actor.h4
-rw-r--r--engines/bladerunner/actor_clues.cpp24
-rw-r--r--engines/bladerunner/actor_clues.h4
-rw-r--r--engines/bladerunner/bladerunner.cpp184
-rw-r--r--engines/bladerunner/bladerunner.h18
-rw-r--r--engines/bladerunner/crimes_database.cpp6
-rw-r--r--engines/bladerunner/debugger.cpp55
-rw-r--r--engines/bladerunner/debugger.h2
-rw-r--r--engines/bladerunner/detection.cpp109
-rw-r--r--engines/bladerunner/detection_tables.h2
-rw-r--r--engines/bladerunner/dialogue_menu.cpp2
-rw-r--r--engines/bladerunner/dialogue_menu.h3
-rw-r--r--engines/bladerunner/game_flags.cpp9
-rw-r--r--engines/bladerunner/game_flags.h1
-rw-r--r--engines/bladerunner/item.cpp4
-rw-r--r--engines/bladerunner/items.cpp4
-rw-r--r--engines/bladerunner/items.h2
-rw-r--r--engines/bladerunner/outtake.cpp4
-rw-r--r--engines/bladerunner/overlays.cpp48
-rw-r--r--engines/bladerunner/overlays.h7
-rw-r--r--engines/bladerunner/savefile.cpp92
-rw-r--r--engines/bladerunner/savefile.h56
-rw-r--r--engines/bladerunner/scene.cpp10
-rw-r--r--engines/bladerunner/scene_objects.cpp5
-rw-r--r--engines/bladerunner/script/ai_script.cpp1
-rw-r--r--engines/bladerunner/script/police_maze.cpp2
-rw-r--r--engines/bladerunner/script/scene/rc01.cpp4
-rw-r--r--engines/bladerunner/script/script.cpp6
-rw-r--r--engines/bladerunner/set.cpp4
-rw-r--r--engines/bladerunner/settings.cpp14
-rw-r--r--engines/bladerunner/settings.h13
-rw-r--r--engines/bladerunner/slice_renderer.cpp5
-rw-r--r--engines/bladerunner/suspects_database.h1
-rw-r--r--engines/bladerunner/ui/elevator.cpp6
-rw-r--r--engines/bladerunner/ui/esper.cpp10
-rw-r--r--engines/bladerunner/ui/kia.cpp30
-rw-r--r--engines/bladerunner/ui/kia.h4
-rw-r--r--engines/bladerunner/ui/kia_section_clues.cpp12
-rw-r--r--engines/bladerunner/ui/kia_section_clues.h2
-rw-r--r--engines/bladerunner/ui/kia_section_crimes.cpp22
-rw-r--r--engines/bladerunner/ui/kia_section_crimes.h3
-rw-r--r--engines/bladerunner/ui/kia_section_suspects.cpp24
-rw-r--r--engines/bladerunner/ui/kia_section_suspects.h3
-rw-r--r--engines/bladerunner/ui/scores.cpp4
-rw-r--r--engines/bladerunner/ui/spinner.cpp8
-rw-r--r--engines/bladerunner/ui/vk.cpp8
-rw-r--r--engines/bladerunner/vqa_player.cpp4
-rw-r--r--engines/bladerunner/vqa_player.h6
49 files changed, 693 insertions, 188 deletions
diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp
index 4899ea9527..26a7a80d6e 100644
--- a/engines/bladerunner/actor.cpp
+++ b/engines/bladerunner/actor.cpp
@@ -51,7 +51,8 @@ Actor::Actor(BladeRunnerEngine *vm, int actorId) {
_walkInfo = new ActorWalk(vm);
_movementTrack = new MovementTrack();
- _clues = new ActorClues(vm, (actorId && actorId != 99) ? 2 : 4);
+ _cluesLimit = (actorId == 0 || actorId == 99) ? 4 : 2;
+ _clues = new ActorClues(vm, _cluesLimit);
_combatInfo = new ActorCombat(vm);
_friendlinessToOther.resize(_vm->_gameInfo->getActorCount());
@@ -1105,6 +1106,10 @@ void Actor::addClueToDatabase(int clueId, int weight, bool clueAcquired, bool un
_clues->add(_id, clueId, weight, clueAcquired, unknownFlag, fromActorId);
}
+bool Actor::canAcquireClue(int clueId) const {
+ return _clues->exists(clueId);
+}
+
void Actor::acquireClue(int clueId, bool unknownFlag, int fromActorId) {
bool hasAlready = hasClue(clueId);
_clues->acquire(clueId, unknownFlag, fromActorId);
@@ -1124,7 +1129,7 @@ bool Actor::hasClue(int clueId) const {
void Actor::copyClues(int actorId) {
Actor *otherActor = _vm->_actors[actorId];
for (int i = 0; i < (int)_vm->_gameInfo->getClueCount(); i++) {
- if (hasClue(i) && !_clues->isPrivate(i) && !otherActor->hasClue(i)) {
+ if (hasClue(i) && !_clues->isPrivate(i) && otherActor->canAcquireClue(i) && !otherActor->hasClue(i)) {
int fromActorId = _id;
if (_id == BladeRunnerEngine::kActorVoiceOver) {
fromActorId = _clues->getFromActorId(i);
@@ -1258,8 +1263,9 @@ void Actor::save(SaveFileWriteStream &f) {
f.writeInt(_honesty);
f.writeInt(_intelligence);
- f.writeInt(_stability);
f.writeInt(_combatAggressiveness);
+ f.writeInt(_stability);
+
f.writeInt(_goalNumber);
f.writeInt(_currentHP);
@@ -1271,7 +1277,8 @@ void Actor::save(SaveFileWriteStream &f) {
f.writeInt(_movementTrackNextAngle);
f.writeBool(_movementTrackNextRunning);
- f.writeInt(0); // TODO: _clueType
+ f.writeInt(_cluesLimit);
+
f.writeBool(_isMoving);
f.writeBool(_isTarget);
f.writeBool(_inCombat);
@@ -1302,7 +1309,7 @@ void Actor::save(SaveFileWriteStream &f) {
uint32 now = _vm->getTotalPlayTime(); // TODO: should be last lock time
for (int i = 0; i < 7; ++i) {
- f.writeInt(_timersLast[i] - now);
+ f.writeInt(now - _timersLast[i]);
}
int actorCount = _vm->_gameInfo->getActorCount();
@@ -1316,9 +1323,10 @@ void Actor::save(SaveFileWriteStream &f) {
_walkInfo->save(f);
- f.writeBoundingBox(_bbox);
+ f.writeBoundingBox(_bbox, false);
_combatInfo->save(f);
+
f.writeInt(_animationModeCombatIdle);
f.writeInt(_animationModeCombatWalk);
f.writeInt(_animationModeCombatRun);
@@ -1334,8 +1342,9 @@ void Actor::load(SaveFileReadStream &f) {
_honesty = f.readInt();
_intelligence = f.readInt();
- _stability = f.readInt();
_combatAggressiveness = f.readInt();
+ _stability = f.readInt();
+
_goalNumber = f.readInt();
_currentHP = f.readInt();
@@ -1347,7 +1356,8 @@ void Actor::load(SaveFileReadStream &f) {
_movementTrackNextAngle = f.readInt();
_movementTrackNextRunning = f.readBool();
- f.skip(4); // TODO: _clueType
+ _cluesLimit = f.readInt();
+
_isMoving = f.readBool();
_isTarget = f.readBool();
_inCombat = f.readBool();
@@ -1378,7 +1388,7 @@ void Actor::load(SaveFileReadStream &f) {
uint32 now = _vm->getTotalPlayTime(); // TODO: should be last lock time
for (int i = 0; i < 7; ++i) {
- _timersLast[i] = f.readInt() + now;
+ _timersLast[i] = now - f.readInt();
}
int actorCount = _vm->_gameInfo->getActorCount();
@@ -1392,7 +1402,7 @@ void Actor::load(SaveFileReadStream &f) {
_walkInfo->load(f);
- _bbox = f.readBoundingBox();
+ _bbox = f.readBoundingBox(false);
_combatInfo->load(f);
diff --git a/engines/bladerunner/actor.h b/engines/bladerunner/actor.h
index 6540c0593a..896f3a2e52 100644
--- a/engines/bladerunner/actor.h
+++ b/engines/bladerunner/actor.h
@@ -70,6 +70,7 @@ private:
int _targetFacing;
int _walkboxId;
+ int _cluesLimit;
int _timer4RemainDefault;
// Flags
@@ -242,9 +243,10 @@ public:
bool isSpeeching();
void addClueToDatabase(int clueId, int unknown, bool clueAcquired, bool unknownFlag, int fromActorId);
+ bool canAcquireClue(int clueId) const;
void acquireClue(int clueId, bool unknownFlag, int fromActorId);
void loseClue(int clueId);
- bool hasClue(int clueId) const;
+ bool hasClue(int clueId) const;
void copyClues(int actorId);
void acquireCluesByRelations();
diff --git a/engines/bladerunner/actor_clues.cpp b/engines/bladerunner/actor_clues.cpp
index 70d3ad50c9..07df81e823 100644
--- a/engines/bladerunner/actor_clues.cpp
+++ b/engines/bladerunner/actor_clues.cpp
@@ -33,11 +33,11 @@
namespace BladeRunner {
-ActorClues::ActorClues(BladeRunnerEngine *vm, int cluesType) {
+ActorClues::ActorClues(BladeRunnerEngine *vm, int cluesLimit) {
_vm = vm;
_count = 0;
_maxCount = 0;
- switch (cluesType) {
+ switch (cluesLimit) {
case 4:
_maxCount = _vm->_gameInfo->getClueCount();
break;
@@ -83,11 +83,11 @@ bool ActorClues::isAcquired(int clueId) const {
if (clueIndex == -1) {
return false;
}
-#if BLADERUNNER_DEBUG_GAME
- return true;
-#else
+// #if BLADERUNNER_DEBUG_GAME
+// return true;
+// #else
return _clues[clueIndex].flags & 0x01;
-#endif
+// #endif
}
int ActorClues::getWeight(int clueId) const {
@@ -346,6 +346,10 @@ void ActorClues::add(int actorId, int clueId, int weight, bool acquired, bool un
++_count;
}
+bool ActorClues::exists(int clueId) const {
+ return findClueIndex(clueId) != -1;
+}
+
void ActorClues::remove(int index) {
if (_vm->_crimesDatabase) {
debug("Actor removed clue: \"%s\"", _vm->_crimesDatabase->getClueText(_clues[index].clueId));
@@ -367,7 +371,7 @@ void ActorClues::remove(int index) {
void ActorClues::save(SaveFileWriteStream &f) {
f.writeInt(_count);
f.writeInt(_maxCount);
- for (int i = 0; i < _count; ++i) {
+ for (int i = 0; i < _maxCount; ++i) {
Clue &c = _clues[i];
f.writeInt(c.clueId);
f.writeInt(c.weight);
@@ -387,7 +391,7 @@ void ActorClues::load(SaveFileReadStream &f) {
_maxCount = f.readInt();
_clues.clear();
_clues.resize(_maxCount);
- for (int i = 0; i < _count; ++i) {
+ for (int i = 0; i < _maxCount; ++i) {
Clue &c = _clues[i];
c.clueId = f.readInt();
c.weight = f.readInt();
@@ -402,8 +406,4 @@ void ActorClues::load(SaveFileReadStream &f) {
}
}
-bool ActorClues::exists(int clueId) const {
- return findClueIndex(clueId) != -1;
-}
-
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/actor_clues.h b/engines/bladerunner/actor_clues.h
index 76690329d3..88af222724 100644
--- a/engines/bladerunner/actor_clues.h
+++ b/engines/bladerunner/actor_clues.h
@@ -60,9 +60,10 @@ public:
};
public:
- ActorClues(BladeRunnerEngine *_vm, int cluesType);
+ ActorClues(BladeRunnerEngine *_vm, int cluesLimit);
void add(int actorId, int clueId, int unknown, bool acquired, bool unknownFlag, int fromActorId);
+ bool exists(int clueId) const;
void acquire(int clueId, bool flag2, int fromActorId);
void lose(int clueId);
@@ -95,7 +96,6 @@ public:
void load(SaveFileReadStream &f);
private:
- bool exists(int clueId) const;
int findClueIndex(int clueId) const;
void remove(int clueIndex);
};
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index 362e0c4b6c..1c08b793b8 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -203,7 +203,80 @@ BladeRunnerEngine::~BladeRunnerEngine() {
}
bool BladeRunnerEngine::hasFeature(EngineFeature f) const {
- return f == kSupportsRTL;
+ return
+ f == kSupportsRTL ||
+ f == kSupportsLoadingDuringRuntime ||
+ f == kSupportsSavingDuringRuntime;
+}
+
+bool BladeRunnerEngine::canLoadGameStateCurrently() {
+ return
+ playerHasControl() &&
+ !_sceneScript->isInsideScript() &&
+ !_aiScripts->isInsideScript() &&
+ !_kia->isOpen() &&
+ !_spinner->isOpen() &&
+ !_vk->isOpen() &&
+ !_elevator->isOpen();
+}
+
+Common::Error BladeRunnerEngine::loadGameState(int slot) {
+ const Common::String saveName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
+
+ Common::InSaveFile *saveFile = getSaveFileManager()->openForLoading(saveName);
+ if (saveFile == nullptr || saveFile->err()) {
+ delete saveFile;
+ return Common::kReadingFailed;
+ }
+
+ BladeRunner::SaveFileHeader header;
+ if (!BladeRunner::SaveFile::readHeader(*saveFile, header)) {
+ error("Invalid savegame");
+ }
+
+ loadGame(*saveFile);
+
+ delete saveFile;
+
+ return Common::kNoError;
+}
+
+bool BladeRunnerEngine::canSaveGameStateCurrently() {
+ return
+ playerHasControl() &&
+ !_sceneScript->isInsideScript() &&
+ !_aiScripts->isInsideScript() &&
+ !_kia->isOpen() &&
+ !_spinner->isOpen() &&
+ !_vk->isOpen() &&
+ !_elevator->isOpen();
+}
+
+Common::Error BladeRunnerEngine::saveGameState(int slot, const Common::String &desc) {
+ const Common::String saveName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
+
+ Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(saveName);
+ if (saveFile == nullptr || saveFile->err()) {
+ delete saveFile;
+ return Common::kReadingFailed;
+ }
+
+ byte *thumbnail = new byte[SaveFile::kThumbnailSize];
+ generateThumbnail(thumbnail);
+
+ BladeRunner::SaveFileHeader header;
+ header._name = desc;
+ BladeRunner::SaveFile::writeHeader(*saveFile, header);
+
+ saveGame(*saveFile, thumbnail);
+
+ saveFile->finalize();
+
+ delete[] thumbnail;
+
+ delete saveFile;
+
+ return Common::kNoError;
}
Common::Error BladeRunnerEngine::run() {
@@ -315,8 +388,8 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
// Seed rand
// TODO: Sine and cosine lookup tables for intervals of 1.0, 4.0, and 12.0
- _cosTable1024 = new Common::CosineTable(1024); // 10-bits = 1024 points for 2*PI;
- _sinTable1024 = new Common::SineTable(1024);
+ _cosTable1024 = new Common::CosineTable(1024); // 10-bits = 1024 points for 2*PI;
+ _sinTable1024 = new Common::SineTable(1024);
_view = new View();
@@ -1640,22 +1713,16 @@ void BladeRunnerEngine::playerGainsControl() {
}
}
-bool BladeRunnerEngine::saveGame(const Common::String &filename, byte *thumbnail) {
- warning("BladeRunnerEngine::saveGame not finished");
-
+bool BladeRunnerEngine::saveGame(Common::WriteStream &stream, const void *thumbnail) {
if (!playerHasControl() || _sceneScript->isInsideScript() || _aiScripts->isInsideScript()) {
return false;
}
- Common::OutSaveFile *commonSaveFile = getSaveFileManager()->openForSaving(filename, false);
- if (commonSaveFile->err()) {
- return false;
- }
-
- SaveFileWriteStream s;
+ Common::MemoryWriteStreamDynamic memoryStream(DisposeAfterUse::Flag::YES);
+ SaveFileWriteStream s(memoryStream);
- s.padBytes(9600); // TODO: thumbnail
- s.writeFloat(-1.0f);
+ s.write(thumbnail, SaveFile::kThumbnailSize);
+ s.writeFloat(1.0f);
_settings->save(s);
_scene->save(s);
_scene->_exits->save(s);
@@ -1691,49 +1758,43 @@ bool BladeRunnerEngine::saveGame(const Common::String &filename, byte *thumbnail
s.writeInt(nextAnimation);
}
_actors[kActorVoiceOver]->save(s);
-
_policeMaze->save(s);
_crimesDatabase->save(s);
s.finalize();
- assert(0 && "ok");
- commonSaveFile->writeUint32LE(s.size() + 4);
- commonSaveFile->write(s.getData(), s.size());
+ stream.writeUint32LE(memoryStream.size() + 4);
+ stream.write(memoryStream.getData(), memoryStream.size());
+ stream.flush();
- return !commonSaveFile->err();
+ return true;
}
-void BladeRunnerEngine::loadGame(const Common::String &filename, byte *thumbnail) {
- warning("BladeRunnerEngine::loadGame not finished");
-
+bool BladeRunnerEngine::loadGame(Common::SeekableReadStream &stream) {
if (!playerHasControl() || _sceneScript->isInsideScript() || _aiScripts->isInsideScript()) {
- return;
- }
-
- Common::InSaveFile *commonSaveFile = getSaveFileManager()->openForLoading(filename);
- if (commonSaveFile->err()) {
- return;
+ return false;
}
- void *buf = malloc(commonSaveFile->size());
- int dataSize = commonSaveFile->read(buf, commonSaveFile->size());
-
- SaveFileReadStream s((const byte*)buf, dataSize);
+ SaveFileReadStream s(stream);
_ambientSounds->removeAllNonLoopingSounds(true);
_ambientSounds->removeAllLoopingSounds(1);
_music->stop(2);
_audioSpeech->stopSpeech();
_actorDialogueQueue->flush(true, false);
+ _screenEffects->_entries.clear();
int size = s.readInt();
- if (size != dataSize) {
- return;
+ if (size != s.size() - s.pos() + 4) {
+ _gameIsLoading = false;
+ return false;
}
- s.skip(9600); // thumbnail
+ _gameIsLoading = true;
+ _settings->setLoadingGame();
+ s.skip(SaveFile::kThumbnailSize); // skip the thumbnail
+ s.skip(4);// always float 1.0, but never used
_settings->load(s);
_scene->load(s);
_scene->_exits->load(s);
@@ -1757,7 +1818,6 @@ void BladeRunnerEngine::loadGame(const Common::String &filename, byte *thumbnail
_obstacles->load(s);
_actorDialogueQueue->load(s);
_waypoints->load(s);
-
for (uint i = 0; i != _gameInfo->getActorCount(); ++i) {
_actors[i]->load(s);
@@ -1768,23 +1828,71 @@ void BladeRunnerEngine::loadGame(const Common::String &filename, byte *thumbnail
_aiScripts->setAnimationState(i, animationState, animationFrame, animationStateNext, nextAnimation);
}
_actors[kActorVoiceOver]->load(s);
-
_policeMaze->load(s);
_crimesDatabase->load(s);
+ _gameIsLoading = false;
+
_settings->setNewSetAndScene(_settings->getSet(), _settings->getScene());
_settings->setChapter(_settings->getChapter());
+
+ return true;
+}
+
+void BladeRunnerEngine::newGame(int difficulty) {
+ _settings->reset();
+ _combat->reset();
+
+ for (uint i = 0; i < _gameInfo->getActorCount(); ++i) {
+ _actors[i]->setup(i);
+ }
+ _actors[kActorVoiceOver]->setup(99);
+
+ for (uint i = 0; i < _gameInfo->getSuspectCount(); ++i) {
+ _suspectsDatabase->get(i)->reset();
+ }
+
+ _gameFlags->clear();
+
+ _gameInfo->getGlobalVarCount();
+
+ for (uint i = 0; i < _gameInfo->getGlobalVarCount(); ++i) {
+ _gameVars[i] = 0;
+ }
+
+ _items->reset();
+ _scores->reset();
+ _kia->reset();
+ _dialogueMenu->clear();
+ _scene->_exits->enable();
+
+ if (difficulty >= 0 && difficulty < 3) {
+ _settings->setDifficulty(difficulty);
+ }
+
+ _settings->setStartingGame();
}
void BladeRunnerEngine::ISez(const Common::String &str) {
debug("\t%s", str.c_str());
}
-void BladeRunnerEngine::blitToScreen(const Graphics::Surface &src) {
+void BladeRunnerEngine::blitToScreen(const Graphics::Surface &src) const {
_system->copyRectToScreen(src.getPixels(), src.pitch, 0, 0, src.w, src.h);
_system->updateScreen();
}
+void BladeRunnerEngine::generateThumbnail(void *thumbnail) const {
+ uint16 *dstPixels = (uint16*)thumbnail;
+
+ for (int y = 0; y < 480; y += 8) {
+ for (int x = 0; x < 640; x += 8) {
+ *dstPixels = *(const uint16 *)_surfaceFront.getBasePtr(x, y);
+ ++dstPixels;
+ }
+ }
+}
+
GUI::Debugger *BladeRunnerEngine::getDebugger() {
return _debugger;
}
diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h
index 8d45d6a806..817c3066e0 100644
--- a/engines/bladerunner/bladerunner.h
+++ b/engines/bladerunner/bladerunner.h
@@ -24,6 +24,7 @@
#define BLADERUNNER_BLADERUNNER_H
#include "bladerunner/archive.h"
+#include "bladerunner/savefile.h"
#include "common/array.h"
#include "common/cosinetables.h"
@@ -37,7 +38,7 @@
//TODO: remove these when game is playable
#define BLADERUNNER_DEBUG_CONSOLE 0
-#define BLADERUNNER_DEBUG_GAME 0
+#define BLADERUNNER_DEBUG_GAME 1
namespace Common {
struct Event;
@@ -224,7 +225,11 @@ public:
BladeRunnerEngine(OSystem *syst, const ADGameDescription *desc);
~BladeRunnerEngine();
- bool hasFeature(EngineFeature f) const;
+ bool hasFeature(EngineFeature f) const override;
+ bool canLoadGameStateCurrently() override;
+ Common::Error loadGameState(int slot) override;
+ bool canSaveGameStateCurrently() override;
+ Common::Error saveGameState(int slot, const Common::String &desc) override;
Common::Error run();
@@ -271,14 +276,15 @@ public:
void playerLosesControl();
void playerGainsControl();
- bool saveGame(const Common::String &filename, byte *thumbnail);
- void loadGame(const Common::String &filename, byte *thumbnail);
- void newGame();
+ bool saveGame(Common::WriteStream &stream, const void *thumbnail);
+ bool loadGame(Common::SeekableReadStream &stream);
+ void newGame(int difficulty);
void autoSaveGame();
void ISez(const Common::String &str);
- void blitToScreen(const Graphics::Surface &src);
+ void blitToScreen(const Graphics::Surface &src) const;
+ void generateThumbnail(void *thumbnail) const;
GUI::Debugger *getDebugger();
};
diff --git a/engines/bladerunner/crimes_database.cpp b/engines/bladerunner/crimes_database.cpp
index e9faa22b41..91def98aba 100644
--- a/engines/bladerunner/crimes_database.cpp
+++ b/engines/bladerunner/crimes_database.cpp
@@ -73,14 +73,14 @@ const char *CrimesDatabase::getClueText(int clueId) const {
void CrimesDatabase::save(SaveFileWriteStream &f) {
for (int i = 0; i < _crimeCount; ++i) {
- uint8 c = _crimes[i];
- f.writeByte(c);
+ int8 c = _crimes[i];
+ f.writeSByte(c);
}
}
void CrimesDatabase::load(SaveFileReadStream &f) {
for (int i = 0; i < _crimeCount; ++i) {
- _crimes[i] = f.readByte();
+ _crimes[i] = f.readSByte();
}
}
diff --git a/engines/bladerunner/debugger.cpp b/engines/bladerunner/debugger.cpp
index 0355f9d0f5..6f7e5d14a2 100644
--- a/engines/bladerunner/debugger.cpp
+++ b/engines/bladerunner/debugger.cpp
@@ -71,6 +71,8 @@ Debugger::Debugger(BladeRunnerEngine *vm) : GUI::Debugger() {
registerCmd("say", WRAP_METHOD(Debugger, cmdSay));
registerCmd("scene", WRAP_METHOD(Debugger, cmdScene));
registerCmd("var", WRAP_METHOD(Debugger, cmdVariable));
+ registerCmd("load", WRAP_METHOD(Debugger, cmdLoad));
+ registerCmd("save", WRAP_METHOD(Debugger, cmdSave));
}
Debugger::~Debugger() {
@@ -358,6 +360,59 @@ bool Debugger::cmdVariable(int argc, const char **argv) {
return true;
}
+bool Debugger::cmdLoad(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Loads a save game from original format.\n");
+ debugPrintf("Usage: %s <file path>\n", argv[0]);
+ return true;
+ }
+
+ Common::FSNode fs(argv[1]);
+
+ if (!fs.isReadable()) {
+ debugPrintf("Warning: File %s does not exist or is not readable\n", argv[1]);
+ return true;
+ }
+
+ Common::SeekableReadStream *saveFile = fs.createReadStream();
+
+ _vm->loadGame(*saveFile);
+
+ delete saveFile;
+
+ return false;
+}
+
+bool Debugger::cmdSave(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Saves game to original format.\n");
+ debugPrintf("Usage: %s <file path>\n", argv[0]);
+ return true;
+ }
+
+ Common::FSNode fs(argv[1]);
+
+ if (fs.exists() && !fs.isWritable()) {
+ debugPrintf("Warning: File %s is not writable\n", argv[1]);
+ return true;
+ }
+
+ Common::WriteStream *saveFile = fs.createWriteStream();
+
+ uint16 *thumbnail = new uint16[SaveFile::kThumbnailSize];
+ _vm->generateThumbnail(thumbnail);
+
+ _vm->saveGame(*saveFile, thumbnail);
+
+ saveFile->finalize();
+
+ delete[] thumbnail;
+
+ delete saveFile;
+
+ return true;
+}
+
void Debugger::drawBBox(Vector3 start, Vector3 end, View *view, Graphics::Surface *surface, int color) {
Vector3 bfl = view->calculateScreenPosition(Vector3(start.x, start.y, start.z));
Vector3 bfr = view->calculateScreenPosition(Vector3(start.x, end.y, start.z));
diff --git a/engines/bladerunner/debugger.h b/engines/bladerunner/debugger.h
index 64e312ae20..fef545eda1 100644
--- a/engines/bladerunner/debugger.h
+++ b/engines/bladerunner/debugger.h
@@ -59,6 +59,8 @@ public:
bool cmdSay(int argc, const char **argv);
bool cmdScene(int argc, const char **argv);
bool cmdVariable(int argc, const char **argv);
+ bool cmdLoad(int argc, const char **argv);
+ bool cmdSave(int argc, const char **argv);
void drawBBox(Vector3 start, Vector3 end, View *view, Graphics::Surface *surface, int color);
void drawSceneObjects();
diff --git a/engines/bladerunner/detection.cpp b/engines/bladerunner/detection.cpp
index 934eea7759..8cd4288a0d 100644
--- a/engines/bladerunner/detection.cpp
+++ b/engines/bladerunner/detection.cpp
@@ -20,12 +20,17 @@
*
*/
-#include "base/plugins.h"
-
-#include "engines/advancedDetector.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/detection_tables.h"
+#include "bladerunner/savefile.h"
+
+#include "common/config-manager.h"
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
+
+#include "engines/advancedDetector.h"
namespace BladeRunner {
@@ -38,19 +43,32 @@ static const PlainGameDescriptor bladeRunnerGames[] = {
class BladeRunnerMetaEngine : public AdvancedMetaEngine {
public:
- BladeRunnerMetaEngine() : AdvancedMetaEngine(BladeRunner::gameDescriptions, sizeof(BladeRunner::gameDescriptions[0]), BladeRunner::bladeRunnerGames) {
- }
+ BladeRunnerMetaEngine();
- virtual const char *getName() const {
- return "Blade Runner Engine";
- }
+ const char *getName() const override;
+ const char *getOriginalCopyright() const override;
+ bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
+ bool hasFeature(MetaEngineFeature f) const override;
+ SaveStateList listSaves(const char *target) const override;
+ int getMaximumSaveSlot() const override;
+ void removeSaveState(const char *target, int slot) const override;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
+};
- virtual const char *getOriginalCopyright() const {
- return "Blade Runner (C) Westwood Studios.";
- }
+BladeRunnerMetaEngine::BladeRunnerMetaEngine()
+ : AdvancedMetaEngine(
+ BladeRunner::gameDescriptions,
+ sizeof(BladeRunner::gameDescriptions[0]),
+ BladeRunner::bladeRunnerGames) {}
- virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
-};
+
+const char *BladeRunnerMetaEngine::getName() const {
+ return "Blade Runner Engine";
+}
+
+const char *BladeRunnerMetaEngine::getOriginalCopyright() const {
+ return "Blade Runner (C) 1997 Westwood Studios";
+}
bool BladeRunnerMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
*engine = new BladeRunner::BladeRunnerEngine(syst, desc);
@@ -58,6 +76,71 @@ bool BladeRunnerMetaEngine::createInstance(OSystem *syst, Engine **engine, const
return true;
}
+bool BladeRunnerMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ f == kSupportsListSaves ||
+ f == kSupportsLoadingDuringStartup ||
+ f == kSupportsDeleteSave ||
+ f == kSavesSupportMetaInfo ||
+ f == kSavesSupportThumbnail ||
+ f == kSimpleSavesNames;
+}
+
+SaveStateList BladeRunnerMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray files = saveFileMan->listSavefiles(Common::String::format("%s.###", target));
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator fileName = files.begin(); fileName != files.end(); ++fileName) {
+ Common::InSaveFile *saveFile = saveFileMan->openForLoading(*fileName);
+ if (saveFile == nullptr || saveFile->err()) {
+ warning("Cannot open save file '%s'", fileName->c_str());
+ continue;
+ }
+
+ BladeRunner::SaveFileHeader header;
+ BladeRunner::SaveFile::readHeader(*saveFile, header);
+
+ int slotNum = atoi(fileName->c_str() + fileName->size() - 3);
+ saveList.push_back(SaveStateDescriptor(slotNum, header._name));
+ }
+
+ // Sort saves based on slot number.
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+ return saveList;
+}
+
+int BladeRunnerMetaEngine::getMaximumSaveSlot() const {
+ return 999;
+}
+
+void BladeRunnerMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String filename = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(filename);
+}
+
+SaveStateDescriptor BladeRunnerMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String filename = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(filename);
+
+ if (saveFile == nullptr || saveFile->err()) {
+ return SaveStateDescriptor();
+ }
+
+ BladeRunner::SaveFileHeader header;
+ if (!BladeRunner::SaveFile::readHeader(*saveFile, header, false)) {
+ delete saveFile;
+ return SaveStateDescriptor();
+ }
+ delete saveFile;
+
+ SaveStateDescriptor desc(slot, header._name);
+ desc.setThumbnail(header._thumbnail);
+ desc.setSaveDate(header._year, header._month, header._day);
+ desc.setSaveTime(header._hour, header._minute);
+ return desc;
+}
+
#if PLUGIN_ENABLED_DYNAMIC(BLADERUNNER)
REGISTER_PLUGIN_DYNAMIC(BLADERUNNER, PLUGIN_TYPE_ENGINE, BladeRunnerMetaEngine);
#else
diff --git a/engines/bladerunner/detection_tables.h b/engines/bladerunner/detection_tables.h
index 3c509f4314..5d1a851598 100644
--- a/engines/bladerunner/detection_tables.h
+++ b/engines/bladerunner/detection_tables.h
@@ -23,6 +23,8 @@
#ifndef BLADERUNNER_DETECTION_TABLES_H
#define BLADERUNNER_DETECTION_TABLES_H
+#include "engines/advancedDetector.h"
+
namespace BladeRunner {
static const ADGameDescription gameDescriptions[] = {
diff --git a/engines/bladerunner/dialogue_menu.cpp b/engines/bladerunner/dialogue_menu.cpp
index d9a7c62866..4f82326564 100644
--- a/engines/bladerunner/dialogue_menu.cpp
+++ b/engines/bladerunner/dialogue_menu.cpp
@@ -183,7 +183,7 @@ int DialogueMenu::queryInput() {
}
_vm->gameTick();
- } while (_waitingForInput);
+ } while (_vm->_gameIsRunning && _waitingForInput);
} else if (agenda == kPlayerAgendaErratic) {
int tries = 0;
bool searching = true;
diff --git a/engines/bladerunner/dialogue_menu.h b/engines/bladerunner/dialogue_menu.h
index 6dfd3efdc6..4029fe465b 100644
--- a/engines/bladerunner/dialogue_menu.h
+++ b/engines/bladerunner/dialogue_menu.h
@@ -81,6 +81,8 @@ public:
DialogueMenu(BladeRunnerEngine *vm);
~DialogueMenu();
+ void clear();
+
bool loadText(const Common::String &name);
bool show();
@@ -106,7 +108,6 @@ private:
int getAnswerIndex(int answer) const;
const char *getText(int id) const;
void calculatePosition(int unusedX = 0, int unusedY = 0);
- void clear();
void reset();
static void darkenRect(Graphics::Surface &s, int x1, int y1, int x2, int y2);
diff --git a/engines/bladerunner/game_flags.cpp b/engines/bladerunner/game_flags.cpp
index 6fdcb89363..e2ae3c3259 100644
--- a/engines/bladerunner/game_flags.cpp
+++ b/engines/bladerunner/game_flags.cpp
@@ -36,14 +36,19 @@ GameFlags::~GameFlags() {
delete[] _flags;
}
+void GameFlags::clear() {
+ for (int i = 0; i <= _flagCount; ++i) {
+ reset(i);
+ }
+}
+
void GameFlags::setFlagCount(int count) {
assert(count > 0);
_flagCount = count;
_flags = new uint32[count / 32 + 1]();
- for (int i = 0; i <= _flagCount; ++i)
- reset(i);
+ clear();
}
void GameFlags::set(int flag) {
diff --git a/engines/bladerunner/game_flags.h b/engines/bladerunner/game_flags.h
index 837537f689..3b0d93f8c8 100644
--- a/engines/bladerunner/game_flags.h
+++ b/engines/bladerunner/game_flags.h
@@ -38,6 +38,7 @@ public:
GameFlags();
~GameFlags();
+ void clear();
void setFlagCount(int count);
void set(int flag);
diff --git a/engines/bladerunner/item.cpp b/engines/bladerunner/item.cpp
index 2f82fc0b35..751978bfd3 100644
--- a/engines/bladerunner/item.cpp
+++ b/engines/bladerunner/item.cpp
@@ -177,7 +177,7 @@ bool Item::isUnderMouse(int mouseX, int mouseY) const {
void Item::save(SaveFileWriteStream &f) {
f.writeInt(_setId);
f.writeInt(_itemId);
- f.writeBoundingBox(_boundingBox);
+ f.writeBoundingBox(_boundingBox, false);
f.writeRect(_screenRectangle);
f.writeInt(_animationId);
f.writeVector3(_position);
@@ -199,7 +199,7 @@ void Item::save(SaveFileWriteStream &f) {
void Item::load(SaveFileReadStream &f) {
_setId = f.readInt();
_itemId = f.readInt();
- _boundingBox = f.readBoundingBox();
+ _boundingBox = f.readBoundingBox(false);
_screenRectangle = f.readRect();
_animationId = f.readInt();
_position = f.readVector3();
diff --git a/engines/bladerunner/items.cpp b/engines/bladerunner/items.cpp
index a2cb9da194..32594515e6 100644
--- a/engines/bladerunner/items.cpp
+++ b/engines/bladerunner/items.cpp
@@ -35,6 +35,10 @@ Items::Items(BladeRunnerEngine *vm) {
}
Items::~Items() {
+ reset();
+}
+
+void Items::reset() {
for (int i = _items.size() - 1; i >= 0; i--) {
delete _items.remove_at(i);
}
diff --git a/engines/bladerunner/items.h b/engines/bladerunner/items.h
index ce29a77787..a2c7720b62 100644
--- a/engines/bladerunner/items.h
+++ b/engines/bladerunner/items.h
@@ -42,6 +42,8 @@ public:
Items(BladeRunnerEngine *vm);
~Items();
+ void reset();
+
void getXYZ(int itemId, float *x, float *y, float *z) const;
void setXYZ(int itemId, Vector3 position);
void getWidthHeight(int itemId, int *width, int *height) const;
diff --git a/engines/bladerunner/outtake.cpp b/engines/bladerunner/outtake.cpp
index 6d76162dd9..187f46c0bd 100644
--- a/engines/bladerunner/outtake.cpp
+++ b/engines/bladerunner/outtake.cpp
@@ -44,9 +44,9 @@ void OuttakePlayer::play(const Common::String &name, bool noLocalization, int co
resName = resName + ".VQA";
- VQAPlayer vqa_player(_vm, &_vm->_surfaceFront);
+ VQAPlayer vqa_player(_vm, &_vm->_surfaceFront, resName);
- vqa_player.open(resName);
+ vqa_player.open();
_vm->_mixer->stopAll();
while (!_vm->shouldQuit()) {
diff --git a/engines/bladerunner/overlays.cpp b/engines/bladerunner/overlays.cpp
index 65ba83f15d..5bbac87c36 100644
--- a/engines/bladerunner/overlays.cpp
+++ b/engines/bladerunner/overlays.cpp
@@ -69,14 +69,15 @@ int Overlays::play(const Common::String &name, int loopId, bool loopForever, boo
_videos[index].loaded = true;
_videos[index].name = name;
_videos[index].hash = hash;
- _videos[index].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront);
+ _videos[index].loopId = loopId;
+ _videos[index].loopForever = loopForever;
+ _videos[index].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront, Common::String::format("%s.VQA", name.c_str()));
// repeat forever
_videos[index].vqaPlayer->setBeginAndEndFrame(0, 0, -1, kLoopSetModeJustStart, nullptr, nullptr);
}
- Common::String resourceName = Common::String::format("%s.VQA", name.c_str());
- _videos[index].vqaPlayer->open(resourceName);
+ _videos[index].vqaPlayer->open();
_videos[index].vqaPlayer->setLoop(
loopId,
loopForever ? -1 : 0,
@@ -86,6 +87,29 @@ int Overlays::play(const Common::String &name, int loopId, bool loopForever, boo
return index;
}
+void Overlays::resume(bool isLoadingGame) {
+
+ for (int i = 0; i < kOverlayVideos; ++i) {
+ if (_videos[i].loaded && isLoadingGame) {
+ _videos[i].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront, Common::String::format("%s.VQA", _videos[i].name.c_str()));
+ if (!_videos[i].vqaPlayer) {
+ resetSingle(i);
+ continue;
+ }
+
+ _videos[i].vqaPlayer->open();
+ _videos[i].vqaPlayer->setLoop(
+ _videos[i].loopId,
+ _videos[i].loopForever ? -1 : 0,
+ kLoopSetModeImmediate,
+ nullptr, nullptr);
+
+ _videos[i].vqaPlayer->seekToFrame(_videos[i].frame);
+ _videos[i].vqaPlayer->update(true);
+ }
+ }
+}
+
void Overlays::remove(const Common::String &name) {
int index = findByHash(MIXArchive::getHash(name));
if (index >= 0) {
@@ -104,8 +128,8 @@ void Overlays::removeAll() {
void Overlays::tick() {
for (int i = 0; i < kOverlayVideos; ++i) {
if (_videos[i].loaded) {
- int frame = _videos[i].vqaPlayer->update(true);
- if (frame < 0) {
+ _videos[i].frame = _videos[i].vqaPlayer->update(true);
+ if (_videos[i].frame < 0) {
resetSingle(i);
}
}
@@ -138,7 +162,7 @@ void Overlays::resetSingle(int i) {
}
_videos[i].loaded = false;
_videos[i].hash = 0;
- _videos[i].field2 = -1;
+ _videos[i].frame = -1;
_videos[i].name.clear();
}
@@ -155,9 +179,9 @@ void Overlays::save(SaveFileWriteStream &f) {
f.writeInt(0); // vqaPlayer pointer
f.writeStringSz(ov.name, 13);
f.writeSint32LE(ov.hash);
- f.writeInt(ov.field0);
- f.writeInt(ov.field1);
- f.writeInt(ov.field2);
+ f.writeInt(ov.loopId);
+ f.writeBool(ov.loopForever);
+ f.writeInt(ov.frame);
}
}
@@ -171,9 +195,9 @@ void Overlays::load(SaveFileReadStream &f) {
ov.vqaPlayer = nullptr;
ov.name = f.readStringSz(13);
ov.hash = f.readSint32LE();
- ov.field0 = f.readInt();
- ov.field1 = f.readInt();
- ov.field2 = f.readInt();
+ ov.loopId = f.readInt();
+ ov.loopForever = f.readBool();
+ ov.frame = f.readInt();
}
}
diff --git a/engines/bladerunner/overlays.h b/engines/bladerunner/overlays.h
index 405acbc264..e250db9810 100644
--- a/engines/bladerunner/overlays.h
+++ b/engines/bladerunner/overlays.h
@@ -45,9 +45,9 @@ class Overlays {
VQAPlayer *vqaPlayer;
Common::String name;
int32 hash;
- int field0;
- int field1;
- int field2;
+ int loopId;
+ bool loopForever;
+ int frame;
};
BladeRunnerEngine *_vm;
@@ -59,6 +59,7 @@ public:
~Overlays();
int play(const Common::String &name, int loopId, bool loopForever, bool startNow, int a6);
+ void resume(bool isLoadingGame);
void remove(const Common::String &name);
void removeAll();
void tick();
diff --git a/engines/bladerunner/savefile.cpp b/engines/bladerunner/savefile.cpp
index 3528a6bb82..b0fb1e7fd6 100644
--- a/engines/bladerunner/savefile.cpp
+++ b/engines/bladerunner/savefile.cpp
@@ -27,13 +27,76 @@
#include "common/rect.h"
#include "common/savefile.h"
+#include "common/system.h"
+
+#include "graphics/thumbnail.h"
namespace BladeRunner {
-SaveFileWriteStream::SaveFileWriteStream()
- : MemoryWriteStreamDynamic(DisposeAfterUse::YES) {
+bool SaveFile::readHeader(Common::SeekableReadStream &in, SaveFileHeader &header, bool skipThumbnail) {
+ SaveFileReadStream s(in);
+
+ if (s.readUint32BE() != kTag) {
+ warning("No header found in save file");
+ return false;
+ }
+
+ header._version = s.readByte();
+ if (header._version != kVersion) {
+ warning("Unsupported version of save file %u, supported is %u", header._version, kVersion);
+ return false;
+ }
+
+ header._name = s.readStringSz(kNameLength);
+
+ header._year = s.readUint16LE();
+ header._month = s.readUint16LE();
+ header._day = s.readUint16LE();
+ header._hour = s.readUint16LE();
+ header._minute = s.readUint16LE();
+
+ header._thumbnail = nullptr;
+
+ if (!skipThumbnail) {
+ header._thumbnail = new Graphics::Surface();
+
+ int32 pos = s.pos();
+
+ s.skip(4); //skip size;
+
+ void *thumbnailData = new byte[kThumbnailSize];
+ s.read(thumbnailData, kThumbnailSize);
+
+ // TODO: cleanup - remove magic constants
+ header._thumbnail->init(80, 60, 160, thumbnailData, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
+
+ s.seek(pos);
+ }
+
+ return true;
+}
+
+bool SaveFile::writeHeader(Common::WriteStream &out, SaveFileHeader &header) {
+ SaveFileWriteStream s(out);
+
+ s.writeUint32BE(kTag);
+ s.writeByte(kVersion);
+
+ s.writeStringSz(header._name, kNameLength);
+
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ s.writeUint16LE(td.tm_year + 1900);
+ s.writeUint16LE(td.tm_mon + 1);
+ s.writeUint16LE(td.tm_mday);
+ s.writeUint16LE(td.tm_hour);
+ s.writeUint16LE(td.tm_min);
+
+ return true;
}
+SaveFileWriteStream::SaveFileWriteStream(Common::WriteStream &s) : _s(s) {}
+
void SaveFileWriteStream::debug(char *p) {
write(p, strlen(p) + 1);
}
@@ -48,7 +111,7 @@ void SaveFileWriteStream::writeInt(int v) {
writeUint32LE(v);
}
-void SaveFileWriteStream::writeFloat(int v) {
+void SaveFileWriteStream::writeFloat(float v) {
writeFloatLE(v);
}
@@ -80,7 +143,7 @@ void SaveFileWriteStream::writeRect(const Common::Rect &v) {
writeUint32LE(v.bottom);
}
-void SaveFileWriteStream::writeBoundingBox(const BoundingBox &v) {
+void SaveFileWriteStream::writeBoundingBox(const BoundingBox &v, bool serialized) {
float x0, y0, z0, x1, y1, z1;
v.getXYZ(&x0, &y0, &z0, &x1, &y1, &z1);
@@ -92,14 +155,13 @@ void SaveFileWriteStream::writeBoundingBox(const BoundingBox &v) {
writeFloatLE(z1);
// Bounding boxes have a lot of extra data that's never actually used
- for (int i = 0; i != 96; ++i) {
+ int count = serialized ? 96 : 64;
+ for (int i = 0; i < count; ++i) {
writeFloatLE(0.0f);
}
}
-SaveFileReadStream::SaveFileReadStream(const byte *dataPtr, uint32 dataSize)
- : MemoryReadStream(dataPtr, dataSize, DisposeAfterUse::YES) {
-}
+SaveFileReadStream::SaveFileReadStream(Common::SeekableReadStream &s) : _s(s) {}
int SaveFileReadStream::readInt() {
return readUint32LE();
@@ -114,10 +176,10 @@ bool SaveFileReadStream::readBool() {
}
Common::String SaveFileReadStream::readStringSz(int sz) {
- char *buf = (char *)malloc(sz);
+ char *buf = new char[sz];
read(buf, sz);
Common::String result = buf;
- free(buf);
+ delete[] buf;
return result;
}
@@ -145,18 +207,22 @@ Common::Rect SaveFileReadStream::readRect() {
return result;
}
-BoundingBox SaveFileReadStream::readBoundingBox() {
+BoundingBox SaveFileReadStream::readBoundingBox(bool serialized) {
float x0, y0, z0, x1, y1, z1;
x0 = readFloatLE();
y0 = readFloatLE();
z0 = readFloatLE();
+
x1 = readFloatLE();
y1 = readFloatLE();
z1 = readFloatLE();
- // Bounding boxes have a lot of extra data that's never actually used
- skip(384);
+ // Bounding boxes have a lot of extra data that's never actually used, and there two formats for storing bounding boxes.
+ int count = serialized ? 96 : 64;
+ for (int i = 0; i < count; ++i) {
+ readFloatLE();
+ }
return BoundingBox(x0, y0, z0, x1, y1, z1);
}
diff --git a/engines/bladerunner/savefile.h b/engines/bladerunner/savefile.h
index 4dfdb20bd4..bcd1619496 100644
--- a/engines/bladerunner/savefile.h
+++ b/engines/bladerunner/savefile.h
@@ -26,6 +26,8 @@
#include "common/memstream.h"
#include "common/types.h"
+#include "graphics/surface.h"
+
namespace Common {
class OutSaveFile;
class String;
@@ -38,27 +40,67 @@ class Vector2;
class Vector3;
class BoundingBox;
-class SaveFileWriteStream : public Common::MemoryWriteStreamDynamic {
+struct SaveFileHeader {
+ uint8 _version;
+ Common::String _name;
+ int _year;
+ int _month;
+ int _day;
+ int _hour;
+ int _minute;
+ Graphics::Surface *_thumbnail;
+};
+
+class SaveFile {
+private:
+ static const uint32 kTag = MKTAG('B', 'R', 'S', 'V');
+ static const uint32 kVersion = 1;
+ static const uint32 kNameLength = 32;
+
+public:
+ static const uint32 kThumbnailSize = 9600; // 80x60x16bpp
+
+ static bool readHeader(Common::SeekableReadStream &in, SaveFileHeader &header, bool skipThumbnail = true);
+ static bool writeHeader(Common::WriteStream &out, SaveFileHeader &header);
+};
+
+class SaveFileWriteStream : public Common::WriteStream {
+private:
+ Common::WriteStream &_s;
+
public:
- SaveFileWriteStream();
+ SaveFileWriteStream(Common::WriteStream &s);
+
+ uint32 write(const void *dataPtr, uint32 dataSize) override { return _s.write(dataPtr, dataSize); }
+ bool flush() override { return _s.flush(); }
+ int32 pos() const override { return _s.pos(); }
void debug(char *p);
void padBytes(int count);
void writeInt(int v);
- void writeFloat(int v);
+ void writeFloat(float v);
void writeBool(bool v);
void writeStringSz(const Common::String &s, int sz);
void writeVector2(const Vector2 &v);
void writeVector3(const Vector3 &v);
void writeRect(const Common::Rect &v);
- void writeBoundingBox(const BoundingBox &v);
+ void writeBoundingBox(const BoundingBox &v, bool serialized);
};
-class SaveFileReadStream : public Common::MemoryReadStream {
+class SaveFileReadStream : public Common::SeekableReadStream {
+private:
+ Common::SeekableReadStream &_s;
+
public:
- SaveFileReadStream(const byte *dataPtr, uint32 dataSize);
+ SaveFileReadStream(Common::SeekableReadStream &s);
+
+ bool eos() const override { return _s.eos(); }
+ uint32 read(void *dataPtr, uint32 dataSize) override { return _s.read(dataPtr, dataSize); }
+ int32 pos() const override { return _s.pos(); }
+ int32 size() const override { return _s.size(); }
+ bool seek(int32 offset, int whence = SEEK_SET) override { return _s.seek(offset, whence); }
int readInt();
float readFloat();
@@ -67,7 +109,7 @@ public:
Vector2 readVector2();
Vector3 readVector3();
Common::Rect readRect();
- BoundingBox readBoundingBox();
+ BoundingBox readBoundingBox(bool serialized);
};
} // End of namespace BladeRunner
diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp
index fe8dbc7b61..09764c9e50 100644
--- a/engines/bladerunner/scene.cpp
+++ b/engines/bladerunner/scene.cpp
@@ -87,7 +87,7 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
const Common::String sceneName = _vm->_gameInfo->getSceneName(_sceneId);
if (isLoadingGame) {
- // TODO: _vm->overlays->resume()
+ _vm->_overlays->resume(true);
} else {
_regions->clear();
_exits->clear();
@@ -113,7 +113,7 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
delete _vqaPlayer;
}
- _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack);
+ _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack, vqaName);
if (!_vm->_sceneScript->open(sceneName)) {
return false;
@@ -138,7 +138,7 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) {
return true;
}
- if (!_vqaPlayer->open(vqaName)) {
+ if (!_vqaPlayer->open()) {
return false;
}
@@ -253,7 +253,9 @@ void Scene::resume(bool isLoadingGame) {
int targetFrame = _frame;
- if (!isLoadingGame) {
+ if (isLoadingGame) {
+ _vqaPlayer->open();
+ } else {
_vm->_zbuffer->disable();
}
diff --git a/engines/bladerunner/scene_objects.cpp b/engines/bladerunner/scene_objects.cpp
index 30802a8d64..51538cd6fc 100644
--- a/engines/bladerunner/scene_objects.cpp
+++ b/engines/bladerunner/scene_objects.cpp
@@ -331,7 +331,7 @@ void SceneObjects::save(SaveFileWriteStream &f) {
for (int i = 0; i < kSceneObjectCount; ++i) {
f.writeInt(_sceneObjects[i].id);
f.writeInt(_sceneObjects[i].type);
- f.writeBoundingBox(_sceneObjects[i].boundingBox);
+ f.writeBoundingBox(_sceneObjects[i].boundingBox, true);
f.writeRect(_sceneObjects[i].screenRectangle);
f.writeFloat(_sceneObjects[i].distanceToCamera);
f.writeBool(_sceneObjects[i].isPresent);
@@ -352,7 +352,8 @@ void SceneObjects::load(SaveFileReadStream &f) {
for (int i = 0; i < kSceneObjectCount; ++i) {
_sceneObjects[i].id = f.readInt();
_sceneObjects[i].type = (SceneObjectType)f.readInt();
- _sceneObjects[i].boundingBox = f.readBoundingBox();
+ _sceneObjects[i].boundingBox = f.readBoundingBox(true);
+ debug("screenRectangle[%i]: %08x", i, f.pos());
_sceneObjects[i].screenRectangle = f.readRect();
_sceneObjects[i].distanceToCamera = f.readFloat();
_sceneObjects[i].isPresent = f.readBool();
diff --git a/engines/bladerunner/script/ai_script.cpp b/engines/bladerunner/script/ai_script.cpp
index b328824de1..6addc4382b 100644
--- a/engines/bladerunner/script/ai_script.cpp
+++ b/engines/bladerunner/script/ai_script.cpp
@@ -364,7 +364,6 @@ void AIScripts::queryAnimationState(int actor, int *animationState, int *animati
_inScriptCounter++;
if (_AIScripts[actor]) {
- _AIScripts[actor]->FledCombat();
_AIScripts[actor]->QueryAnimationState(animationState, animationFrame, animationStateNext, animationNext);
}
_inScriptCounter--;
diff --git a/engines/bladerunner/script/police_maze.cpp b/engines/bladerunner/script/police_maze.cpp
index a85fa07451..284b55dcb0 100644
--- a/engines/bladerunner/script/police_maze.cpp
+++ b/engines/bladerunner/script/police_maze.cpp
@@ -175,7 +175,7 @@ void PoliceMazeTargetTrack::clear(bool isLoadingGame) {
void PoliceMazeTargetTrack::add(int trackId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, const int *instructions, bool isActive) {
_data = (const int *)instructions;
- if (true /* !GameIsLoading */) { // TODO: FIXME
+ if (!_vm->_gameIsLoading) {
_itemId = trackId;
_pointCount = steps;
_dataIndex = 0;
diff --git a/engines/bladerunner/script/scene/rc01.cpp b/engines/bladerunner/script/scene/rc01.cpp
index db89807022..b217d030f9 100644
--- a/engines/bladerunner/script/scene/rc01.cpp
+++ b/engines/bladerunner/script/scene/rc01.cpp
@@ -50,7 +50,7 @@ void SceneScriptRC01::InitializeScene() {
#if BLADERUNNER_DEBUG_GAME
//TODO: not part of game, remove
Game_Flag_Set(kFlagIntroPlayed); // force skip intro
- Game_Flag_Set(kFlagRC02toRC01); // no landing
+ Game_Flag_Set(kFlagRC02toRC01); // no landing
// Game_Flag_Set(kFlagRC01PoliceDone);
// Game_Flag_Set(kFlagKIAPrivacyAddon);
// Game_Flag_Set(kFlagZubenRetired);
@@ -74,7 +74,7 @@ void SceneScriptRC01::InitializeScene() {
// Global_Variable_Set(kVariableChapter, 2);
// Chapter_Enter(2, kSetRC03, kSceneRC03);
- Set_Enter(14, 73);
+ // Set_Enter(14, 73);
#endif
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index 92fbc2b4a0..9d9243afa5 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -589,7 +589,7 @@ void ScriptBase::Loop_Actor_Travel_Stairs(int actorId, int stepCount, bool up, i
break;
}
}
- } while (true);
+ } while (_vm->_gameIsRunning);
actor->setImmunityToObstacles(immunityToObstacles);
actor->setAtXYZ(Vector3(actor->getX(), targetY, actor->getZ()), actor->getFacing(), true, false, false);
@@ -632,7 +632,7 @@ void ScriptBase::Loop_Actor_Travel_Ladder(int actorId, int stepCount, bool up, i
break;
}
}
- } while (true);
+ } while (_vm->_gameIsRunning);
actor->setImmunityToObstacles(immunityToObstacles);
actor->setAtXYZ(Vector3(actor->getX(), targetY, actor->getZ()), actor->getFacing(), true, false, false);
@@ -730,7 +730,7 @@ int ScriptBase::Animation_Skip_To_Frame() {
void ScriptBase::Delay(int miliseconds) {
Player_Loses_Control();
int endTime = _vm->getTotalPlayTime() + miliseconds;
- while ((int)_vm->getTotalPlayTime() < endTime) {
+ while (_vm->_gameIsRunning && (int)_vm->getTotalPlayTime() < endTime) {
_vm->gameTick();
}
Player_Gains_Control();
diff --git a/engines/bladerunner/set.cpp b/engines/bladerunner/set.cpp
index ac026a4d76..8111d0b38c 100644
--- a/engines/bladerunner/set.cpp
+++ b/engines/bladerunner/set.cpp
@@ -340,7 +340,7 @@ void Set::save(SaveFileWriteStream &f) {
for (int i = 0; i != _objectCount; ++i) {
f.writeStringSz(_objects[i].name, 20);
- f.writeBoundingBox(_objects[i].bbox);
+ f.writeBoundingBox(_objects[i].bbox, true);
f.writeBool(_objects[i].isObstacle);
f.writeBool(_objects[i].isClickable);
f.writeBool(_objects[i].isHotMouse);
@@ -375,7 +375,7 @@ void Set::load(SaveFileReadStream &f) {
for (int i = 0; i != _objectCount; ++i) {
_objects[i].name = f.readStringSz(20);
- _objects[i].bbox = f.readBoundingBox();
+ _objects[i].bbox = f.readBoundingBox(true);
_objects[i].isObstacle = f.readBool();
_objects[i].isClickable = f.readBool();
_objects[i].isHotMouse = f.readBool();
diff --git a/engines/bladerunner/settings.cpp b/engines/bladerunner/settings.cpp
index 071adf6dd5..6c3e5a7e33 100644
--- a/engines/bladerunner/settings.cpp
+++ b/engines/bladerunner/settings.cpp
@@ -73,6 +73,13 @@ Settings::Settings(BladeRunnerEngine *vm) {
_learyMode = false;
}
+void Settings::reset() {
+ _ammoType = 0;
+ _ammoAmounts[0] = 1;
+ _ammoAmounts[1] = 0;
+ _ammoAmounts[2] = 0;
+}
+
bool Settings::openNewScene() {
if (_newSet == -1) {
assert(_newScene == -1);
@@ -108,8 +115,9 @@ bool Settings::openNewScene() {
return false;
}
_chapter = newChapter;
- if (_startingGame)
+ if (_startingGame) {
_startingGame = false;
+ }
}
if (!_vm->_scene->open(newSet, newScene, _loadingGame)) {
@@ -184,6 +192,10 @@ int Settings::getDifficulty() const {
return _difficulty;
}
+void Settings::setDifficulty(int difficulty) {
+ _difficulty = difficulty;
+}
+
int Settings::getPlayerAgenda() const {
return _playerAgenda;
}
diff --git a/engines/bladerunner/settings.h b/engines/bladerunner/settings.h
index 413786e2e5..3c7048f02b 100644
--- a/engines/bladerunner/settings.h
+++ b/engines/bladerunner/settings.h
@@ -70,6 +70,8 @@ class Settings {
public:
Settings(BladeRunnerEngine *vm);
+ void reset();
+
void setGamma(float gamma) {
_gamma = gamma;
}
@@ -109,16 +111,16 @@ public:
_newChapter = newChapter;
}
- void setLoadingGame(bool loadingGame) {
- _loadingGame = loadingGame;
+ void setLoadingGame() {
+ _loadingGame = true;
}
- bool getLoadingGame() const {
+ bool isLoadingGame() const {
return _loadingGame;
}
- void setStartingGame(bool startingGame) {
- _startingGame = startingGame;
+ void setStartingGame() {
+ _startingGame = true;
}
bool openNewScene();
@@ -130,6 +132,7 @@ public:
void decreaseAmmo();
int getDifficulty() const;
+ void setDifficulty(int difficulty);
int getPlayerAgenda() const;
void setPlayerAgenda(int agenda);
diff --git a/engines/bladerunner/slice_renderer.cpp b/engines/bladerunner/slice_renderer.cpp
index 932e02bee8..5cf818c1ff 100644
--- a/engines/bladerunner/slice_renderer.cpp
+++ b/engines/bladerunner/slice_renderer.cpp
@@ -207,15 +207,13 @@ void SliceRenderer::calculateBoundingRect() {
* Calculate min and max X
*/
- /* TODO, there is something off with X scaling when Y is high like in rc02, on sides, x seems to be ofsetted a bit more than it should. Start/top vector is doing that */
-
Matrix3x2 facingRotation = calculateFacingRotationMatrix();
Matrix3x2 mProjection(_view->_viewportPosition.z / bottom.z, 0.0f, 0.0f,
0.0f, 25.5f, 0.0f);
Matrix3x2 mOffset(1.0f, 0.0f, _framePos.x,
- 0.0f, 1.0f, _framePos.y);
+ 0.0f, 1.0f, _framePos.y);
Matrix3x2 mScale(_frameScale.x, 0.0f, 0.0f,
0.0f, _frameScale.y, 0.0f);
@@ -281,7 +279,6 @@ void SliceRenderer::loadFrame(int animation, int frame) {
}
struct SliceLineIterator {
- // int _sliceMatrix[2][3];
Matrix3x2 _sliceMatrix;
int _startY;
int _endY;
diff --git a/engines/bladerunner/suspects_database.h b/engines/bladerunner/suspects_database.h
index c4ed08998e..3eff7a7ba3 100644
--- a/engines/bladerunner/suspects_database.h
+++ b/engines/bladerunner/suspects_database.h
@@ -96,7 +96,6 @@ public:
int getPhotoShapeId(int photoId) const;
int getPhotoNotUsed(int photoId) const;
-private:
void reset();
};
diff --git a/engines/bladerunner/ui/elevator.cpp b/engines/bladerunner/ui/elevator.cpp
index 7a6ab3ca35..c7432368f2 100644
--- a/engines/bladerunner/ui/elevator.cpp
+++ b/engines/bladerunner/ui/elevator.cpp
@@ -66,8 +66,8 @@ int Elevator::activate(int elevatorId) {
return 0;
}
- _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack);
- if (!_vqaPlayer->open(vqaName)) {
+ _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack, vqaName);
+ if (!_vqaPlayer->open()) {
return 0;
}
@@ -161,7 +161,7 @@ int Elevator::activate(int elevatorId) {
_buttonClicked = -1;
do {
_vm->gameTick();
- } while (_buttonClicked == -1);
+ } while (_vm->_gameIsRunning && _buttonClicked == -1);
_imagePicker->deactivate();
diff --git a/engines/bladerunner/ui/esper.cpp b/engines/bladerunner/ui/esper.cpp
index 338ee148f3..6803ce5c5c 100644
--- a/engines/bladerunner/ui/esper.cpp
+++ b/engines/bladerunner/ui/esper.cpp
@@ -107,8 +107,8 @@ void ESPER::open(Graphics::Surface *surface) {
_shapesPhotos.resize(10);
- _vqaPlayerMain = new VQAPlayer(_vm, &_vm->_surfaceBack);
- if (!_vqaPlayerMain->open("ESPER.VQA")) {
+ _vqaPlayerMain = new VQAPlayer(_vm, &_vm->_surfaceBack, "ESPER.VQA");
+ if (!_vqaPlayerMain->open()) {
return;
}
_vqaPlayerMain->setLoop(2, -1, kLoopSetModeJustStart, nullptr, nullptr);
@@ -534,7 +534,7 @@ void ESPER::wait(int timeout) {
if (!_isWaiting) {
_isWaiting = true;
uint timeEnd = timeout + _vm->getTotalPlayTime();
- while (_vm->getTotalPlayTime() < timeEnd) {
+ while (_vm->_gameIsRunning && _vm->getTotalPlayTime() < timeEnd) {
_vm->gameTick();
}
_isWaiting = false;
@@ -866,8 +866,8 @@ void ESPER::drawPhotoZoomOut(Graphics::Surface &surface) {
void ESPER::drawVideoZooming(Graphics::Surface &surface) {
if (_vqaPlayerPhoto == nullptr) {
- _vqaPlayerPhoto = new VQAPlayer(_vm, &_surfaceViewport);
- if (!_vqaPlayerPhoto->open(Common::String(_regions[_regionSelected].name) + ".VQA")) {
+ _vqaPlayerPhoto = new VQAPlayer(_vm, &_surfaceViewport, Common::String(_regions[_regionSelected].name) + ".VQA");
+ if (!_vqaPlayerPhoto->open()) {
setStatePhoto(kEsperPhotoStateShow);
_vm->_mouse->enable();
diff --git a/engines/bladerunner/ui/kia.cpp b/engines/bladerunner/ui/kia.cpp
index 756f1bd2cd..4b95607541 100644
--- a/engines/bladerunner/ui/kia.cpp
+++ b/engines/bladerunner/ui/kia.cpp
@@ -88,6 +88,8 @@ KIA::KIA(BladeRunnerEngine *vm) {
_pogoPos = 0;
+ _thumbnail = nullptr;
+
_buttons = new UIImagePicker(_vm, 22);
_crimesSection = new KIASectionCrimes(_vm, _vm->_playerActor->_clues);
@@ -124,6 +126,18 @@ KIA::~KIA() {
delete _script;
}
+void KIA::reset() {
+ _lastSectionIdKIA = kKIASectionCrimes;
+ _lastSectionIdOptions = kKIASectionSettings;
+ _playerVqaFrame = 0;
+ _playerVisualizerState = 0;
+ _playerSliceModelAngle = 0.0f;
+
+ _crimesSection->reset();
+ _suspectsSection->reset();
+ _cluesSection->reset();
+}
+
void KIA::openLastOpened() {
open(_lastSectionIdKIA);
}
@@ -169,8 +183,8 @@ void KIA::open(KIASections sectionId) {
_mainVqaPlayer = nullptr;
}
- _mainVqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack);
- _mainVqaPlayer->open(name);
+ _mainVqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack, name);
+ _mainVqaPlayer->open();
}
if (_transitionId) {
@@ -621,6 +635,9 @@ void KIA::loopEnded(void *callbackData, int frame, int loopId) {
}
void KIA::init() {
+ _thumbnail = new byte[SaveFile::kThumbnailSize];
+ _vm->generateThumbnail(_thumbnail);
+
if (!_vm->openArchive("MODE.MIX")) {
return;
}
@@ -640,8 +657,8 @@ void KIA::init() {
_vm->_mouse->setCursor(0);
if (_playerVqaPlayer == nullptr) {
- _playerVqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront);
- _playerVqaPlayer->open("kiaover.vqa");
+ _playerVqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront, "kiaover.vqa");
+ _playerVqaPlayer->open();
_playerVqaPlayer->setLoop(0, -1, kLoopSetModeJustStart, nullptr, nullptr);
}
_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(501), 70, 0, 0, 50, 0);
@@ -650,6 +667,9 @@ void KIA::init() {
}
void KIA::unload() {
+ delete[] _thumbnail;
+ _thumbnail = nullptr;
+
if (!isOpen()) {
return;
}
@@ -684,7 +704,7 @@ void KIA::unload() {
// TODO: Unfreeze game time
- if (!_vm->_settings->getLoadingGame() && _vm->_gameIsRunning) {
+ if (!_vm->_settings->isLoadingGame() && _vm->_gameIsRunning) {
_vm->_scene->resume();
}
}
diff --git a/engines/bladerunner/ui/kia.h b/engines/bladerunner/ui/kia.h
index 1c2dc19d9f..0612234db1 100644
--- a/engines/bladerunner/ui/kia.h
+++ b/engines/bladerunner/ui/kia.h
@@ -117,6 +117,8 @@ class KIA {
int _pogoPos;
+ byte *_thumbnail;
+
public:
KIALog *_log;
KIAScript *_script;
@@ -126,6 +128,8 @@ public:
KIA(BladeRunnerEngine *vm);
~KIA();
+ void reset();
+
void openLastOpened();
void open(KIASections sectionId);
bool isOpen() const;
diff --git a/engines/bladerunner/ui/kia_section_clues.cpp b/engines/bladerunner/ui/kia_section_clues.cpp
index e003e9bb28..7485d8ebcb 100644
--- a/engines/bladerunner/ui/kia_section_clues.cpp
+++ b/engines/bladerunner/ui/kia_section_clues.cpp
@@ -80,6 +80,18 @@ KIASectionClues::~KIASectionClues() {
delete _uiContainer;
}
+void KIASectionClues::reset() {
+ _debugIntangible = false;
+ _debugNop = 0;
+
+ _mouseX = 0;
+ _mouseY = 0;
+
+ for (int i = 0; i < _filterCount; ++i) {
+ _filters[i] = true;
+ }
+}
+
void KIASectionClues::open() {
_isOpen = true;
diff --git a/engines/bladerunner/ui/kia_section_clues.h b/engines/bladerunner/ui/kia_section_clues.h
index 3f6a13d135..afd8b67433 100644
--- a/engines/bladerunner/ui/kia_section_clues.h
+++ b/engines/bladerunner/ui/kia_section_clues.h
@@ -67,6 +67,8 @@ public:
KIASectionClues(BladeRunnerEngine *vm, ActorClues *clues);
~KIASectionClues();
+ void reset();
+
void open();
void close();
diff --git a/engines/bladerunner/ui/kia_section_crimes.cpp b/engines/bladerunner/ui/kia_section_crimes.cpp
index 96075fbc22..ff6352b3e0 100644
--- a/engines/bladerunner/ui/kia_section_crimes.cpp
+++ b/engines/bladerunner/ui/kia_section_crimes.cpp
@@ -41,7 +41,6 @@
#include "bladerunner/ui/ui_image_picker.h"
#include "bladerunner/ui/ui_scroll_box.h"
-
#include "graphics/surface.h"
namespace BladeRunner {
@@ -71,6 +70,7 @@ KIASectionCrimes::KIASectionCrimes(BladeRunnerEngine *vm, ActorClues *clues) : K
_suspectSelected = -1;
_suspectPhotoShapeId = -1;
+ _suspectPhotoNotUsed = -1;
_suspectPhotoShape = nullptr;
_suspectsFoundCount = 0;
_suspectsFound.resize(_vm->_gameInfo->getSuspectCount());
@@ -87,6 +87,18 @@ KIASectionCrimes::~KIASectionCrimes() {
delete _uiContainer;
}
+void KIASectionCrimes::reset() {
+ _acquiredClueCount = 0;
+ _crimesFoundCount = 0;
+ _suspectsFoundCount = 0;
+ _mouseX = 0;
+ _mouseY = 0;
+ _suspectSelected = -1;
+ _crimeSelected = -1;
+ _suspectPhotoShapeId = -1;
+ _suspectPhotoNotUsed = -1;
+}
+
void KIASectionCrimes::open() {
_scheduledSwitch = false;
@@ -277,7 +289,7 @@ void KIASectionCrimes::populateAcquiredClues() {
++_acquiredClueCount;
}
}
- // sort clues by name, is it necessary
+ // sort clues by name, is it necessary?
}
void KIASectionCrimes::populateCrimes() {
@@ -391,18 +403,20 @@ void KIASectionCrimes::updateSuspectPhoto() {
SuspectDatabaseEntry *suspect = _vm->_suspectsDatabase->get(_suspectSelected);
_suspectPhotoShapeId = -1;
+ _suspectPhotoNotUsed = -1;
int photoCluesCount = suspect->getPhotoCount();
if (photoCluesCount > 0) {
for (int i = 0 ; i < photoCluesCount; i++) {
- //TODO: weird stuff going on here... it's using index instead id, also some field is used but its always -1
+ //TODO: weird stuff going on here... original game is using internal clue index instead id
if (_clues->isAcquired(suspect->getPhotoClueId(i))) {
_suspectPhotoShapeId = suspect->getPhotoShapeId(i);
+ _suspectPhotoNotUsed = suspect->getPhotoNotUsed(i);
break;
}
}
}
- if (_suspectPhotoShapeId == -1) {
+ if (_suspectPhotoShapeId == -1 && _suspectPhotoNotUsed == -1) {
if (suspect->getSex()) {
_suspectPhotoShapeId = 14;
} else {
diff --git a/engines/bladerunner/ui/kia_section_crimes.h b/engines/bladerunner/ui/kia_section_crimes.h
index 23983b8d39..bd2a2f2d80 100644
--- a/engines/bladerunner/ui/kia_section_crimes.h
+++ b/engines/bladerunner/ui/kia_section_crimes.h
@@ -69,6 +69,7 @@ class KIASectionCrimes : public KIASectionBase {
int _mouseY;
int _suspectPhotoShapeId;
+ int _suspectPhotoNotUsed;
Shape *_suspectPhotoShape;
public:
@@ -78,6 +79,8 @@ public:
KIASectionCrimes(BladeRunnerEngine *vm, ActorClues *clues);
~KIASectionCrimes();
+ void reset();
+
void open();
void close();
diff --git a/engines/bladerunner/ui/kia_section_suspects.cpp b/engines/bladerunner/ui/kia_section_suspects.cpp
index 54e33cb62b..460f744a2a 100644
--- a/engines/bladerunner/ui/kia_section_suspects.cpp
+++ b/engines/bladerunner/ui/kia_section_suspects.cpp
@@ -86,6 +86,7 @@ KIASectionSuspects::KIASectionSuspects(BladeRunnerEngine *vm, ActorClues *clues)
_suspectSelected = -1;
_suspectPhotoShapeId = -1;
+ _suspectPhotoNotUsed = -1;
_suspectPhotoShape = nullptr;
_suspectsFoundCount = 0;
_suspectsFound.resize(_vm->_gameInfo->getSuspectCount());
@@ -108,6 +109,22 @@ KIASectionSuspects::~KIASectionSuspects() {
delete _uiContainer;
}
+void KIASectionSuspects::reset() {
+ _acquiredClueCount = 0;
+ _suspectsFoundCount = 0;
+ _mouseX = 0;
+ _mouseY = 0;
+ _suspectSelected = -1;
+ _crimeSelected = -1;
+ _suspectPhotoShapeId = -1;
+ _suspectPhotoNotUsed = -1;
+ _whereaboutsFilter = true;
+ _MOFilter = true;
+ _replicantFilter = true;
+ _nonReplicantFilter = true;
+ _othersFilter = true;
+}
+
void KIASectionSuspects::open() {
_scheduledSwitch = false;
@@ -169,7 +186,6 @@ void KIASectionSuspects::draw(Graphics::Surface &surface) {
_uiContainer->draw(surface);
-
_vm->_mainFont->drawColor(_vm->_textKIA->getText(0), surface, 300, 162, 0x77DF);
_vm->_mainFont->drawColor(_vm->_textKIA->getText(46), surface, 142, 248, 0x77DF);
_vm->_mainFont->drawColor(_vm->_textKIA->getText(47), surface, 142, 308, 0x77DF);
@@ -479,18 +495,20 @@ void KIASectionSuspects::updateSuspectPhoto() {
SuspectDatabaseEntry *suspect = _vm->_suspectsDatabase->get(_suspectSelected);
_suspectPhotoShapeId = -1;
+ _suspectPhotoNotUsed = -1;
int photoCluesCount = suspect->getPhotoCount();
if (photoCluesCount > 0) {
for (int i = 0 ; i < photoCluesCount; i++) {
- //TODO: weird stuff going on here... it's using index instead id, also some field is used but its always -1
+ //TODO: weird stuff going on here... original game is using internal clue index instead id
if (_clues->isAcquired(suspect->getPhotoClueId(i))) {
_suspectPhotoShapeId = suspect->getPhotoShapeId(i);
+ _suspectPhotoNotUsed = suspect->getPhotoNotUsed(i);
break;
}
}
}
- if (_suspectPhotoShapeId == -1) {
+ if (_suspectPhotoShapeId == -1 && _suspectPhotoNotUsed == -1) {
if (suspect->getSex()) {
_suspectPhotoShapeId = 14;
} else {
diff --git a/engines/bladerunner/ui/kia_section_suspects.h b/engines/bladerunner/ui/kia_section_suspects.h
index 0cc957f609..22a3accbee 100644
--- a/engines/bladerunner/ui/kia_section_suspects.h
+++ b/engines/bladerunner/ui/kia_section_suspects.h
@@ -78,6 +78,7 @@ class KIASectionSuspects : public KIASectionBase {
int _mouseY;
int _suspectPhotoShapeId;
+ int _suspectPhotoNotUsed;
Shape *_suspectPhotoShape;
public:
@@ -87,6 +88,8 @@ public:
KIASectionSuspects(BladeRunnerEngine *vm, ActorClues *clues);
~KIASectionSuspects();
+ void reset();
+
void open();
void close();
diff --git a/engines/bladerunner/ui/scores.cpp b/engines/bladerunner/ui/scores.cpp
index c4a7df778c..8fc3378207 100644
--- a/engines/bladerunner/ui/scores.cpp
+++ b/engines/bladerunner/ui/scores.cpp
@@ -50,9 +50,9 @@ void Scores::open() {
return;
}
- _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack);
+ _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack, "SCORE.VQA");
- if (!_vqaPlayer->open("SCORE.VQA")) {
+ if (!_vqaPlayer->open()) {
return;
}
diff --git a/engines/bladerunner/ui/spinner.cpp b/engines/bladerunner/ui/spinner.cpp
index 9e491f719c..32809e8740 100644
--- a/engines/bladerunner/ui/spinner.cpp
+++ b/engines/bladerunner/ui/spinner.cpp
@@ -74,14 +74,14 @@ int Spinner::chooseDestination(int loopId, bool immediately) {
} else {
_vm->playerLosesControl();
_vm->_scene->loopStartSpecial(kSceneLoopModeSpinner, loopId, immediately);
- while (!_isOpen) {
+ while (_vm->_gameIsRunning && !_isOpen) {
_vm->gameTick();
}
_vm->playerGainsControl();
}
- _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack);
- if (!_vqaPlayer->open("SPINNER.VQA")) {
+ _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceBack, "SPINNER.VQA");
+ if (!_vqaPlayer->open()) {
return 0;
}
@@ -159,7 +159,7 @@ int Spinner::chooseDestination(int loopId, bool immediately) {
_selectedDestination = -1;
do {
_vm->gameTick();
- } while (_selectedDestination == -1);
+ } while (_vm->_gameIsRunning && _selectedDestination == -1);
_imagePicker->deactivate();
diff --git a/engines/bladerunner/ui/vk.cpp b/engines/bladerunner/ui/vk.cpp
index ec5013ca4c..ae776b7e55 100644
--- a/engines/bladerunner/ui/vk.cpp
+++ b/engines/bladerunner/ui/vk.cpp
@@ -87,8 +87,8 @@ void VK::open(int actorId, int calibrationRatio) {
_shapes[i]->open("VK.SHP", i);
}
- _vqaPlayerMain = new VQAPlayer(_vm, &_vm->_surfaceBack);
- if (!_vqaPlayerMain->open("VK.VQA")) {
+ _vqaPlayerMain = new VQAPlayer(_vm, &_vm->_surfaceBack, "VK.VQA");
+ if (!_vqaPlayerMain->open()) {
return;
}
@@ -114,8 +114,8 @@ void VK::open(int actorId, int calibrationRatio) {
}
_surfaceEye.create(172, 116, createRGB555());
- _vqaPlayerEye = new VQAPlayer(_vm, &_surfaceEye);
- if (!_vqaPlayerEye->open(eyeVqa)) {
+ _vqaPlayerEye = new VQAPlayer(_vm, &_surfaceEye, eyeVqa);
+ if (!_vqaPlayerEye->open()) {
return;
}
if (!_vqaPlayerEye->setLoop(0, -1, kLoopSetModeEnqueue, nullptr, nullptr)) {
diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp
index 5f25a6387c..68a4e9491d 100644
--- a/engines/bladerunner/vqa_player.cpp
+++ b/engines/bladerunner/vqa_player.cpp
@@ -30,8 +30,8 @@
namespace BladeRunner {
-bool VQAPlayer::open(const Common::String &name) {
- _s = _vm->getResourceStream(name);
+bool VQAPlayer::open() {
+ _s = _vm->getResourceStream(_name);
if (!_s) {
return false;
}
diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h
index b2c6ff2d4d..c4dd182697 100644
--- a/engines/bladerunner/vqa_player.h
+++ b/engines/bladerunner/vqa_player.h
@@ -49,6 +49,7 @@ class VQAPlayer {
friend class Debugger;
BladeRunnerEngine *_vm;
+ Common::String _name;
Common::SeekableReadStream *_s;
VQADecoder _decoder;
Audio::QueuingAudioStream *_audioStream;
@@ -77,8 +78,9 @@ class VQAPlayer {
public:
- VQAPlayer(BladeRunnerEngine *vm, Graphics::Surface *surface)
+ VQAPlayer(BladeRunnerEngine *vm, Graphics::Surface *surface, const Common::String &name)
: _vm(vm),
+ _name(name),
_s(nullptr),
_surface(surface),
_decoder(),
@@ -103,7 +105,7 @@ public:
close();
}
- bool open(const Common::String &name);
+ bool open();
void close();
int update(bool forceDraw = false, bool advanceFrame = true, Graphics::Surface *customSurface = nullptr);