Proper handling of BS2 cutscene lead-outs, plus some other minor fixes.

svn-id: r12907
This commit is contained in:
Torbjörn Andersson 2004-02-15 14:22:54 +00:00
parent 2e7badd6dc
commit 55556c813c
5 changed files with 122 additions and 35 deletions

View File

@ -74,8 +74,14 @@ bool AnimationState::init(const char *basename) {
p = 0;
while (!feof(f)) {
if (fscanf(f, "%i %i", &palettes[p].end, &palettes[p].cnt) != 2)
int end, cnt;
if (fscanf(f, "%i %i", &end, &cnt) != 2)
break;
palettes[p].end = (uint) end;
palettes[p].cnt = (uint) cnt;
for (i = 0; i < palettes[p].cnt; i++) {
int r, g, b;
fscanf(f, "%i", &r);

View File

@ -80,8 +80,14 @@ bool AnimationState::init(const char *name) {
p = 0;
while (!feof(f)) {
if (fscanf(f, "%i %i", &palettes[p].end, &palettes[p].cnt) != 2)
int end, cnt;
if (fscanf(f, "%i %i", &end, &cnt) != 2)
break;
palettes[p].end = (uint) end;
palettes[p].cnt = (uint) cnt;
for (i = 0; i < palettes[p].cnt; i++) {
int r, g, b;
fscanf(f, "%i", &r);
@ -410,6 +416,26 @@ bool AnimationState::decodeFrame() {
return false;
}
MovieInfo MoviePlayer::_movies[] = {
{ "carib", 222 },
{ "escape", 187 },
{ "eye", 248 },
{ "finale", 1485 },
{ "guard", 75 },
{ "intro", 1800 },
{ "jungle", 186 },
{ "museum", 167 },
{ "pablo", 75 },
{ "pyramid", 60 },
{ "quaram", 184 },
{ "river", 656 },
{ "sailing", 138 },
{ "shaman", 788 },
{ "stone1", 34 },
{ "stone2", 282 },
{ "stone3", 65 }
};
void MoviePlayer::openTextObject(MovieTextObject *obj) {
if (obj->textSprite)
_vm->_graphics->createSurface(obj->textSprite, &_textSurface);
@ -444,7 +470,7 @@ void MoviePlayer::drawTextObject(AnimationState *anim, MovieTextObject *obj) {
int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *musicOut) {
#ifdef USE_MPEG2
int frameCounter = 0, textCounter = 0;
uint frameCounter = 0, textCounter = 0;
PlayingSoundHandle handle;
bool skipCutscene = false, textVisible = false;
uint32 flags = SoundMixer::FLAG_16BITS;
@ -454,7 +480,7 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu
memcpy(oldPal, _vm->_graphics->_palCopy, 1024);
AnimationState *anim = new AnimationState(_vm);
if (!anim->init(filename)) {
delete anim;
// Missing Files? Use the old 'Narration Only' hack
@ -468,6 +494,22 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu
flags |= SoundMixer::FLAG_LITTLE_ENDIAN;
#endif
int i;
uint leadOutFrame = (uint) -1;
for (i = 0; i < ARRAYSIZE(_movies); i++) {
if (scumm_stricmp(filename, _movies[i].name) == 0) {
if (_movies[i].frames >= 60)
leadOutFrame = _movies[i].frames - 60;
else
leadOutFrame = 0;
break;
}
}
if (i == ARRAYSIZE(_movies))
warning("Unknown movie, '%s'", filename);
while (anim->decodeFrame()) {
if (text && text[textCounter]) {
if (frameCounter == text[textCounter]->startFrame) {
@ -495,6 +537,9 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu
frameCounter++;
if (frameCounter == leadOutFrame && musicOut)
_vm->_sound->playFx(0, musicOut, 0, 0, RDSE_FXLEADOUT);
#ifdef BACKEND_8BIT
_vm->_graphics->updateDisplay(true);
#else
@ -512,6 +557,37 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu
}
if (!skipCutscene) {
// Sleep for one frame so that the last frame is displayed.
_vm->_system->delay_msecs(1000 / 12);
}
#ifndef BACKEND_8BIT
// Most movies fade to black on their own, but not all of them. Since
// we may be hanging around in the cutscene player for a while longer,
// waiting for the lead-out sound to finish, paint the overlay black.
anim->clearDisplay();
#else
_vm->_graphics->clearScene();
_vm->_graphics->setNeedFullRedraw();
#endif
// If the speech is still playing, redraw the subtitles. At least in
// the English version this is most noticeable in the "carib" cutscene.
if (textVisible && handle.isActive())
drawTextObject(anim, text[textCounter]);
if (text)
closeTextObject(text[textCounter]);
#ifndef BACKEND_8BIT
anim->updateDisplay();
#else
_vm->_graphics->updateDisplay(true);
#endif
// Wait for the voice to stop playing. This is to make sure
// that we don't cut off the speech in mid-sentence, and - even
// more importantly - that we don't free the sound buffer while
@ -522,14 +598,9 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu
_vm->_system->delay_msecs(100);
}
if (text)
closeTextObject(text[textCounter]);
// Clear the screen again
#ifndef BACKEND_8BIT
// Most movies fade to black on their own, but not all of them. Since
// we may be hanging around in the cutscene player for a while longer,
// waiting for the lead-out sound to finish, paint the overlay black.
anim->clearDisplay();
anim->updateDisplay();
#endif
@ -537,13 +608,13 @@ int32 MoviePlayer::play(const char *filename, MovieTextObject *text[], uint8 *mu
_vm->_graphics->clearScene();
_vm->_graphics->setNeedFullRedraw();
if (!skipCutscene)
_vm->_sound->playLeadOut(musicOut);
_vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT);
delete anim;
// Wait for the lead-out to stop, if there is any.
_vm->_sound->waitForLeadOut();
// Lead-in and lead-out music are, as far as I can tell, only used for
// the animated cut-scenes, so this seems like a good place to close
// both of them.
@ -688,8 +759,10 @@ int32 MoviePlayer::playDummy(const char *filename, MovieTextObject *text[], uint
// FIXME: For now, only play the lead-out music for cutscenes
// that have subtitles.
if (!skipCutscene)
_vm->_sound->playLeadOut(musicOut);
if (!skipCutscene && musicOut) {
_vm->_sound->playFx(0, musicOut, 0, 0, RDSE_FXLEADOUT);
_vm->_sound->waitForLeadOut();
}
_vm->_graphics->setPalette(0, 256, oldPal, RDPAL_INSTANT);
}

View File

@ -54,7 +54,6 @@ typedef sequence_t mpeg2_sequence_t;
namespace Sword2 {
#ifdef BACKEND_8BIT
#define SQR(x) ((x) * (x))
#define SHIFT 3
@ -135,11 +134,18 @@ private:
#endif
};
struct MovieInfo {
char name[9];
uint frames;
};
class MoviePlayer {
private:
Sword2Engine *_vm;
uint8 *_textSurface;
static struct MovieInfo _movies[];
void openTextObject(MovieTextObject *obj);
void closeTextObject(MovieTextObject *obj);
void drawTextObject(AnimationState *anim, MovieTextObject *obj);

View File

@ -252,11 +252,16 @@ bool MusicHandle::endOfData(void) const {
*/
bool Sound::getWavInfo(uint8 *data, WavInfo *wavInfo) {
uint32 wavLength;
uint32 offset;
if (READ_UINT32(data) != MKID('RIFF')) {
warning("getWavInfo: No 'RIFF' header");
return false;
}
wavLength = READ_LE_UINT32(data + 4) + 8;
if (READ_UINT32(data + 8) != MKID('WAVE')) {
warning("getWavInfo: No 'WAVE' header");
return false;
@ -270,15 +275,21 @@ bool Sound::getWavInfo(uint8 *data, WavInfo *wavInfo) {
wavInfo->channels = READ_LE_UINT16(data + 22);
wavInfo->rate = READ_LE_UINT16(data + 24);
data += READ_LE_UINT32(data + 16) + 20;
offset = READ_LE_UINT32(data + 16) + 20;
if (READ_UINT32(data) != MKID('data')) {
warning("getWavInfo: No 'data' header");
return false;
// It's almost certainly a WAV file, but we still need to find its
// 'data' chunk.
while (READ_UINT32(data + offset) != MKID('data')) {
if (offset >= wavLength) {
warning("getWavInfo: Can't find 'data' chunk");
return false;
}
offset += (READ_LE_UINT32(data + offset + 4) + 8);
}
wavInfo->samples = READ_LE_UINT32(data + 4);
wavInfo->data = data + 8;
wavInfo->samples = READ_LE_UINT32(data + offset + 4);
wavInfo->data = data + offset + 8;
return true;
}
@ -429,21 +440,12 @@ void Sound::restoreMusicState(void) {
}
}
void Sound::playLeadOut(uint8 *leadOut) {
int i;
void Sound::waitForLeadOut(void) {
int i = getFxIndex(-1);
if (!leadOut)
if (i == MAXFX)
return;
playFx(0, leadOut, 0, 0, RDSE_FXLEADOUT);
i = getFxIndex(-1);
if (i == MAXFX) {
warning("playLeadOut: Can't find lead-out sound handle");
return;
}
while (_fx[i]._handle.isActive()) {
_vm->_graphics->updateDisplay();
_vm->_system->delay_msecs(30);

View File

@ -131,7 +131,7 @@ public:
void stopMusic(void);
void saveMusicState(void);
void restoreMusicState(void);
void playLeadOut(uint8 *leadOut);
void waitForLeadOut(void);
int32 streamCompMusic(const char *filename, uint32 musicId, bool looping);
int32 musicTimeRemaining(void);