From 5d32a2c034a1e9036c9dcc721b6bfe27c46eb904 Mon Sep 17 00:00:00 2001 From: Robert Göffringmann Date: Sun, 5 Dec 2004 02:55:06 +0000 Subject: added support for an international BS1 cutscene pack (which we didn't release yet) svn-id: r15983 --- sword1/animation.cpp | 222 +++++++++++++++++++++++++++++++-- sword1/animation.h | 65 +++++++++- sword1/credits.cpp | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++ sword1/credits.h | 68 +++++++++++ sword1/logic.cpp | 39 ++---- sword1/sword1.cpp | 9 ++ sword1/sword1.h | 2 + 7 files changed, 698 insertions(+), 46 deletions(-) create mode 100644 sword1/credits.cpp create mode 100644 sword1/credits.h (limited to 'sword1') diff --git a/sword1/animation.cpp b/sword1/animation.cpp index 0e4531bdd6..c856b6a411 100644 --- a/sword1/animation.cpp +++ b/sword1/animation.cpp @@ -21,12 +21,14 @@ #include "common/stdafx.h" #include "common/file.h" +#include "sword1/sword1.h" #include "sword1/animation.h" -#include "sound/audiostream.h" - +#include "sword1/credits.h" +#include "sound/vorbis.h" #include "common/config-manager.h" #include "common/str.h" + namespace Sword1 { AnimationState::AnimationState(Screen *scr, SoundMixer *snd, OSystem *sys) @@ -38,11 +40,9 @@ AnimationState::~AnimationState() { #ifdef BACKEND_8BIT - void AnimationState::setPalette(byte *pal) { _sys->setPalette(pal, 0, 256); } - #endif void AnimationState::drawYUV(int width, int height, byte *const *dat) { @@ -50,28 +50,95 @@ void AnimationState::drawYUV(int width, int height, byte *const *dat) { _scr->plotYUV(lut, width, height, dat); #else plotYUV(lookup, width, height, dat); +#endif +} + +void AnimationState::updateScreen(void) { +#ifndef BACKEND_8BIT _sys->copyRectToOverlay(overlay, MOVIE_WIDTH, 0, 40, MOVIE_WIDTH, MOVIE_HEIGHT); #endif + _sys->updateScreen(); +} + +OverlayColor *AnimationState::giveRgbBuffer(void) { +#ifdef BACKEND_8BIT + return NULL; +#else + return overlay; +#endif +} + +bool AnimationState::soundFinished(void) { + return !bgSound.isActive(); +} + +AudioStream *AnimationState::createAudioStream(const char *name, void *arg) { + if (arg) + return (AudioStream*)arg; + else + return AudioStream::openStreamFile(name); } MoviePlayer::MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys) : _scr(scr), _snd(snd), _sys(sys) { + for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++) + _logoOvls[cnt] = NULL; + _introPal = NULL; +} + +MoviePlayer::~MoviePlayer(void) { + if (_introPal) + free(_introPal); + for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++) + if (_logoOvls[cnt]) + free(_logoOvls[cnt]); } /** * Plays an animated cutscene. - * @param filename the file name of the cutscene file + * @param id the id of the file */ -void MoviePlayer::play(const char *filename) { +void MoviePlayer::play(uint32 id) { #ifdef USE_MPEG2 AnimationState *anim = new AnimationState(_scr, _snd, _sys); - bool initOK = anim->init(filename); + AudioStream *stream = NULL; + if (SwordEngine::_systemVars.cutscenePackVersion == 1) { + if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) { + // these sequences are language specific + char sndName[20]; + sprintf(sndName, "%s.snd", _sequenceList[id]); + File *oggSource = new File(); + if (oggSource->open(sndName)) { + SplittedAudioStream *sStream = new SplittedAudioStream(); + uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2. + // for each segment and each of the 7 languages, we've got fileoffset and size + uint32 *header = (uint32*)malloc(numSegs * 7 * 2 * 4); + for (uint32 cnt = 0; cnt < numSegs * 7 * 2; cnt++) + header[cnt] = oggSource->readUint32LE(); + for (uint32 segCnt = 0; segCnt < numSegs; segCnt++) { + oggSource->seek( header[SwordEngine::_systemVars.language * 2 + 0 + segCnt * 14]); + uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14]; + AudioStream *apStream = makeVorbisStream(oggSource, segSize); + if (!apStream) + error("Can't create Vorbis Stream from file %s", sndName); + sStream->appendStream(apStream); + } + free(header); + stream = sStream; + } else + warning("Sound file \"%s\" not found", sndName); + initOverlays(id); + oggSource->decRef(); + } + } + bool initOK = anim->init(_sequenceList[id], stream); + uint32 frameCount = 0; if (initOK) { while (anim->decodeFrame()) { -#ifndef BACKEND_8BIT - _sys->updateScreen(); -#endif + processFrame(id, anim, frameCount); + anim->updateScreen(); + frameCount++; OSystem::Event event; while (_sys->pollEvent(event)) { switch (event.event_code) { @@ -95,10 +162,143 @@ void MoviePlayer::play(const char *filename) { } } } - + while (!anim->soundFinished()) + _sys->delayMillis(100); delete anim; +#endif // USE_MPEG2 +} + +void MoviePlayer::insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal) { + if (ovl != NULL) + for (uint32 cnt = 0; cnt < 640 * 400; cnt++) + if (ovl[cnt]) + buf[cnt] = pal[ovl[cnt]]; +} +void MoviePlayer::processFrame(uint32 animId, AnimationState *anim, uint32 frameNo) { +#if defined(USE_MPEG2) && !defined(BACKEND_8BIT) + if ((animId != 4) || (SwordEngine::_systemVars.cutscenePackVersion == 0)) + return; + OverlayColor *buf = anim->giveRgbBuffer(); + if ((frameNo > 397) && (frameNo < 444)) { // Broken Sword Logo + if (frameNo <= 403) + insertOverlay(buf, _logoOvls[frameNo - 398], _introPal); // fade up + else if (frameNo <= 437) + insertOverlay(buf, _logoOvls[(frameNo - 404) % 6 + 6], _introPal); // animation + else { + insertOverlay(buf, _logoOvls[5 - (frameNo - 438)], _introPal); // fade down + } + } +#endif +} + +bool MoviePlayer::initOverlays(uint32 id) { +#if defined(USE_MPEG2) && !defined(BACKEND_8BIT) + if (id == SEQ_INTRO) { + ArcFile ovlFile; + if (!ovlFile.open("intro.dat")) { + warning("\"intro.dat\" not found"); + return false; + } + ovlFile.enterPath(SwordEngine::_systemVars.language); + for (uint8 fcnt = 0; fcnt < 12; fcnt++) { + _logoOvls[fcnt] = ovlFile.decompressFile(fcnt); + if (fcnt > 0) + for (uint32 cnt = 0; cnt < 640 * 400; cnt++) + if (_logoOvls[fcnt - 1][cnt] && !_logoOvls[fcnt][cnt]) + _logoOvls[fcnt][cnt] = _logoOvls[fcnt - 1][cnt]; + } + uint8 *pal = ovlFile.fetchFile(12); + _introPal = (OverlayColor*)malloc(256 * sizeof(OverlayColor)); + for (uint16 cnt = 0; cnt < 256; cnt++) + _introPal[cnt] = _sys->RGBToColor(pal[cnt * 3 + 0], pal[cnt * 3 + 1], pal[cnt * 3 + 2]); + } + return true; #endif } +SplittedAudioStream::SplittedAudioStream(void) { + _queue = NULL; +} + +SplittedAudioStream::~SplittedAudioStream(void) { + while (_queue) { + delete _queue->stream; + FileQueue *que = _queue->next; + delete _queue; + _queue = que; + } +} + +int SplittedAudioStream::getRate(void) const { + if (_queue) + return _queue->stream->getRate(); + else + return 22050; +} + +void SplittedAudioStream::appendStream(AudioStream *stream) { + FileQueue **que = &_queue; + while (*que) + que = &((*que)->next); + *que = new FileQueue; + (*que)->stream = stream; + (*que)->next = NULL; +} + +bool SplittedAudioStream::endOfData(void) const { + if (_queue) + return _queue->stream->endOfData(); + else + return true; +} + +bool SplittedAudioStream::isStereo(void) const { + if (_queue) + return _queue->stream->isStereo(); + else + return false; // all the BS1 files are mono, anyways. +} + +int SplittedAudioStream::readBuffer(int16 *buffer, const int numSamples) { + int retVal = 0; + int needSamples = numSamples; + while (needSamples && _queue) { + int retSmp = _queue->stream->readBuffer(buffer, needSamples); + needSamples -= retSmp; + retVal += retSmp; + buffer += retSmp; + if (_queue->stream->endOfData()) { + delete _queue->stream; + FileQueue *que = _queue->next; + delete _queue; + _queue = que; + } + } + return retVal; +} + +const char * MoviePlayer::_sequenceList[20] = { + "ferrari", // 0 CD2 ferrari running down fitz in sc19 + "ladder", // 1 CD2 george walking down ladder to dig sc24->sc$ + "steps", // 2 CD2 george walking down steps sc23->sc24 + "sewer", // 3 CD1 george entering sewer sc2->sc6 + "intro", // 4 CD1 intro sequence ->sc1 + "river", // 5 CD1 george being thrown into river by flap & g$ + "truck", // 6 CD2 truck arriving at bull's head sc45->sc53/4 + "grave", // 7 BOTH george's grave in scotland, from sc73 + from sc38 $ + "montfcon", // 8 CD2 monfaucon clue in ireland dig, sc25 + "tapestry", // 9 CD2 tapestry room beyond spain well, sc61 + "ireland", // 10 CD2 ireland establishing shot europe_map->sc19 + "finale", // 11 CD2 grand finale at very end, from sc73 + "history", // 12 CD1 George's history lesson from Nico, in sc10 + "spanish", // 13 CD2 establishing shot for 1st visit to Spain, europe_m$ + "well", // 14 CD2 first time being lowered down well in Spai$ + "candle", // 15 CD2 Candle burning down in Spain mausoleum sc59 + "geodrop", // 16 CD2 from sc54, George jumping down onto truck + "vulture", // 17 CD2 from sc54, vultures circling George's dead body + "enddemo", // 18 --- for end of single CD demo + "credits", // 19 CD2 credits, to follow "finale" sequence +}; + } // End of namespace Sword1 diff --git a/sword1/animation.h b/sword1/animation.h index b1a0ecc6a0..078311b739 100644 --- a/sword1/animation.h +++ b/sword1/animation.h @@ -26,10 +26,35 @@ #include "sword1/screen.h" #include "sword1/sound.h" +#include "sound/audiostream.h" +namespace Sword1 { +enum { + SEQ_FERRARI = 0, + SEQ_LADDER, + SEQ_STEPS, + SEQ_SEWER, + SEQ_INTRO, + SEQ_RIVER, + SEQ_TRUCK, + SEQ_GRAVE, + SEQ_MONTFCON, + SEQ_TAPESTRY, + SEQ_IRELAND, + SEQ_FINALE, + SEQ_HISTORY, + SEQ_SPANISH, + SEQ_WELL, + SEQ_CANDLE, + SEQ_GEODROP, + SEQ_VULTURE, + SEQ_ENDDEMO, + SEQ_CREDITS +}; -namespace Sword1 { +#define INTRO_LOGO_OVLS 12 +#define INTRO_TEXT_OVLS 8 class AnimationState : public Graphics::BaseAnimationState { private: @@ -38,6 +63,9 @@ private: public: AnimationState(Screen *scr, SoundMixer *snd, OSystem *sys); ~AnimationState(); + void updateScreen(); + OverlayColor *giveRgbBuffer(void); + bool soundFinished(); private: void drawYUV(int width, int height, byte *const *dat); @@ -45,19 +73,48 @@ private: #ifdef BACKEND_8BIT void setPalette(byte *pal); #endif + +protected: + virtual AudioStream *createAudioStream(const char *name, void *arg); }; class MoviePlayer { +public: + MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys); + ~MoviePlayer(void); + void play(uint32 id); private: + void insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal); + void processFrame(uint32 animId, AnimationState *anim, uint32 frameNo); + bool initOverlays(uint32 id); + void decompressRle(uint8 *src, uint8 *dest, uint32 srcSize); Screen *_scr; SoundMixer *_snd; OSystem *_sys; + static const char *_sequenceList[20]; + uint8 *_logoOvls[INTRO_LOGO_OVLS]; + OverlayColor *_introPal; +}; + +struct FileQueue { + AudioStream *stream; + FileQueue *next; +}; + +class SplittedAudioStream : public AudioStream { public: - MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys); - void play(const char *filename); + SplittedAudioStream(void); + ~SplittedAudioStream(void); + void appendStream(AudioStream *stream); + virtual int readBuffer(int16 *buffer, const int numSamples); + virtual bool isStereo(void) const; + virtual bool endOfData(void) const; + virtual int getRate(void) const; +private: + FileQueue *_queue; }; -} // End of namespace Sword2 +} // End of namespace Sword1 #endif diff --git a/sword1/credits.cpp b/sword1/credits.cpp new file mode 100644 index 0000000000..07d56ae96f --- /dev/null +++ b/sword1/credits.cpp @@ -0,0 +1,339 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003-2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "credits.h" +#include "screen.h" +#include "common/file.h" +#include "sound/mixer.h" +#include "common/util.h" +#include "sound/audiostream.h" + +#include "sword1.h" + +#define CREDITS_X 480 +#define CREDITS_Y 300 +#define BUFSIZE_Y 640 + +#define START_X ((640 - CREDITS_X) / 2) +#define START_Y ((480 - CREDITS_Y) / 2) + +#define SCROLL_TIMING (2000 / 59) // 29.5 frames per second + +#define LOGO_FADEUP_TIME (133 * 1000) +#define LOGO_FADEDOWN_TIME (163 * 1000) + +namespace Sword1 { + +enum { + FONT_PAL = 0, + FONT, + TEXT, + REVO_PAL, + REVO_LOGO, + F_EOF +}; + +enum { + FNT_LFT = 0, // left column + FNT_RGT, // right column + FNT_CEN, // centered + FNT_BIG = 64, // big font + FNT_EOL = 128, // linebreak + FNT_EOB = 255 // end of textblock +}; + + +CreditsPlayer::CreditsPlayer(OSystem *pSystem, SoundMixer *pMixer) { + _system = pSystem; + _mixer = pMixer; + _smlFont = _bigFont = NULL; +} + +bool spaceInBuf(uint16 blitSta, uint16 blitEnd, uint16 renderDest) { + if (blitEnd > blitSta) { + if ((renderDest > blitEnd) || (renderDest + 15 < blitSta)) + return true; + } else { + if ((renderDest > blitEnd) && (renderDest + 15 < blitSta)) + return true; + } + return false; +} + +void CreditsPlayer::play(void) { + AudioStream *bgSoundStream = AudioStream::openStreamFile("credits"); + if (bgSoundStream == NULL) { + warning("\"credits.ogg\" not found, skipping credits sequence"); + return; + } + ArcFile credFile; + if (!credFile.open("credits.dat")) { + warning("\"credits.dat\" not found, skipping credits sequence"); + return; + } + + uint8 *palSrc = credFile.fetchFile(FONT_PAL, &_palLen); + for (uint32 cnt = 0; cnt < _palLen; cnt++) + _palette[(cnt / 3) * 4 + cnt % 3] = palSrc[cnt]; + _palLen /= 3; + + generateFonts(&credFile); + + uint8 *textData = credFile.fetchFile(TEXT); + textData += READ_LE_UINT32(textData + SwordEngine::_systemVars.language * 4); + + uint8 *screenBuf = (uint8*)malloc(CREDITS_X * BUFSIZE_Y); + memset(screenBuf, 0, CREDITS_X * BUFSIZE_Y); + _system->copyRectToScreen(screenBuf, 640, 0, 0, 640, 480); + _system->setPalette(_palette, 0, _palLen); + _system->updateScreen(); + + // everything's initialized, time to render and show the credits. + PlayingSoundHandle bgSound; + _mixer->playInputStream(&bgSound, bgSoundStream, true, 0); + + int relDelay = 0; + uint16 scrollY = 0; + uint16 renderY = BUFSIZE_Y / 2; + uint16 clearY = 0xFFFF; + bool clearLine = false; + while (((*textData != FNT_EOB) || (scrollY != renderY)) && !SwordEngine::_systemVars.engineQuit) { + if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio + if (scrollY < BUFSIZE_Y - CREDITS_Y) + _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y); + else { + _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, BUFSIZE_Y - scrollY); + _system->copyRectToScreen(screenBuf, CREDITS_X, START_X, START_Y + BUFSIZE_Y - scrollY, CREDITS_X, CREDITS_Y - (BUFSIZE_Y - scrollY)); + } + _system->updateScreen(); + } else + warning("frame skipped"); + + while (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY) && (*textData != FNT_EOB)) { + if (*textData & FNT_EOL) { + renderY = (renderY + 16) % BUFSIZE_Y; // linebreak + clearLine = true; + *textData &= ~FNT_EOL; + } + if (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY)) { + if (clearLine) + memset(screenBuf + renderY * CREDITS_X, 0, 16 * CREDITS_X); + clearLine = false; + renderLine(screenBuf, textData + 1, renderY, *textData); + if (*textData & FNT_BIG) + renderY += 16; + while (*++textData != 0) // search for the start of next string + ; + textData++; + } + if (*textData == FNT_EOB) + clearY = renderY; + } + if ((*textData == FNT_EOB) && spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, clearY)) { + memset(screenBuf + clearY * CREDITS_X, 0, 16 * CREDITS_X); + clearY = (clearY + 16) % BUFSIZE_Y; + } + + relDelay += SCROLL_TIMING; + delay(relDelay - (int32)_mixer->getSoundElapsedTime(bgSound)); + scrollY = (scrollY + 1) % BUFSIZE_Y; + } + free(_smlFont); + free(_bigFont); + _smlFont = _bigFont = NULL; + free(screenBuf); + + // credits done, now show the revolution logo + uint8 *revoBuf = credFile.decompressFile(REVO_LOGO); + uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen); + _palLen /= 3; + while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !SwordEngine::_systemVars.engineQuit) { + _system->updateScreen(); + delay(100); + } + memset(_palette, 0, 256 * 4); + _system->setPalette(_palette, 0, 256); + _system->copyRectToScreen(revoBuf, 480, START_X, START_Y, CREDITS_X, CREDITS_Y); + _system->updateScreen(); + + fadePalette(revoPal, true, _palLen); + while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !SwordEngine::_systemVars.engineQuit) { + _system->updateScreen(); + delay(100); + } + fadePalette(revoPal, false, _palLen); + delay(3000); + + if (SwordEngine::_systemVars.engineQuit) + _mixer->stopAll(); + free(revoBuf); +} + +void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) { + int8 fadeDir = fadeup ? 1 : -1; + int fadeStart = fadeup ? 0 : 12; + + int relDelay = _system->getMillis(); + for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !SwordEngine::_systemVars.engineQuit; fadeStep += fadeDir) { + for (uint16 cnt = 0; cnt < len * 3; cnt++) + _palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12; + _system->setPalette(_palette, 0, 256); + _system->updateScreen(); + relDelay += 1000 / 12; + delay(relDelay - _system->getMillis()); + } +} + +void CreditsPlayer::renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags) { + uint8 *font; + uint16 fntSize = 16; + if (flags & FNT_BIG) { + font = _bigFont; + fntSize = 32; + flags &= ~FNT_BIG; + } else + font = _smlFont; + + uint16 width = getWidth(font, line); + uint16 xBufPos = (flags == FNT_CEN) ? (CREDITS_X - width) / 2 : ((flags == FNT_LFT) ? (234 - width) : 255); + uint8 *bufDest = screenBuf + yBufPos * CREDITS_X + xBufPos; + while (*line) { + uint8 *chrSrc = font + _numChars + (*line - 1) * fntSize * fntSize; + for (uint16 cnty = 0; cnty < fntSize; cnty++) { + for (uint16 cntx = 0; cntx < fntSize; cntx++) + bufDest[cnty * CREDITS_X + cntx] = chrSrc[cntx]; + chrSrc += fntSize; + } + bufDest += font[*line++ - 1]; + } +} + +uint16 CreditsPlayer::getWidth(uint8 *font, uint8 *line) { + uint16 width = 0; + while (*line) + width += font[*line++ - 1]; + return width; +} + +void CreditsPlayer::generateFonts(ArcFile *arcFile) { + _bigFont = arcFile->decompressFile(FONT); + _numChars = *_bigFont; + memmove(_bigFont, _bigFont + 1, _numChars * (32 * 32 + 1)); + _smlFont = (uint8*)malloc(_numChars * (32 * 32 + 1)); + uint8 *src = _bigFont + _numChars; + uint8 *dst = _smlFont + _numChars; + for (uint16 cnt = 0; cnt < _numChars; cnt++) { + _smlFont[cnt] = (_bigFont[cnt]++ + 1) / 2; // width table + for (uint16 cnty = 0; cnty < 16; cnty++) { + for (uint16 cntx = 0; cntx < 16; cntx++) { + uint8 resR = (uint8)((_palette[src[0] * 4 + 0] + _palette[src[1] * 4 + 0] + _palette[src[32] * 4 + 0] + _palette[src[33] * 4 + 0]) >> 2); + uint8 resG = (uint8)((_palette[src[0] * 4 + 1] + _palette[src[1] * 4 + 1] + _palette[src[32] * 4 + 1] + _palette[src[33] * 4 + 1]) >> 2); + uint8 resB = (uint8)((_palette[src[0] * 4 + 2] + _palette[src[1] * 4 + 2] + _palette[src[32] * 4 + 2] + _palette[src[33] * 4 + 2]) >> 2); + *dst++ = getPalIdx(resR, resG, resB); + src += 2; + } + src += 32; + } + } +} + +uint8 CreditsPlayer::getPalIdx(uint8 r, uint8 g, uint8 b) { + for (uint16 cnt = 0; cnt < _palLen; cnt++) + if ((_palette[cnt * 4 + 0] == r) && (_palette[cnt * 4 + 1] == g) && (_palette[cnt * 4 + 2] == b)) + return (uint8)cnt; + assert(_palLen < 256); + _palette[_palLen * 4 + 0] = r; + _palette[_palLen * 4 + 1] = g; + _palette[_palLen * 4 + 2] = b; + return (uint8)_palLen++; +} + +void CreditsPlayer::delay(int msecs) { + + OSystem::Event event; + uint32 start = _system->getMillis(); + do { + while (_system->pollEvent(event)) { + switch (event.event_code) { + case OSystem::EVENT_QUIT: + SwordEngine::_systemVars.engineQuit = true; + break; + default: + break; + } + } + if (msecs > 0) + _system->delayMillis(10); + } while ((_system->getMillis() < start + msecs) && !SwordEngine::_systemVars.engineQuit); +} + +ArcFile::ArcFile(void) { + _buf = NULL; +} + +ArcFile::~ArcFile(void) { + if (_buf) + free(_buf); +} + +bool ArcFile::open(const char *name) { + File arc; + if (!arc.open(name)) + return false; + _bufPos = _buf = (uint8*)malloc(arc.size()); + arc.read(_buf, arc.size()); + arc.close(); + return true; +} + +void ArcFile::enterPath(uint32 id) { + _bufPos += READ_LE_UINT32(_bufPos + id * 4); +} + +uint8 *ArcFile::fetchFile(uint32 fileId, uint32 *size) { + if (size) + *size = READ_LE_UINT32(_bufPos + (fileId + 1) * 4) - READ_LE_UINT32(_bufPos + fileId * 4); + return _bufPos + READ_LE_UINT32(_bufPos + fileId * 4); +} + +uint8 *ArcFile::decompressFile(uint32 fileId) { + uint32 size; + uint8 *srcBuf = fetchFile(fileId, &size); + uint8 *dstBuf = (uint8*)malloc(READ_LE_UINT32(srcBuf)); + uint8 *srcPos = srcBuf + 4; + uint8 *dstPos = dstBuf; + while (srcPos < srcBuf + size) { + uint16 len = READ_LE_UINT16(srcPos); + memset(dstPos, 0, len); + dstPos += len; + srcPos += 2; + if (srcPos < srcBuf + size) { + uint8 len = *srcPos++; + memcpy(dstPos, srcPos, len); + dstPos += len; + srcPos += len; + } + } + return dstBuf; +} + +}; // end of namespace Sword1 diff --git a/sword1/credits.h b/sword1/credits.h new file mode 100644 index 0000000000..5a4364ad3a --- /dev/null +++ b/sword1/credits.h @@ -0,0 +1,68 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2003-2004 The ScummVM project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#ifndef BS1CREDITS_H +#define BS1CREDITS_H + +#include "common/util.h" +class SoundMixer; +class OSystem; + +namespace Sword1 { + +class ArcFile { +public: + ArcFile(void); + ~ArcFile(void); + bool open(const char *name); + uint8 *fetchFile(uint32 fileId, uint32 *size = NULL); + uint8 *decompressFile(uint32 fileId); + void enterPath(uint32 id); + void backToRoot(void) { _bufPos = _buf; }; +private: + uint8 *_bufPos; + uint8 *_buf; +}; + +class CreditsPlayer { +public: + CreditsPlayer(OSystem *pSystem, SoundMixer *pMixer); + void play(void); +private: + void generateFonts(ArcFile *arcFile); + void renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags); + void fadePalette(uint8 *srcPal, bool fadeup, uint16 len); + void delay(int msecs); + uint16 getWidth(uint8 *font, uint8 *line); + uint8 getPalIdx(uint8 r, uint8 g, uint8 b); + uint8 _palette[256 * 4]; + uint32 _palLen; + uint8 _numChars; + + OSystem *_system; + SoundMixer *_mixer; + + uint8 *_smlFont, *_bigFont; +}; + +}; // end of namespace Sword1 + +#endif // BS1CREDITS_H diff --git a/sword1/logic.cpp b/sword1/logic.cpp index 660ee3517c..571535465d 100644 --- a/sword1/logic.cpp +++ b/sword1/logic.cpp @@ -34,6 +34,7 @@ #include "sword1/music.h" #include "sword1/swordres.h" #include "sword1/animation.h" +#include "sword1/credits.h" #include "sword1/debug.h" @@ -940,37 +941,13 @@ int Logic::fnSetPaletteToCut(Object *cpt, int32 id, int32 c, int32 d, int32 e, i int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int32 e, int32 f, int32 z, int32 x) { - static const char *sequence_list[20] = { - "ferrari", // 0 CD2 ferrari running down fitz in sc19 - "ladder", // 1 CD2 george walking down ladder to dig sc24->sc$ - "steps", // 2 CD2 george walking down steps sc23->sc24 - "sewer", // 3 CD1 george entering sewer sc2->sc6 - "intro", // 4 CD1 intro sequence ->sc1 - "river", // 5 CD1 george being thrown into river by flap & g$ - "truck", // 6 CD2 truck arriving at bull's head sc45->sc53/4 - "grave", // 7 BOTH george's grave in scotland, from sc73 + from sc38 $ - "montfcon", // 8 CD2 monfaucon clue in ireland dig, sc25 - "tapestry", // 9 CD2 tapestry room beyond spain well, sc61 - "ireland", // 10 CD2 ireland establishing shot europe_map->sc19 - "finale", // 11 CD2 grand finale at very end, from sc73 - "history", // 12 CD1 George's history lesson from Nico, in sc10 - "spanish", // 13 CD2 establishing shot for 1st visit to Spain, europe_m$ - "well", // 14 CD2 first time being lowered down well in Spai$ - "candle", // 15 CD2 Candle burning down in Spain mausoleum sc59 - "geodrop", // 16 CD2 from sc54, George jumping down onto truck - "vulture", // 17 CD2 from sc54, vultures circling George's dead body - "enddemo", // 18 --- for end of single CD demo - "credits", // 19 CD2 credits, to follow "finale" sequence - // etc. - }; - - MoviePlayer player(_screen, _mixer, _system); - - player.play(sequence_list[sequenceId]); - - //_scriptVars[NEW_PALETTE] = 1; - /* the logic usually calls fnFadeDown before playing the sequence, so we have to - set NEW_PALETTE now to force a palette refresh */ + if ((SwordEngine::_systemVars.cutscenePackVersion == 1) && (sequenceId == SEQ_CREDITS)) { + CreditsPlayer player(_system, _mixer); + player.play(); + } else { + MoviePlayer player(_screen, _mixer, _system); + player.play(sequenceId); + } return SCRIPT_CONT; } diff --git a/sword1/sword1.cpp b/sword1/sword1.cpp index f64a77f219..f5f1f8bad4 100644 --- a/sword1/sword1.cpp +++ b/sword1/sword1.cpp @@ -1134,6 +1134,15 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or error(msg); } } + + // check cutscene pack version + _systemVars.cutscenePackVersion = 0; +#ifdef USE_MPEG2 + if (test.open("intro.snd")) { + _systemVars.cutscenePackVersion = 1; + test.close(); + } +#endif } int SwordEngine::go() { diff --git a/sword1/sword1.h b/sword1/sword1.h index 52db32e867..f7f21803f1 100644 --- a/sword1/sword1.h +++ b/sword1/sword1.h @@ -63,6 +63,8 @@ struct SystemVars { uint8 showText; uint8 language; bool isDemo; + + uint8 cutscenePackVersion; }; class SwordEngine : public Engine { -- cgit v1.2.3