BLADERUNNER: Release non-repeated and support queued overlays

This commit is contained in:
Thanasis Antoniou 2019-03-31 12:23:01 +03:00
parent fa50678125
commit 20d77710c9
5 changed files with 71 additions and 14 deletions

View File

@ -23,6 +23,7 @@
#include "bladerunner/overlays.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/game_constants.h"
#include "bladerunner/archive.h"
#include "bladerunner/savefile.h"
@ -58,6 +59,10 @@ Overlays::~Overlays() {
int Overlays::play(const Common::String &name, int loopId, bool loopForever, bool startNow, int a6) {
assert(name.size() <= 12);
if (loopId < 0) {
warning("Overlays::play - loop id can't be a negative number!");
return -1;
}
int32 hash = MIXArchive::getHash(name);
int index = findByHash(hash);
@ -70,20 +75,38 @@ int Overlays::play(const Common::String &name, int loopId, bool loopForever, boo
_videos[index].name = name;
_videos[index].hash = hash;
_videos[index].loopId = loopId;
_videos[index].enqueuedLoopId = -1;
_videos[index].loopForever = loopForever;
_videos[index].vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceFront, Common::String::format("%s.VQA", name.c_str()));
if (!_videos[index].vqaPlayer) {
resetSingle(index);
return -1;
}
// TODO? Removed as redundant
// repeat forever
_videos[index].vqaPlayer->setBeginAndEndFrame(0, 0, -1, kLoopSetModeJustStart, nullptr, nullptr);
//_videos[index].vqaPlayer->setBeginAndEndFrame(0, 0, -1, kLoopSetModeJustStart, nullptr, nullptr);
}
_videos[index].vqaPlayer->open();
_videos[index].vqaPlayer->setLoop(
loopId,
loopForever ? -1 : 0,
startNow ? kLoopSetModeImmediate : kLoopSetModeEnqueue,
nullptr, nullptr);
bool skipNewVQAPlayerOpen = false;
if (_videos[index].vqaPlayer
&& !startNow
&& _videos[index].vqaPlayer->getFrameCount() > 0
) {
skipNewVQAPlayerOpen = true;
_videos[index].enqueuedLoopId = loopId;
}
if (skipNewVQAPlayerOpen || _videos[index].vqaPlayer->open()) {
_videos[index].vqaPlayer->setLoop(
loopId,
loopForever ? -1 : 0,
startNow ? kLoopSetModeImmediate : kLoopSetModeEnqueue,
nullptr, nullptr);
} else {
resetSingle(index);
return -1;
}
return index;
}
@ -179,7 +202,12 @@ void Overlays::save(SaveFileWriteStream &f) {
f.writeInt(0); // vqaPlayer pointer
f.writeStringSz(ov.name, 13);
f.writeSint32LE(ov.hash);
f.writeInt(ov.loopId);
if (ov.enqueuedLoopId != -1) {
// When there is an enqueued video, save that loop Id instead
f.writeInt(ov.enqueuedLoopId);
} else {
f.writeInt(ov.loopId);
}
f.writeBool(ov.loopForever);
f.writeInt(ov.frame);
}

View File

@ -48,6 +48,7 @@ class Overlays {
Common::String name;
int32 hash;
int loopId;
int enqueuedLoopId;
bool loopForever;
int frame;
};

View File

