aboutsummaryrefslogtreecommitdiff
path: root/sword1
diff options
context:
space:
mode:
authorRobert Göffringmann2004-12-05 02:55:06 +0000
committerRobert Göffringmann2004-12-05 02:55:06 +0000
commit5d32a2c034a1e9036c9dcc721b6bfe27c46eb904 (patch)
treeeab152166ad59cdb6e5760599f1a6784ee522685 /sword1
parent095549125b303db33702f30aeacb924e0b703ea0 (diff)
downloadscummvm-rg350-5d32a2c034a1e9036c9dcc721b6bfe27c46eb904.tar.gz
scummvm-rg350-5d32a2c034a1e9036c9dcc721b6bfe27c46eb904.tar.bz2
scummvm-rg350-5d32a2c034a1e9036c9dcc721b6bfe27c46eb904.zip
added support for an international BS1 cutscene pack (which we didn't release yet)
svn-id: r15983
Diffstat (limited to 'sword1')
-rw-r--r--sword1/animation.cpp222
-rw-r--r--sword1/animation.h65
-rw-r--r--sword1/credits.cpp339
-rw-r--r--sword1/credits.h68
-rw-r--r--sword1/logic.cpp39
-rw-r--r--sword1/sword1.cpp9
-rw-r--r--sword1/sword1.h2
7 files changed, 698 insertions, 46 deletions
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 {