@ -67,7 +67,7 @@ void SceneScriptBB06::InitializeScene() {
#else
// bugfix: case of not transitioning from BB51: chess/ egg boiler sub-space
if (Game_Flag_Query(kFlagBB06AndroidDestroyed)) {
Overlay_Play("BB06OVER", 1, false, false, 0);
Overlay_Play("BB06OVER", 1, true, true, 0);
}
#endif // BLADERUNNER_ORIGINAL_BUGS
}
@ -111,8 +111,17 @@ bool SceneScriptBB06::ClickedOn3DObject(const char *objectName, bool a2) {
}
#else
if (Player_Query_Combat_Mode()) {
Overlay_Play("BB06OVER", 0, false, true, 0); // explosion - don't loop
// Doll Explosion case:
// We need to use enqueued overlays for this.
// Note: Queuing only works on top of a video that is repeating itself.
// First we load the "exploding animation state" as a forever loop (even though it will only play once)
// Then we enqueue the final exploded state loop, also as a forever loop.
// This (along with some fixes in the Overlays class will ensure
// that the second overlay will play after the first has completed one loop
// and it will persist (across save games too).
Game_Flag_Set(kFlagBB06AndroidDestroyed);
Overlay_Play("BB06OVER", 0, true, true, 0);
Overlay_Play("BB06OVER", 1, true, false, 0);
Un_Combat_Target_Object("BOX31");
return true;
} else {
@ -195,7 +204,7 @@ void SceneScriptBB06::SceneFrameAdvanced(int frame) {
// last frame of transition is 15, try 13 for better transition - minimize weird effect
if (frame == 13) { // executed once during transition FROM bb51 (chess sub space)
if (Game_Flag_Query(kFlagBB06AndroidDestroyed)) {
Overlay_Play("BB06OVER", 1, false, false, 0);
Overlay_Play("BB06OVER", 1, true, true, 0);
}
}
#endif // BLADERUNNER_ORIGINAL_BUGS

View File

@ -51,7 +51,7 @@ void SceneScriptBB51::InitializeScene() {
#if BLADERUNNER_ORIGINAL_BUGS // Sebastian's Doll Fix
#else
if (Game_Flag_Query(kFlagBB06AndroidDestroyed)) {
Overlay_Play("BB06OVER", 1, false, false, 0);
Overlay_Play("BB06OVER", 1, true, true, 0);
}
#endif // BLADERUNNER_ORIGINAL_BUGS

View File

@ -57,10 +57,12 @@ bool VQAPlayer::open() {
_repeatsCountQueued = -1;
if (_loopInitial >= 0) {
// TODO? When does this happen? _loopInitial seems to be unused
setLoop(_loopInitial, _repeatsCountInitial, kLoopSetModeImmediate, nullptr, nullptr);
} else {
_frameNext = 0;
setBeginAndEndFrame(0, _frameEnd, 0, kLoopSetModeJustStart, nullptr, nullptr);
// TODO? Removed as redundant
// setBeginAndEndFrame(0, _frameEnd, 0, kLoopSetModeJustStart, nullptr, nullptr);
}
return true;
@ -107,6 +109,8 @@ int VQAPlayer::update(bool forceDraw, bool advanceFrame, bool useTime, Graphics:
result = -1;
} else if (_frameNext > _frameEnd) {
result = -3;
// _repeatsCount == 0, so return here at the end of the video, to release the resource
return result;
} else if (useTime && (now < _frameNextTime)) {
result = -1;
} else if (advanceFrame) {
@ -149,7 +153,9 @@ int VQAPlayer::update(bool forceDraw, bool advanceFrame, bool useTime, Graphics:
_decoder.decodeVideoFrame(customSurface != nullptr ? customSurface : _surface, _frame, true);
result = _frame;
}
return result;
return result; // Note: result here could be negative.
// Negative valid value should only be -1, since there are various assertions
// assert(frame >= -1) in overlay modes (elevator, scores, spinner)
}
void VQAPlayer::updateZBuffer(ZBuffer *zbuffer) {
@ -187,11 +193,23 @@ bool VQAPlayer::setLoop(int loop, int repeatsCount, int loopSetMode, void (*call
}
bool VQAPlayer::setBeginAndEndFrame(int begin, int end, int repeatsCount, int loopSetMode, void (*callback)(void *, int, int), void *callbackData) {
if ( begin >= getFrameCount()
|| end >= getFrameCount()
|| begin >= end
|| loopSetMode < 0
|| loopSetMode >= 3
) {
warning("VQAPlayer::setBeginAndEndFrame - Invalid arguments for video");
return false; // VQA_DECODER_ERROR_BAD_INPUT case
}
if (repeatsCount < 0) {
repeatsCount = -1;
}
if (_repeatsCount == 0 && loopSetMode == kLoopSetModeEnqueue) {
// if the member var _repeatsCount is 0 (which means "don't repeat existing loop")
// then execute set the enqueued loop for immediate execution
loopSetMode = kLoopSetModeImmediate;
}
@ -199,6 +217,7 @@ bool VQAPlayer::setBeginAndEndFrame(int begin, int end, int repeatsCount, int lo
if (loopSetMode == kLoopSetModeJustStart) {
_repeatsCount = repeatsCount;
_frameEnd = end;
} else if (loopSetMode == kLoopSetModeEnqueue) {
_repeatsCountQueued = repeatsCount;
_frameEndQueued = end;