aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/sequence
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/sequence')
-rw-r--r--engines/kyra/sequence/seqplayer.cpp658
-rw-r--r--engines/kyra/sequence/seqplayer.h124
-rw-r--r--engines/kyra/sequence/sequences_darkmoon.cpp1643
-rw-r--r--engines/kyra/sequence/sequences_eob.cpp1152
-rw-r--r--engines/kyra/sequence/sequences_hof.cpp3515
-rw-r--r--engines/kyra/sequence/sequences_hof.h74
-rw-r--r--engines/kyra/sequence/sequences_lok.cpp2116
-rw-r--r--engines/kyra/sequence/sequences_lol.cpp1538
-rw-r--r--engines/kyra/sequence/sequences_mr.cpp237
-rw-r--r--engines/kyra/sequence/sequences_v2.cpp130
10 files changed, 11187 insertions, 0 deletions
diff --git a/engines/kyra/sequence/seqplayer.cpp b/engines/kyra/sequence/seqplayer.cpp
new file mode 100644
index 0000000000..d039a352f8
--- /dev/null
+++ b/engines/kyra/sequence/seqplayer.cpp
@@ -0,0 +1,658 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/sequence/seqplayer.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+
+#include "common/system.h"
+
+#define SEQOP(n, x) { n, &SeqPlayer::x, #x }
+
+namespace Kyra {
+
+SeqPlayer::SeqPlayer(KyraEngine_LoK *vm, OSystem *system) {
+ _vm = vm;
+ _system = system;
+
+ _screen = vm->screen();
+ _sound = vm->sound();
+ _res = vm->resource();
+
+ _copyViewOffs = false;
+ _specialBuffer = 0;
+
+ for (int i = 0; i < ARRAYSIZE(_handShapes); ++i)
+ _handShapes[i] = 0;
+ for (int i = 0; i < ARRAYSIZE(_seqMovies); ++i)
+ _seqMovies[i].movie = 0;
+}
+
+SeqPlayer::~SeqPlayer() {
+ freeHandShapes();
+
+ for (int i = 0; i < ARRAYSIZE(_seqMovies); ++i) {
+ if (!_seqMovies[i].movie)
+ continue;
+ _seqMovies[i].movie->close();
+ delete _seqMovies[i].movie;
+ _seqMovies[i].movie = 0;
+ }
+}
+
+uint8 *SeqPlayer::setPanPages(int pageNum, int shape) {
+ uint8 *panPage = 0;
+ const uint8 *data = _screen->getCPagePtr(pageNum);
+ uint16 numShapes = READ_LE_UINT16(data);
+ if (shape < numShapes) {
+ uint32 offs = 0;
+ if (_vm->gameFlags().useAltShapeHeader)
+ offs = READ_LE_UINT32(data + 2 + shape * 4);
+ else
+ offs = READ_LE_UINT16(data + 2 + shape * 2);
+
+ if (offs != 0) {
+ data += offs;
+ uint16 sz = READ_LE_UINT16(data + 6);
+ panPage = new uint8[sz];
+ assert(panPage);
+ memcpy(panPage, data, sz);
+ }
+ }
+ return panPage;
+}
+
+void SeqPlayer::makeHandShapes() {
+ _screen->loadBitmap("WRITING.CPS", 3, 3, &_screen->getPalette(0));
+ if (_vm->gameFlags().platform == Common::kPlatformMacintosh || _vm->gameFlags().platform == Common::kPlatformAmiga) {
+ freeHandShapes();
+
+ int pageBackUp = _screen->_curPage;
+ _screen->_curPage = 2;
+ _handShapes[0] = _screen->encodeShape(0, 0, 88, 122, 0);
+ assert(_handShapes[0]);
+ _handShapes[1] = _screen->encodeShape(88, 0, 80, 117, 0);
+ assert(_handShapes[1]);
+ _handShapes[2] = _screen->encodeShape(168, 0, 117, 124, 0);
+ assert(_handShapes[2]);
+ _screen->_curPage = pageBackUp;
+ } else {
+ for (int i = 0; i < ARRAYSIZE(_handShapes); ++i) {
+ if (_handShapes[i])
+ delete[] _handShapes[i];
+ _handShapes[i] = setPanPages(3, i);
+ assert(_handShapes[i]);
+ }
+ }
+}
+
+void SeqPlayer::freeHandShapes() {
+ for (int i = 0; i < ARRAYSIZE(_handShapes); ++i) {
+ delete[] _handShapes[i];
+ _handShapes[i] = 0;
+ }
+}
+
+void SeqPlayer::s1_wsaOpen() {
+ uint8 wsaObj = *_seqData++;
+ assert(wsaObj < ARRAYSIZE(_seqMovies));
+ uint8 offscreenDecode = *_seqData++;
+ _seqWsaCurDecodePage = _seqMovies[wsaObj].page = (offscreenDecode == 0) ? 0 : 3;
+ if (!_seqMovies[wsaObj].movie)
+ _seqMovies[wsaObj].movie = _vm->createWSAMovie();
+ _seqMovies[wsaObj].movie->open(_vm->seqWSATable()[wsaObj], offscreenDecode, 0);
+ _seqMovies[wsaObj].frame = 0;
+ _seqMovies[wsaObj].numFrames = _seqMovies[wsaObj].movie->frames() - 1;
+}
+
+void SeqPlayer::s1_wsaClose() {
+ uint8 wsaObj = *_seqData++;
+ assert(wsaObj < ARRAYSIZE(_seqMovies));
+ if (_seqMovies[wsaObj].movie)
+ _seqMovies[wsaObj].movie->close();
+}
+
+void SeqPlayer::s1_wsaPlayFrame() {
+ uint8 wsaObj = *_seqData++;
+ assert(wsaObj < ARRAYSIZE(_seqMovies));
+ int16 frame = (int8)*_seqData++;
+ _seqMovies[wsaObj].pos.x = READ_LE_UINT16(_seqData); _seqData += 2;
+ _seqMovies[wsaObj].pos.y = *_seqData++;
+ assert(_seqMovies[wsaObj].movie);
+ _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, 0, 0);
+ _seqMovies[wsaObj].frame = frame;
+}
+
+void SeqPlayer::s1_wsaPlayNextFrame() {
+ uint8 wsaObj = *_seqData++;
+ assert(wsaObj < ARRAYSIZE(_seqMovies));
+ int16 frame = ++_seqMovies[wsaObj].frame;
+ if (frame > _seqMovies[wsaObj].numFrames) {
+ frame = 0;
+ _seqMovies[wsaObj].frame = 0;
+ }
+ _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, 0, 0);
+}
+
+void SeqPlayer::s1_wsaPlayPrevFrame() {
+ uint8 wsaObj = *_seqData++;
+ assert(wsaObj < ARRAYSIZE(_seqMovies));
+ int16 frame = --_seqMovies[wsaObj].frame;
+ if (frame < 0) {
+ frame = _seqMovies[wsaObj].numFrames;
+ _seqMovies[wsaObj].frame = frame;
+ } else {
+ _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, 0, 0);
+ }
+}
+
+void SeqPlayer::s1_drawShape() {
+ uint8 shapeNum = *_seqData++;
+ int x = READ_LE_UINT16(_seqData); _seqData += 2;
+ int y = *_seqData++;
+ _screen->drawShape(2, _handShapes[shapeNum], x, y, 0, 0, 0);
+}
+
+void SeqPlayer::s1_waitTicks() {
+ uint16 ticks = READ_LE_UINT16(_seqData); _seqData += 2;
+ _vm->delay(ticks * _vm->tickLength());
+}
+
+void SeqPlayer::s1_copyWaitTicks() {
+ s1_copyView();
+ s1_waitTicks();
+}
+
+void SeqPlayer::s1_shuffleScreen() {
+ _screen->shuffleScreen(0, 16, 320, 128, 2, 0, 0, false);
+ if (_specialBuffer)
+ _screen->copyRegionToBuffer(2, 0, 16, 320, 128, _specialBuffer);
+ _screen->_curPage = 0;
+}
+
+void SeqPlayer::s1_copyView() {
+ int h = !_copyViewOffs ? 120 : 128;
+
+ if (_specialBuffer && !_copyViewOffs)
+ _screen->copyToPage0(16, h, 3, _specialBuffer);
+ else
+ _screen->copyRegion(0, 16, 0, 16, 320, h, 2, 0);
+}
+
+void SeqPlayer::s1_loopInit() {
+ uint8 seqLoop = *_seqData++;
+ if (seqLoop < ARRAYSIZE(_seqLoopTable))
+ _seqLoopTable[seqLoop].ptr = _seqData;
+ else
+ _seqQuitFlag = true;
+}
+
+void SeqPlayer::s1_loopInc() {
+ uint8 seqLoop = *_seqData++;
+ uint16 seqLoopCount = READ_LE_UINT16(_seqData); _seqData += 2;
+ if (_seqLoopTable[seqLoop].count == 0xFFFF) {
+ _seqLoopTable[seqLoop].count = seqLoopCount - 1;
+ _seqData = _seqLoopTable[seqLoop].ptr;
+ } else if (_seqLoopTable[seqLoop].count == 0) {
+ _seqLoopTable[seqLoop].count = 0xFFFF;
+ _seqLoopTable[seqLoop].ptr = 0;
+ } else {
+ --_seqLoopTable[seqLoop].count;
+ _seqData = _seqLoopTable[seqLoop].ptr;
+ }
+}
+
+void SeqPlayer::s1_skip() {
+ uint8 a = *_seqData++;
+ warning("STUB: s1_skip(%d)", a);
+}
+
+void SeqPlayer::s1_loadPalette() {
+ uint8 colNum = *_seqData++;
+
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
+ if (!colNum)
+ _screen->copyPalette(0, 6);
+ else if (colNum == 3)
+ _screen->copyPalette(0, 7);
+ else if (colNum == 4)
+ _screen->copyPalette(0, 3);
+
+ _screen->setScreenPalette(_screen->getPalette(0));
+ } else {
+ _screen->loadPalette(_vm->seqCOLTable()[colNum], _screen->getPalette(0));
+ }
+}
+
+void SeqPlayer::s1_loadBitmap() {
+ uint8 cpsNum = *_seqData++;
+ _screen->loadBitmap(_vm->seqCPSTable()[cpsNum], 3, 3, &_screen->getPalette(0));
+}
+
+void SeqPlayer::s1_fadeToBlack() {
+ _screen->fadeToBlack();
+}
+
+void SeqPlayer::s1_printText() {
+ static const uint8 colorMap[] = { 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0 };
+ uint8 txt = *_seqData++;
+
+ if (!_vm->textEnabled())
+ return;
+
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga)
+ _screen->fillRect(0, 180, 319, 195, 0);
+ else
+ _screen->fillRect(0, 180, 319, 195, 12);
+ _screen->setTextColorMap(colorMap);
+ if (!_seqDisplayTextFlag) {
+ const char *str = _vm->seqTextsTable()[txt];
+ int x = (Screen::SCREEN_W - _screen->getTextWidth(str)) / 2;
+ _screen->printText(str, x, 180, 0xF, 0xC);
+ } else {
+ _seqDisplayedTextTimer = _system->getMillis() + 1000 / ((_vm->gameFlags().lang == Common::FR_FRA) ? 120 : 60);
+ _seqDisplayedText = txt;
+ _seqDisplayedChar = 0;
+ const char *str = _vm->seqTextsTable()[_seqDisplayedText];
+ _seqDisplayedTextX = (Screen::SCREEN_W - _screen->getTextWidth(str)) / 2;
+ }
+}
+
+void SeqPlayer::s1_printTalkText() {
+ uint8 txt = *_seqData++;
+ int x = READ_LE_UINT16(_seqData); _seqData += 2;
+ int y = *_seqData++;
+ uint8 fillColor = *_seqData++;
+
+ if (!_vm->textEnabled())
+ return;
+
+ int b;
+ if (_seqTalkTextPrinted && !_seqTalkTextRestored) {
+ if (_seqWsaCurDecodePage != 0 && !_specialBuffer)
+ b = 2;
+ else
+ b = 0;
+ _vm->text()->restoreTalkTextMessageBkgd(2, b);
+ }
+ _seqTalkTextPrinted = true;
+ _seqTalkTextRestored = false;
+ if (_seqWsaCurDecodePage != 0 && !_specialBuffer)
+ b = 2;
+ else
+ b = 0;
+ _vm->text()->printTalkTextMessage(_vm->seqTextsTable()[txt], x, y, fillColor, b, 2);
+}
+
+void SeqPlayer::s1_restoreTalkText() {
+ if (_seqTalkTextPrinted && !_seqTalkTextRestored && _vm->textEnabled()) {
+ int b;
+ if (_seqWsaCurDecodePage != 0 && !_specialBuffer)
+ b = 2;
+ else
+ b = 0;
+ _vm->text()->restoreTalkTextMessageBkgd(2, b);
+ _seqTalkTextRestored = true;
+ }
+}
+
+void SeqPlayer::s1_clearCurrentScreen() {
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga)
+ _screen->fillRect(10, 180, 319, 195, 0);
+ else
+ _screen->fillRect(10, 180, 319, 196, 0xC);
+}
+
+void SeqPlayer::s1_break() {
+ // Do nothing
+}
+
+void SeqPlayer::s1_fadeFromBlack() {
+ _screen->fadeFromBlack();
+}
+
+void SeqPlayer::s1_copyRegion() {
+ uint8 srcPage = *_seqData++;
+ uint8 dstPage = *_seqData++;
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, srcPage, dstPage);
+}
+
+void SeqPlayer::s1_copyRegionSpecial() {
+ static const uint8 colorMap[] = { 0, 0, 0, 0, 0, 12, 12, 0, 0, 0, 0, 0 };
+ const char *copyStr = 0;
+ if (!_vm->gameFlags().isTalkie)
+ copyStr = "Copyright (c) 1992 Westwood Studios";
+ else
+ copyStr = "Copyright (c) 1992,1993 Westwood Studios";
+
+ uint8 so = *_seqData++;
+ switch (so) {
+ case 0:
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga)
+ _screen->copyRegion(0, 0, 0, 47, 312, 76, 2, 0);
+ else
+ _screen->copyRegion(0, 0, 0, 47, 320, 77, 2, 0);
+ break;
+ case 1:
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga)
+ _screen->copyRegion(0, 0, 8, 47, 312, 55, 2, 0);
+ else
+ _screen->copyRegion(0, 0, 0, 47, 320, 56, 2, 0);
+ break;
+ case 2:
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga) {
+ _screen->copyRegion(104, 72, 104, 72, 40, 87, 2, 0);
+ _screen->copyRegion(128, 159, 128, 159, 32, 17, 2, 0);
+ _screen->copyRegion(160, 105, 160, 105, 32, 9, 2, 0);
+ _screen->copyRegion(200, 83, 200, 83, 88, 93, 2, 0);
+ } else {
+ _screen->copyRegion(107, 72, 107, 72, 43, 87, 2, 0);
+ _screen->copyRegion(130, 159, 130, 159, 35, 17, 2, 0);
+ _screen->copyRegion(165, 105, 165, 105, 32, 9, 2, 0);
+ _screen->copyRegion(206, 83, 206, 83, 94, 93, 2, 0);
+ }
+ break;
+ case 3:
+ _screen->copyRegion(152, 56, 152, 56, 48, 48, 2, 0);
+ break;
+ case 4: {
+ _screen->_charWidth = -2;
+ const int x = (Screen::SCREEN_W - _screen->getTextWidth(copyStr)) / 2;
+ const int y = 179;
+ _screen->setTextColorMap(colorMap);
+ if (_vm->gameFlags().platform != Common::kPlatformAmiga)
+ _screen->printText(copyStr, x + 1, y + 1, 0xB, 0xC);
+ _screen->printText(copyStr, x, y, 0xF, 0xC);
+ } break;
+ case 5:
+ _screen->_curPage = 2;
+ break;
+ default:
+ error("Invalid subopcode %d for s1_copyRegionSpecial", so);
+ }
+}
+
+void SeqPlayer::s1_fillRect() {
+ int x1 = READ_LE_UINT16(_seqData); _seqData += 2;
+ int y1 = *_seqData++;
+ int x2 = READ_LE_UINT16(_seqData); _seqData += 2;
+ int y2 = *_seqData++;
+ uint8 color = *_seqData++;
+ uint8 page = *_seqData++;
+ _screen->fillRect(x1, y1, x2, y2, color, page);
+}
+
+void SeqPlayer::s1_playEffect() {
+ uint8 track = *_seqData++;
+ _vm->delay(3 * _vm->tickLength());
+
+ if (_vm->gameFlags().platform == Common::kPlatformPC98) {
+ if (track > 21 && track < 38)
+ track -= 22;
+ else
+ return;
+ }
+
+ _sound->playSoundEffect(track);
+}
+
+void SeqPlayer::s1_playTrack() {
+ uint8 msg = *_seqData++;
+
+ if (msg == 0 && _vm->gameFlags().platform == Common::kPlatformPC98) {
+ _sound->haltTrack();
+ } else if (msg == 1) {
+ _sound->beginFadeOut();
+ } else {
+ _sound->haltTrack();
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns)
+ msg += 2;
+ _sound->playTrack(msg);
+ }
+}
+
+void SeqPlayer::s1_allocTempBuffer() {
+ if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
+ _seqQuitFlag = true;
+ } else {
+ if (!_specialBuffer && !_copyViewOffs) {
+ _specialBuffer = new uint8[40960];
+ assert(_specialBuffer);
+ _screen->copyRegionToBuffer(2, 0, 16, 320, 128, _specialBuffer);
+ }
+ }
+}
+
+void SeqPlayer::s1_textDisplayEnable() {
+ _seqDisplayTextFlag = true;
+}
+
+void SeqPlayer::s1_textDisplayDisable() {
+ _seqDisplayTextFlag = false;
+}
+
+void SeqPlayer::s1_endOfScript() {
+ _seqQuitFlag = true;
+}
+
+void SeqPlayer::s1_loadIntroVRM() {
+ _res->loadPakFile("INTRO.VRM");
+}
+
+void SeqPlayer::s1_playVocFile() {
+ _vm->snd_voiceWaitForFinish(false);
+ uint8 a = *_seqData++;
+ if (_vm->speechEnabled())
+ _vm->snd_playVoiceFile(a);
+}
+
+void SeqPlayer::s1_miscUnk3() {
+ warning("STUB: s1_miscUnk3");
+}
+
+void SeqPlayer::s1_prefetchVocFile() {
+ _seqData++;
+ // we do not have to prefetch the vocfiles on modern systems
+}
+
+bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) {
+ assert(seqData);
+
+ static const SeqEntry floppySeqProcs[] = {
+ // 0x00
+ SEQOP(3, s1_wsaOpen),
+ SEQOP(2, s1_wsaClose),
+ SEQOP(6, s1_wsaPlayFrame),
+ SEQOP(2, s1_wsaPlayNextFrame),
+ // 0x04
+ SEQOP(2, s1_wsaPlayPrevFrame),
+ SEQOP(5, s1_drawShape),
+ SEQOP(3, s1_waitTicks),
+ SEQOP(3, s1_copyWaitTicks),
+ // 0x08
+ SEQOP(1, s1_shuffleScreen),
+ SEQOP(1, s1_copyView),
+ SEQOP(2, s1_loopInit),
+ SEQOP(4, s1_loopInc),
+ // 0x0C
+ SEQOP(2, s1_loadPalette),
+ SEQOP(2, s1_loadBitmap),
+ SEQOP(1, s1_fadeToBlack),
+ SEQOP(2, s1_printText),
+ // 0x10
+ SEQOP(6, s1_printTalkText),
+ SEQOP(1, s1_restoreTalkText),
+ SEQOP(1, s1_clearCurrentScreen),
+ SEQOP(1, s1_break),
+ // 0x14
+ SEQOP(1, s1_fadeFromBlack),
+ SEQOP(3, s1_copyRegion),
+ SEQOP(2, s1_copyRegionSpecial),
+ SEQOP(9, s1_fillRect),
+ // 0x18
+ SEQOP(2, s1_playEffect),
+ SEQOP(2, s1_playTrack),
+ SEQOP(1, s1_allocTempBuffer),
+ SEQOP(1, s1_textDisplayEnable),
+ // 0x1C
+ SEQOP(1, s1_textDisplayDisable),
+ SEQOP(1, s1_endOfScript)
+ };
+
+ static const SeqEntry cdromSeqProcs[] = {
+ // 0x00
+ SEQOP(3, s1_wsaOpen),
+ SEQOP(2, s1_wsaClose),
+ SEQOP(6, s1_wsaPlayFrame),
+ SEQOP(2, s1_wsaPlayNextFrame),
+ // 0x04
+ SEQOP(2, s1_wsaPlayPrevFrame),
+ SEQOP(5, s1_drawShape),
+ SEQOP(3, s1_waitTicks),
+ SEQOP(3, s1_waitTicks),
+ // 0x08
+ SEQOP(3, s1_copyWaitTicks),
+ SEQOP(1, s1_shuffleScreen),
+ SEQOP(1, s1_copyView),
+ SEQOP(2, s1_loopInit),
+ // 0x0C
+ SEQOP(4, s1_loopInc),
+ SEQOP(4, s1_loopInc),
+ SEQOP(2, s1_skip),
+ SEQOP(2, s1_loadPalette),
+ // 0x10
+ SEQOP(2, s1_loadBitmap),
+ SEQOP(1, s1_fadeToBlack),
+ SEQOP(2, s1_printText),
+ SEQOP(6, s1_printTalkText),
+ // 0x14
+ SEQOP(1, s1_restoreTalkText),
+ SEQOP(1, s1_clearCurrentScreen),
+ SEQOP(1, s1_break),
+ SEQOP(1, s1_fadeFromBlack),
+ // 0x18
+ SEQOP(3, s1_copyRegion),
+ SEQOP(2, s1_copyRegionSpecial),
+ SEQOP(9, s1_fillRect),
+ SEQOP(2, s1_playEffect),
+ // 0x1C
+ SEQOP(2, s1_playTrack),
+ SEQOP(1, s1_allocTempBuffer),
+ SEQOP(1, s1_textDisplayEnable),
+ SEQOP(1, s1_textDisplayDisable),
+ // 0x20
+ SEQOP(1, s1_endOfScript),
+ SEQOP(1, s1_loadIntroVRM),
+ SEQOP(2, s1_playVocFile),
+ SEQOP(1, s1_miscUnk3),
+ // 0x24
+ SEQOP(2, s1_prefetchVocFile)
+ };
+
+ const SeqEntry *commands;
+ int numCommands;
+
+ if (_vm->gameFlags().isTalkie) {
+ commands = cdromSeqProcs;
+ numCommands = ARRAYSIZE(cdromSeqProcs);
+ } else {
+ commands = floppySeqProcs;
+ numCommands = ARRAYSIZE(floppySeqProcs);
+ }
+
+ bool seqSkippedFlag = false;
+
+ _seqData = seqData;
+
+ _seqDisplayedTextTimer = 0xFFFFFFFF;
+ _seqDisplayTextFlag = false;
+ _seqDisplayedTextX = 0;
+ _seqDisplayedText = 0;
+ _seqDisplayedChar = 0;
+ _seqTalkTextRestored = false;
+ _seqTalkTextPrinted = false;
+
+ _seqQuitFlag = false;
+ _seqWsaCurDecodePage = 0;
+
+ for (int i = 0; i < 20; ++i) {
+ _seqLoopTable[i].ptr = 0;
+ _seqLoopTable[i].count = 0xFFFF;
+ }
+
+ memset(_seqMovies, 0, sizeof(_seqMovies));
+
+ _screen->_curPage = 0;
+ while (!_seqQuitFlag && !_vm->shouldQuit()) {
+ if (skipSeq && _vm->seq_skipSequence()) {
+ while (1) {
+ uint8 code = *_seqData;
+ if (commands[code].proc == &SeqPlayer::s1_endOfScript || commands[code].proc == &SeqPlayer::s1_break)
+ break;
+
+ _seqData += commands[code].len;
+ }
+ skipSeq = false;
+ seqSkippedFlag = true;
+ }
+ // used in Kallak writing intro
+ if (_seqDisplayTextFlag && _seqDisplayedTextTimer != 0xFFFFFFFF && _vm->textEnabled()) {
+ if (_seqDisplayedTextTimer < _system->getMillis()) {
+ char charStr[3];
+ charStr[0] = _vm->seqTextsTable()[_seqDisplayedText][_seqDisplayedChar];
+ charStr[1] = charStr[2] = '\0';
+ if (_vm->gameFlags().lang == Common::JA_JPN)
+ charStr[1] = _vm->seqTextsTable()[_seqDisplayedText][++_seqDisplayedChar];
+ _screen->printText(charStr, _seqDisplayedTextX, 180, 0xF, 0xC);
+ _seqDisplayedTextX += _screen->getCharWidth((uint8)charStr[0]);
+ ++_seqDisplayedChar;
+
+ if (_vm->seqTextsTable()[_seqDisplayedText][_seqDisplayedChar] == '\0')
+ _seqDisplayedTextTimer = 0xFFFFFFFF;
+ else
+ _seqDisplayedTextTimer = _system->getMillis() + 1000 / ((_vm->gameFlags().lang == Common::FR_FRA) ? 120 : 60);
+ }
+ }
+
+ uint8 seqCode = *_seqData++;
+ if (seqCode < numCommands) {
+ SeqProc currentProc = commands[seqCode].proc;
+ debugC(5, kDebugLevelSequence, "0x%.4X seqCode = %d (%s)", (uint16)(_seqData - 1 - seqData), seqCode, commands[seqCode].desc);
+ (this->*currentProc)();
+ } else {
+ error("Invalid sequence opcode %d called from 0x%.04X", seqCode, (uint16)(_seqData - 1 - seqData));
+ }
+
+ _screen->updateScreen();
+ }
+ delete[] _specialBuffer;
+ _specialBuffer = 0;
+
+ for (uint i = 0; i < ARRAYSIZE(_seqMovies); ++i) {
+ delete _seqMovies[i].movie;
+ _seqMovies[i].movie = 0;
+ }
+ return seqSkippedFlag;
+}
+
+
+} // End of namespace Kyra
diff --git a/engines/kyra/sequence/seqplayer.h b/engines/kyra/sequence/seqplayer.h
new file mode 100644
index 0000000000..8ca7fbac1b
--- /dev/null
+++ b/engines/kyra/sequence/seqplayer.h
@@ -0,0 +1,124 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KYRA_SEQPLAYER_H
+#define KYRA_SEQPLAYER_H
+
+#include "kyra/engine/kyra_lok.h"
+
+namespace Kyra {
+
+class SeqPlayer {
+public:
+ SeqPlayer(KyraEngine_LoK *vm, OSystem *system);
+ ~SeqPlayer();
+
+ void setCopyViewOffs(bool offs) {
+ _copyViewOffs = offs;
+ }
+
+ void makeHandShapes();
+ void freeHandShapes();
+
+ bool playSequence(const uint8 *seqData, bool skipSeq);
+
+ uint8 *setPanPages(int pageNum, int shape);
+protected:
+ KyraEngine_LoK *_vm;
+ OSystem *_system;
+ Screen *_screen;
+ Sound *_sound;
+ Resource *_res;
+
+ uint8 *_handShapes[3];
+ bool _copyViewOffs;
+
+ typedef void (SeqPlayer::*SeqProc)();
+ struct SeqEntry {
+ uint8 len;
+ SeqProc proc;
+ const char *desc;
+ };
+
+ // the sequence procs
+ void s1_wsaOpen();
+ void s1_wsaClose();
+ void s1_wsaPlayFrame();
+ void s1_wsaPlayNextFrame();
+ void s1_wsaPlayPrevFrame();
+ void s1_drawShape();
+ void s1_waitTicks();
+ void s1_copyWaitTicks();
+ void s1_shuffleScreen();
+ void s1_copyView();
+ void s1_loopInit();
+ void s1_loopInc();
+ void s1_skip();
+ void s1_loadPalette();
+ void s1_loadBitmap();
+ void s1_fadeToBlack();
+ void s1_printText();
+ void s1_printTalkText();
+ void s1_restoreTalkText();
+ void s1_clearCurrentScreen();
+ void s1_break();
+ void s1_fadeFromBlack();
+ void s1_copyRegion();
+ void s1_copyRegionSpecial();
+ void s1_fillRect();
+ void s1_playEffect();
+ void s1_playTrack();
+ void s1_allocTempBuffer();
+ void s1_textDisplayEnable();
+ void s1_textDisplayDisable();
+ void s1_endOfScript();
+ void s1_loadIntroVRM();
+ void s1_playVocFile();
+ void s1_miscUnk3();
+ void s1_prefetchVocFile();
+
+ struct SeqMovie {
+ Movie *movie;
+ int32 page;
+ int16 frame;
+ int16 numFrames;
+ Common::Point pos;
+ };
+
+ const uint8 *_seqData;
+ uint8 *_specialBuffer;
+ SeqMovie _seqMovies[12];
+ SeqLoop _seqLoopTable[20];
+ uint16 _seqWsaCurDecodePage;
+ uint32 _seqDisplayedTextTimer;
+ bool _seqDisplayTextFlag;
+ uint8 _seqDisplayedText;
+ uint8 _seqDisplayedChar;
+ uint16 _seqDisplayedTextX;
+ bool _seqTalkTextPrinted;
+ bool _seqTalkTextRestored;
+ bool _seqQuitFlag;
+};
+
+} // End of namespace Kyra
+
+#endif
diff --git a/engines/kyra/sequence/sequences_darkmoon.cpp b/engines/kyra/sequence/sequences_darkmoon.cpp
new file mode 100644
index 0000000000..532591e9b0
--- /dev/null
+++ b/engines/kyra/sequence/sequences_darkmoon.cpp
@@ -0,0 +1,1643 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/engine/darkmoon.h"
+#include "kyra/graphics/screen_eob.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+
+#include "common/system.h"
+
+#include "base/version.h"
+
+namespace Kyra {
+
+class DarkmoonSequenceHelper {
+friend class DarkMoonEngine;
+public:
+ enum Mode {
+ kIntro,
+ kFinale
+ };
+
+ DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, Mode mode);
+ ~DarkmoonSequenceHelper();
+
+ void loadScene(int index, int pageNum);
+ void animCommand(int index, int del = -1);
+
+ void printText(int index, int color);
+ void fadeText();
+
+ void update(int srcPage);
+
+ void setPalette(int index);
+ void fadePalette(int index, int del);
+ void copyPalette(int srcIndex, int destIndex);
+
+ void initDelayedPaletteFade(int palIndex, int rate);
+ bool processDelayedPaletteFade();
+
+ void delay(uint32 ticks);
+ void waitForSongNotifier(int index, bool introUpdateAnim = false);
+
+private:
+ void setPaletteWithoutTextColor(int index);
+
+ OSystem *_system;
+ DarkMoonEngine *_vm;
+ Screen_EoB *_screen;
+
+ struct Config {
+ Config(const char *const *str, const char *const *cpsfiles, const uint8 **cpsdata, const char *const *pal, const DarkMoonShapeDef **shp, const DarkMoonAnimCommand **anim, bool loadScenePalette, bool paletteFading, bool animCmdRestorePalette, bool shapeBackgroundFading, int animPalOffset, int animType1ShapeDim, bool animCmd5SetPalette, int animCmd5ExtraPage) : strings(str), cpsFiles(cpsfiles), cpsData(cpsdata), palFiles(pal), shapeDefs(shp), animData(anim), loadScenePal(loadScenePalette), palFading(paletteFading), animCmdRestorePal(animCmdRestorePalette), shpBackgroundFading(shapeBackgroundFading), animPalOffs(animPalOffset), animCmd1ShapeFrame(animType1ShapeDim), animCmd5SetPal(animCmd5SetPalette), animCmd5AltPage(animCmd5ExtraPage) {}
+ const char *const *strings;
+ const char *const *cpsFiles;
+ const uint8 **cpsData;
+ const char *const *palFiles;
+ const DarkMoonShapeDef **shapeDefs;
+ const DarkMoonAnimCommand **animData;
+ bool loadScenePal;
+ bool palFading;
+ bool animCmdRestorePal;
+ bool shpBackgroundFading;
+ int animPalOffs;
+ int animCmd1ShapeFrame;
+ bool animCmd5SetPal;
+ int animCmd5AltPage;
+ };
+
+ const Config *_config;
+
+ Palette *_palettes[13];
+ uint8 *_fadingTables[7];
+
+ const uint8 **_shapes;
+
+ uint32 _fadePalTimer;
+ int _fadePalRate;
+ int _fadePalIndex;
+
+ Screen::FontId _prevFont;
+
+ static const char *const _palFilesIntroVGA[];
+ static const char *const _palFilesIntroEGA[];
+ static const char *const _palFilesFinaleVGA[];
+ static const char *const _palFilesFinaleEGA[];
+};
+
+int DarkMoonEngine::mainMenu() {
+ int menuChoice = _menuChoiceInit;
+ _menuChoiceInit = 0;
+
+ _sound->selectAudioResourceSet(kMusicIntro);
+ _sound->loadSoundFile("INTRO");
+
+ Screen::FontId of = _screen->_currentFont;
+ int op = 0;
+ Common::SeekableReadStream *s = 0;
+
+ while (menuChoice >= 0 && !shouldQuit()) {
+ switch (menuChoice) {
+ case 0: {
+ if (_flags.platform == Common::kPlatformFMTowns) {
+ _screen->loadPalette("MENU.PAL", _screen->getPalette(0));
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->loadEoBBitmap("MENU", 0, 3, 3, 2);
+ } else {
+ s = _res->createReadStream("XENU.CPS");
+ if (s) {
+ s->read(_screen->getPalette(0).getData(), 768);
+ _screen->loadFileDataToPage(s, 3, 64000);
+ delete s;
+ } else {
+ _screen->loadBitmap("MENU.CPS", 3, 3, &_screen->getPalette(0));
+ }
+
+ if (_configRenderMode == Common::kRenderEGA)
+ _screen->loadPalette("MENU.EGA", _screen->getPalette(0));
+ }
+
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->convertPage(3, 2, 0);
+
+ of = _screen->setFont(Screen::FID_6_FNT);
+ op = _screen->setCurPage(2);
+ Common::String versionString(Common::String::format("ScummVM %s", gScummVMVersion));
+ _screen->printText(versionString.c_str(), 267 - versionString.size() * 6, _flags.platform == Common::kPlatformFMTowns ? 152 : 160, 13, 0);
+ _screen->setFont(of);
+ _screen->_curPage = op;
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->shadeRect(78, 99, 249, 141, 4);
+ _screen->updateScreen();
+ _allowImport = true;
+ menuChoice = mainMenuLoop();
+ _allowImport = false;
+ } break;
+
+ case 1:
+ // load game in progress
+ menuChoice = -1;
+ break;
+
+ case 2:
+ // create new party
+ menuChoice = -2;
+ break;
+
+ case 3:
+ // transfer party
+ menuChoice = -3;
+ break;
+
+ case 4:
+ // play intro
+ seq_playIntro();
+ menuChoice = 0;
+ break;
+
+ case 5:
+ // quit
+ menuChoice = -5;
+ break;
+ }
+ }
+
+ return shouldQuit() ? -5 : menuChoice;
+}
+
+int DarkMoonEngine::mainMenuLoop() {
+ int sel = -1;
+ do {
+ _screen->setScreenDim(6);
+ _gui->simpleMenu_setup(6, 0, _mainMenuStrings, -1, 0, 0);
+
+ while (sel == -1 && !shouldQuit())
+ sel = _gui->simpleMenu_process(6, _mainMenuStrings, 0, -1, 0);
+ } while ((sel < 0 || sel > 5) && !shouldQuit());
+
+ if (_flags.platform == Common::kPlatformFMTowns && sel == 2) {
+ townsUtilitiesMenu();
+ sel = -1;
+ }
+
+ return sel + 1;
+}
+
+void DarkMoonEngine::townsUtilitiesMenu() {
+ _screen->copyRegion(78, 99, 78, 99, 172, 43, 2, 0, Screen::CR_NO_P_CHECK);
+ int sel = -1;
+ do {
+ _gui->simpleMenu_setup(8, 0, _utilMenuStrings, -1, 0, 0);
+ while (sel == -1 && !shouldQuit())
+ sel = _gui->simpleMenu_process(8, _utilMenuStrings, 0, -1, 0);
+ if (sel == 0) {
+ _config2431 ^= true;
+ sel = -1;
+ }
+ } while ((sel < 0 || sel > 1) && !shouldQuit());
+}
+
+void DarkMoonEngine::seq_playIntro() {
+ DarkmoonSequenceHelper sq(_system, this, _screen, DarkmoonSequenceHelper::kIntro);
+
+ _screen->setCurPage(0);
+ _screen->clearCurPage();
+
+ snd_stopSound();
+
+ sq.loadScene(4, 2);
+ sq.loadScene(0, 2);
+ sq.delay(1);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSong(12);
+
+ _screen->copyRegion(0, 0, 8, 8, 304, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ sq.setPalette(9);
+ sq.fadePalette(0, 3);
+
+ _screen->setCurPage(2);
+ _screen->setClearScreenDim(17);
+ _screen->setCurPage(0);
+
+ removeInputTop();
+ sq.delay(18);
+
+ sq.animCommand(3, 18);
+ sq.animCommand(6, 18);
+ sq.animCommand(0);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 229 : 1);
+
+ sq.animCommand(_configRenderMode == Common::kRenderEGA ? 12 : 11);
+ sq.animCommand(7, 6);
+ sq.animCommand(2, 6);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 447 : 2);
+
+ sq.animCommand(_configRenderMode == Common::kRenderEGA ? 39 : 38);
+ sq.animCommand(3);
+ sq.animCommand(8);
+ sq.animCommand(1, 10);
+ sq.animCommand(0, 6);
+ sq.animCommand(2);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 670 : 3);
+
+ _screen->setClearScreenDim(17);
+ _screen->setCurPage(2);
+ _screen->setClearScreenDim(17);
+ _screen->setCurPage(0);
+
+ sq.animCommand(_configRenderMode == Common::kRenderEGA ? 41 : 40);
+ sq.animCommand(7, 18);
+
+ sq.printText(0, 16); // You were settling...
+ sq.animCommand(7, 90);
+ sq.fadeText();
+
+ sq.printText(1, 16); // Then a note was slipped to you
+ sq.animCommand(8);
+ sq.animCommand(2, 72);
+ sq.fadeText();
+
+ sq.printText(2, 16); // It was from your friend Khelben Blackstaff...
+ sq.animCommand(2);
+ sq.animCommand(6, 36);
+ sq.animCommand(3);
+ sq.fadeText();
+
+ sq.printText(3, 16); // The message was urgent.
+
+ sq.loadScene(1, 2);
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 1380 : 4);
+
+ // intro scroll
+ if (!skipFlag() && !shouldQuit()) {
+ if (_configRenderMode == Common::kRenderEGA) {
+ for (int i = 0; i < 35; i++) {
+ uint32 endtime = _system->getMillis() + 2 * _tickLength;
+ _screen->copyRegion(16, 8, 8, 8, 296, 128, 0, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(i << 3, 0, 304, 8, 8, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ if (i == 12)
+ sq.animCommand(42);
+ else if (i == 25)
+ snd_playSoundEffect(11);
+ delayUntil(endtime);
+ }
+ } else {
+ for (int i = 0; i < 280; i += 3) {
+ uint32 endtime = _system->getMillis() + _tickLength;
+ _screen->copyRegion(11, 8, 8, 8, 301, 128, 0, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(i, 0, 309, 8, 3, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ if (i == 96)
+ sq.animCommand(42);
+ delayUntil(endtime);
+ }
+ }
+ }
+
+ _screen->copyRegion(8, 8, 0, 0, 304, 128, 0, 2, Screen::CR_NO_P_CHECK);
+ sq.animCommand(4);
+ sq.fadeText();
+ sq.delay(10);
+
+ sq.loadScene(2, 2);
+ sq.update(2);
+ sq.delay(10);
+
+ sq.printText(4, 16); // What could Khelben want?
+ sq.delay(25);
+
+ sq.loadScene(3, 2);
+ sq.delay(54);
+ sq.animCommand(13);
+ _screen->copyRegion(104, 16, 96, 8, 120, 100, 0, 2, Screen::CR_NO_P_CHECK);
+ sq.fadeText();
+
+ sq.printText(5, 15); // Welcome, please come in
+ sq.animCommand(10);
+ sq.animCommand(10);
+ sq.animCommand(9);
+ sq.animCommand(9);
+ sq.fadeText();
+
+ sq.printText(6, 15); // Khelben awaits you in his study
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(10);
+ sq.animCommand(9);
+ sq.animCommand(14);
+ sq.loadScene(5, 2);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 2037 : 5);
+
+ sq.fadeText();
+ _screen->clearCurPage();
+ _screen->updateScreen();
+
+ for (int i = 0; i < 6; i++)
+ sq.animCommand(15);
+
+ if (_configRenderMode == Common::kRenderEGA && !skipFlag() && !shouldQuit()) {
+ _screen->loadPalette("INTRO.EGA", _screen->getPalette(0));
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+
+ sq.loadScene(6, 2);
+ sq.loadScene(7, 2);
+ _screen->clearCurPage();
+ sq.update(2);
+
+ sq.animCommand(16);
+ sq.printText(7, 15); // Thank you for coming so quickly
+ sq.animCommand(16);
+ sq.animCommand(17);
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(16);
+ sq.fadeText();
+ sq.animCommand(16);
+
+ sq.loadScene(8, 2);
+ sq.update(2);
+ sq.animCommand(32);
+ sq.printText(8, 15); // I am troubled my friend
+ sq.animCommand(33);
+ sq.animCommand(33);
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(32);
+ sq.fadeText();
+
+ sq.printText(9, 15); // Ancient evil stirs in the Temple Darkmoon
+ sq.animCommand(33);
+ sq.animCommand(43);
+ sq.animCommand(33);
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(32);
+ sq.fadeText();
+
+ sq.printText(10, 15); // I fear for the safety of our city
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(33);
+ sq.animCommand(32);
+ sq.animCommand(32);
+
+ sq.loadScene(9, 2);
+ sq.fadeText();
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 3000 : 6);
+
+ sq.update(2);
+ sq.animCommand(34);
+
+ sq.printText(11, 15); // I need your help
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(34);
+ sq.animCommand(35);
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(34);
+ sq.fadeText();
+
+ sq.loadScene(12, 2);
+ sq.update(2);
+ sq.loadScene(6, 2);
+ sq.animCommand(18);
+
+ sq.printText(12, 15); // Three nights ago I sent forth a scout
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(22);
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.fadeText();
+
+ sq.printText(13, 15); // She has not yet returned
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(23);
+ sq.animCommand(24);
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(17);
+ sq.animCommand(18);
+ sq.fadeText();
+
+ sq.printText(14, 15); // I fear for her safety
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.animCommand(25);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+ sq.animCommand(18);
+ sq.animCommand(18);
+
+ sq.printText(15, 15); // Take this coin
+ sq.animCommand(28);
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+
+ sq.loadScene(10, 2);
+ _screen->clearCurPage();
+ _screen->updateScreen();
+
+ sq.animCommand(37, 18);
+ sq.animCommand(36, 36);
+
+ sq.loadScene(12, 2);
+ _screen->clearCurPage();
+ sq.update(2);
+
+ sq.loadScene(11, 2);
+ sq.printText(16, 15); // I will use it to contact you
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+
+ sq.printText(17, 15); // You must act quickly
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+ sq.animCommand(18);
+
+ sq.printText(18, 15); // I will teleport you near Darkmoon
+ sq.animCommand(20);
+ sq.animCommand(27);
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+ sq.animCommand(18);
+
+ sq.printText(19, 15); // May luck be with you my friend
+ sq.animCommand(19);
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.fadeText();
+ sq.animCommand(29);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 4475 : 7);
+
+ sq.animCommand(30);
+ sq.animCommand(31);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 4825 : 8, true);
+
+ if (skipFlag() || shouldQuit()) {
+ snd_fadeOut();
+ } else {
+ _screen->setScreenDim(17);
+ _screen->clearCurDim();
+ snd_playSoundEffect(14);
+
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.fadePalette(10, 1);
+ _screen->setClearScreenDim(18);
+ sq.delay(6);
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.fadePalette(9, 1);
+ _screen->clearCurPage();
+ }
+ sq.fadePalette(9, 10);
+}
+
+void DarkMoonEngine::seq_playFinale() {
+ DarkmoonSequenceHelper sq(_system, this, _screen, DarkmoonSequenceHelper::kFinale);
+
+ _screen->setCurPage(0);
+
+ _sound->loadSoundFile(_flags.platform == Common::kPlatformFMTowns ? "FINALE" : "FINALE1");
+ snd_stopSound();
+ sq.delay(3);
+
+ _screen->clearCurPage();
+ _screen->clearPage(2);
+ _screen->updateScreen();
+
+ sq.loadScene(0, 2);
+ sq.delay(18);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSong(1);
+ sq.update(2);
+
+ sq.loadScene(1, 2);
+
+ sq.animCommand(0);
+ sq.animCommand(0);
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(2);
+ sq.animCommand(1);
+ sq.animCommand(2);
+ sq.animCommand(2);
+
+ sq.printText(0, 10); // Finally, Dran has been defeated
+ for (int i = 0; i < 7; i++)
+ sq.animCommand(2);
+ sq.fadeText();
+ sq.animCommand(2);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 475 : 1);
+
+ sq.printText(1, 10); // Suddenly, your friend Khelben appears
+ sq.animCommand(4);
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(2, 15); // Greetings, my victorious friends
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+ sq.animCommand(6);
+
+ sq.printText(3, 15); // You have defeated Dran
+ for (int i = 0; i < 5; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(4, 15); // I did not know Dran was a dragon
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(5, 15); // He must have been over 300 years old
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(6, 15); // His power is gone
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(7, 15); // But Darkmoon is still a source of great evil
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(8, 15); // And many of his minions remain
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.loadScene(2, 2);
+ sq.update(2);
+ sq.loadScene(3, 2);
+ _screen->copyRegion(8, 8, 0, 0, 304, 128, 0, 2, Screen::CR_NO_P_CHECK);
+
+ sq.printText(9, 15); // Now we must leave this place
+ sq.animCommand(7);
+ sq.animCommand(8);
+ sq.animCommand(7);
+ sq.animCommand(7, 36);
+ sq.fadeText();
+
+ sq.printText(10, 15); // So my forces can destroy it..
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(7);
+ sq.animCommand(8);
+ sq.animCommand(7);
+ sq.animCommand(7, 36);
+ sq.animCommand(8, 18);
+ sq.fadeText();
+
+ sq.printText(11, 15); // Follow me
+ sq.animCommand(7, 18);
+ sq.animCommand(9, 18);
+ sq.animCommand(8, 18);
+ sq.fadeText();
+
+ sq.loadScene(7, 2);
+
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.copyPalette(3, 0);
+
+ sq.loadScene(4, 2);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 2030 : 2);
+
+ _screen->clearCurPage();
+ sq.update(2);
+
+ sq.loadScene(8, 2);
+ sq.loadScene(6, 6);
+ sq.delay(10);
+
+ sq.printText(12, 10); // Powerful mages stand ready for the final assault...
+ sq.delay(90);
+ sq.fadeText();
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 2200 : 3);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(7);
+ sq.delay(8);
+
+ sq.animCommand(10);
+ sq.animCommand(13);
+ sq.initDelayedPaletteFade(4, 1);
+
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(14);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.initDelayedPaletteFade(2, 1);
+
+ sq.animCommand(15);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(15);
+ sq.animCommand(15);
+ sq.animCommand(11);
+
+ sq.printText(13, 10); // The temple's evil is very strong
+ sq.delay(72);
+ sq.fadeText();
+
+ sq.printText(14, 10); // It must not be allowed...
+ sq.delay(72);
+ sq.fadeText();
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 2752 : 4);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(7);
+ sq.delay(8);
+
+ sq.animCommand(10);
+ sq.initDelayedPaletteFade(5, 1);
+ sq.animCommand(13);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(13);
+ sq.animCommand(14);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(12);
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(16);
+ sq.animCommand(17);
+ sq.animCommand(18);
+
+ sq.printText(15, 10); // The temple ceases to exist
+ sq.initDelayedPaletteFade(6, 1);
+ sq.delay(36);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+
+ sq.delay(54);
+ sq.fadeText();
+ sq.loadScene(12, 2);
+
+ sq.waitForSongNotifier(_flags.platform == Common::kPlatformFMTowns ? 3475 : 5);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(6);
+
+ if (!skipFlag() && !shouldQuit()) {
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.setPaletteWithoutTextColor(0);
+ _screen->crossFadeRegion(0, 0, 8, 8, 304, 128, 2, 0);
+ }
+ sq.delay(18);
+
+ sq.printText(16, 15); // My friends, our work is done
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(19, 36);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+ sq.fadeText();
+
+ sq.printText(17, 15); // Thank you
+ sq.animCommand(19);
+ sq.animCommand(20, 36);
+ sq.fadeText();
+
+ sq.printText(18, 15); // You have earned my deepest respect
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(19);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.delay(36);
+ sq.fadeText();
+
+ sq.printText(19, 15); // We will remember you always
+ sq.animCommand(19);
+ sq.animCommand(19, 18);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.animCommand(20, 18);
+ sq.fadeText();
+
+ sq.delay(28);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+ sq.delay(3);
+
+ sq.loadScene(5, 2);
+ if (skipFlag() || shouldQuit()) {
+ _screen->copyRegion(0, 0, 8, 8, 304, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ snd_playSoundEffect(6);
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.setPaletteWithoutTextColor(0);
+ _screen->crossFadeRegion(0, 0, 8, 8, 304, 128, 2, 0);
+ }
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+ sq.delay(5);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.delay(11);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+ sq.delay(7);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.delay(12);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+
+ removeInputTop();
+ resetSkipFlag(true);
+
+ sq.loadScene(10, 2);
+ sq.loadScene(9, 2);
+
+ snd_stopSound();
+ sq.delay(3);
+
+ if (_flags.platform != Common::kPlatformFMTowns)
+ _sound->loadSoundFile("FINALE2");
+
+ sq.delay(18);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSong(_flags.platform == Common::kPlatformFMTowns ? 16 : 1);
+
+ int temp = 0;
+ const uint8 *creditsData = (_flags.platform == Common::kPlatformFMTowns) ? _res->fileData("CREDITS.TXT", 0) : _staticres->loadRawData(kEoB2CreditsData, temp);
+
+ seq_playCredits(&sq, creditsData, 18, 2, 6, 2);
+
+ if (_flags.platform == Common::kPlatformFMTowns)
+ delete[] creditsData;
+
+ sq.delay(90);
+
+ resetSkipFlag(true);
+
+ if (_configRenderMode != Common::kRenderEGA) {
+ sq.setPalette(11);
+ sq.fadePalette(9, 10);
+ }
+
+ _screen->clearCurPage();
+ sq.loadScene(11, 2);
+
+ static const uint8 finPortraitPos[] = { 0x50, 0x50, 0xD0, 0x50, 0x50, 0x90, 0xD0, 0x90, 0x90, 0x50, 0x90, 0x90 };
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (i > 3)
+ _screen->drawShape(2, sq._shapes[6 + i], finPortraitPos[i << 1] - 16, finPortraitPos[(i << 1) + 1] - 16, 0);
+ _screen->drawShape(2, _characters[i].faceShape, finPortraitPos[i << 1], finPortraitPos[(i << 1) + 1], 0);
+ }
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+
+ if (_flags.platform == Common::kPlatformFMTowns)
+ sq.copyPalette(12, 0);
+
+ sq.setPalette(9);
+ sq.fadePalette(0, 18);
+
+ while (!skipFlag() && !shouldQuit())
+ delay(_tickLength);
+
+ snd_stopSound();
+ sq.fadePalette(9, 10);
+}
+
+void DarkMoonEngine::seq_playCredits(DarkmoonSequenceHelper *sq, const uint8 *data, int sd, int backupPage, int tempPage, int speed) {
+ if (!data)
+ return;
+
+ _screen->setFont(Screen::FID_8_FNT);
+ _screen->setScreenDim(sd);
+
+ const ScreenDim *dm = _screen->_curDim;
+
+ _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, 0, backupPage, Screen::CR_NO_P_CHECK);
+
+ struct CreditsDataItem {
+ int16 x;
+ int16 y;
+ const void *data;
+ char *str;
+ uint8 crlf;
+ uint8 size;
+ uint8 dataType;
+ } items[36];
+ memset(items, 0, sizeof(items));
+
+ const char *pos = (const char *)data;
+ uint32 end = _system->getMillis();
+ uint32 cur = 0;
+ int i = 0;
+
+ do {
+ for (bool loop = true; loop;) {
+ sq->processDelayedPaletteFade();
+ cur = _system->getMillis();
+ if (end <= cur)
+ break;
+ delay(MIN<uint32>(_tickLength, end - cur));
+ }
+
+ end = _system->getMillis() + speed * _tickLength;
+
+ for (; i < 35 && *pos; i++) {
+ int16 nextY = i ? items[i].y + items[i].size + (items[i].size >> 2) : dm->h;
+
+ const char *posOld = pos;
+ pos = strchr(pos, 0x0D);
+ if (!pos)
+ pos = strchr(posOld, 0x00);
+
+ items[i + 1].crlf = *pos++;
+
+ if (*posOld == 2) {
+ const uint8 *shp = sq->_shapes[(*++posOld) - 1];
+ items[i + 1].data = shp;
+ items[i + 1].size = shp[1];
+ items[i + 1].x = (dm->w - shp[2]) << 2;
+ items[i + 1].dataType = 1;
+ delete[] items[i + 1].str;
+ items[i + 1].str = 0;
+
+ } else {
+ if (*posOld == 1) {
+ posOld++;
+ items[i + 1].size = 6;
+ } else {
+ items[i + 1].size = _screen->getFontWidth();
+ }
+
+ items[i + 1].dataType = 0;
+
+ int l = pos - posOld;
+ if (items[i + 1].crlf != 0x0D)
+ l++;
+
+ delete[] items[i + 1].str;
+ items[i + 1].str = new char[l];
+ memcpy(items[i + 1].str, posOld, l);
+ items[i + 1].str[l - 1] = 0;
+ items[i + 1].data = 0;
+ items[i + 1].x = (((dm->w << 3) - (strlen(items[i + 1].str) * items[i + 1].size)) >> 1) + 1;
+ }
+
+ items[i + 1].y = nextY;
+ }
+
+ _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, backupPage, tempPage, Screen::CR_NO_P_CHECK);
+
+ for (int h = 0; h < i; h++) {
+ if (items[h + 1].y < dm->h) {
+ if (items[h + 1].dataType == 1) {
+ _screen->drawShape(tempPage, (const uint8 *)items[h + 1].data, items[h + 1].x, items[h + 1].y, sd);
+ } else {
+ _screen->setCurPage(tempPage);
+
+ if (items[h + 1].size == 6)
+ _screen->setFont(Screen::FID_6_FNT);
+
+ _screen->printText(items[h + 1].str, (dm->sx << 3) + items[h + 1].x - 1, dm->sy + items[h + 1].y + 1, 12, 0);
+ _screen->printText(items[h + 1].str, (dm->sx << 3) + items[h + 1].x, dm->sy + items[h + 1].y, 240, 0);
+
+ if (items[h + 1].size == 6)
+ _screen->setFont(Screen::FID_8_FNT);
+
+ _screen->setCurPage(0);
+ }
+ }
+
+ items[h + 1].y -= 2;
+ }
+
+ _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, tempPage, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ if (-items[1].size > items[1].y) {
+ delete[] items[1].str;
+ --i;
+ for (int t = 1; t <= i; t++)
+ memcpy(&items[t], &items[t + 1], sizeof(CreditsDataItem));
+ items[i + 1].str = 0;
+ }
+
+ if (i < 35 && ((items[i].y + items[i].size) < (dm->sy + dm->h))) {
+ resetSkipFlag(true);
+ break;
+ }
+
+ sq->processDelayedPaletteFade();
+ } while (!skipFlag() && i && !shouldQuit());
+
+ for (i = 0; i < 35; i++)
+ delete[] items[i].str;
+}
+
+DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, Mode mode) :
+ _system(system), _vm(vm), _screen(screen) {
+
+ int size = 0;
+
+ if (mode == kIntro) {
+ _config = new Config(
+ _vm->staticres()->loadStrings(kEoB2IntroStrings, size),
+ _vm->staticres()->loadStrings(kEoB2IntroCPSFiles, size),
+ new const uint8*[13],
+ _vm->_configRenderMode == Common::kRenderEGA ? _palFilesIntroEGA : _palFilesIntroVGA,
+ new const DarkMoonShapeDef*[13],
+ new const DarkMoonAnimCommand *[44],
+ false,
+ false,
+ true,
+ true,
+ 0,
+ 0,
+ false,
+ 2
+ );
+
+ for (int i = 0; i < 44; i++)
+ _config->animData[i] = _vm->staticres()->loadEoB2SeqData(kEoB2IntroAnimData00 + i, size);
+
+ for (int i = 0; i < 13; i++)
+ _config->cpsData[i] = _vm->staticres()->loadRawData(kEoB2IntroCpsDataStreet1 + i, size);
+
+ memset(_config->shapeDefs, 0, 13 * sizeof(DarkMoonShapeDef*));
+ _config->shapeDefs[0] = _vm->staticres()->loadEoB2ShapeData(kEoB2IntroShapes00, size);
+ _config->shapeDefs[1] = _vm->staticres()->loadEoB2ShapeData(kEoB2IntroShapes01, size);
+ _config->shapeDefs[4] = _vm->staticres()->loadEoB2ShapeData(kEoB2IntroShapes04, size);
+ _config->shapeDefs[7] = _vm->staticres()->loadEoB2ShapeData(kEoB2IntroShapes07, size);
+
+ } else {
+ _config = new Config(
+ _vm->staticres()->loadStrings(kEoB2FinaleStrings, size),
+ _vm->staticres()->loadStrings(kEoB2FinaleCPSFiles, size),
+ new const uint8*[13],
+ _vm->_configRenderMode == Common::kRenderEGA ? _palFilesFinaleEGA : _palFilesFinaleVGA,
+ new const DarkMoonShapeDef*[13],
+ new const DarkMoonAnimCommand *[21],
+ true,
+ true,
+ false,
+ false,
+ 1,
+ 18,
+ true,
+ 6
+ );
+
+ for (int i = 0; i < 21; i++)
+ _config->animData[i] = _vm->staticres()->loadEoB2SeqData(kEoB2FinaleAnimData00 + i, size);
+
+ for (int i = 0; i < 13; i++)
+ _config->cpsData[i] = _vm->staticres()->loadRawData(kEoB2FinaleCpsDataDragon1 + i, size);
+
+ memset(_config->shapeDefs, 0, 13 * sizeof(DarkMoonShapeDef*));
+ _config->shapeDefs[0] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes00, size);
+ _config->shapeDefs[3] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes03, size);
+ _config->shapeDefs[7] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes07, size);
+ _config->shapeDefs[9] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes09, size);
+ _config->shapeDefs[10] = _vm->staticres()->loadEoB2ShapeData(kEoB2FinaleShapes10, size);
+ }
+
+ _screen->enableHiColorMode(false);
+
+ for (int i = 0; _config->palFiles[i]; i++) {
+ if (i < 4)
+ _palettes[i] = &_screen->getPalette(i);
+ else
+ _palettes[i] = new Palette(256);
+ _screen->loadPalette(_config->palFiles[i], *_palettes[i]);
+ }
+
+ for (int i = 9; i < 13; ++i)
+ _palettes[i] = new Palette(256);
+
+ _palettes[9]->fill(0, 256, 0);
+ _palettes[10]->fill(0, 256, 63);
+ _palettes[11]->fill(0, 256, 0);
+
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns)
+ _screen->loadPalette("PALETTE.COL", *_palettes[12]);
+
+ for (int i = 0; i < 7; i++)
+ _fadingTables[i] = 0;
+
+ uint8 *fadeData = (_vm->_configRenderMode != Common::kRenderCGA && _vm->_configRenderMode != Common::kRenderEGA) ? _vm->resource()->fileData("FADING.DAT", 0) : 0;
+
+ if (fadeData) {
+ for (int i = 0; i < 7; i++) {
+ _fadingTables[i] = new uint8[256];
+ memcpy(_fadingTables[i], fadeData + (i << 8), 256);
+ }
+ } else {
+ if (_vm->_configRenderMode != Common::kRenderCGA && _vm->_configRenderMode != Common::kRenderEGA) {
+ uint8 *pal = _vm->resource()->fileData("PALETTE1.PAL", 0);
+ for (int i = 0; i < 7; i++)
+ _screen->createFadeTable(pal, _fadingTables[i], 18, (i + 1) * 36);
+ delete[] pal;
+ }
+ }
+
+ delete[] fadeData;
+
+ _shapes = new const uint8*[30];
+ memset(_shapes, 0, 30 * sizeof(uint8 *));
+
+ _fadePalTimer = 0;
+ _fadePalRate = 0;
+
+ _screen->setScreenPalette(*_palettes[0]);
+ _prevFont = _screen->setFont(_vm->gameFlags().platform == Common::kPlatformFMTowns ? Screen::FID_SJIS_LARGE_FNT : Screen::FID_8_FNT);
+ _screen->hideMouse();
+
+ _vm->delay(150);
+ _vm->_eventList.clear();
+ _vm->_allowSkip = true;
+}
+
+DarkmoonSequenceHelper::~DarkmoonSequenceHelper() {
+ for (int i = 4; _config->palFiles[i]; i++)
+ delete _palettes[i];
+ for (int i = 9; i < 13; ++i)
+ delete _palettes[i];
+
+ for (int i = 0; i < 7; i++)
+ delete[] _fadingTables[i];
+
+ for (int i = 0; i < 30; i++)
+ delete[] _shapes[i];
+ delete[] _shapes;
+
+ delete[] _config->animData;
+ delete[] _config->shapeDefs;
+ delete[] _config->cpsData;
+ delete _config;
+
+ _screen->enableHiColorMode(true);
+ _screen->clearCurPage();
+ _screen->setFont(_prevFont);
+ _screen->showMouse();
+ _screen->updateScreen();
+
+ _system->delayMillis(150);
+ _vm->resetSkipFlag(true);
+ _vm->_allowSkip = false;
+}
+
+void DarkmoonSequenceHelper::loadScene(int index, int pageNum) {
+ char file[13] = "";
+ Common::SeekableReadStream *s = 0;
+ uint32 chunkID = 0;
+
+ if (_config->cpsFiles) {
+ strcpy(file, _config->cpsFiles[index]);
+ s = _vm->resource()->createReadStream(file);
+ }
+
+ if (s) {
+ chunkID = s->readUint32LE();
+ s->seek(0);
+ }
+
+ if (_config->cpsData[index]) {
+ _screen->decodeSHP(_config->cpsData[index], pageNum);
+ } else if (s && chunkID == MKTAG('F', 'O', 'R', 'M')) {
+ // The original code also handles files with FORM chunks and ILBM and PBM sub chunks. This will probably be necessary for Amiga versions.
+ // The DOS versions do not need this, but still have the code for it. We error out for now.
+ error("DarkmoonSequenceHelper::loadScene(): CPS file loading failure in scene %d - unhandled FORM chunk encountered", index);
+ } else if (s && file[0] != 'X') {
+ delete s;
+ _screen->loadBitmap(_config->cpsFiles[index], pageNum | 1, pageNum | 1, _palettes[0]);
+ } else {
+ if (!s) {
+ file[0] = 'X';
+ s = _vm->resource()->createReadStream(file);
+ }
+
+ if (!s)
+ error("DarkmoonSequenceHelper::loadScene(): CPS file loading failure in scene %d", index);
+
+ if (_config->loadScenePal)
+ s->read(_palettes[0]->getData(), 768);
+ else
+ s->seek(768);
+ _screen->loadFileDataToPage(s, 3, 64000);
+ delete s;
+ }
+
+ int cp = _screen->setCurPage(pageNum);
+
+ if (_config->shapeDefs[index]) {
+ for (const DarkMoonShapeDef *df = _config->shapeDefs[index]; df->w; df++) {
+ uint16 shapeIndex = (df->index < 0) ? df->index * -1 : df->index;
+ if (_shapes[shapeIndex])
+ delete[] _shapes[shapeIndex];
+ _shapes[shapeIndex] = _screen->encodeShape(df->x, df->y, df->w, df->h, (df->index >> 8) != 0);
+ }
+ }
+
+ _screen->setCurPage(cp);
+
+ if (_vm->_configRenderMode == Common::kRenderEGA)
+ setPalette(0);
+
+ _screen->convertPage(pageNum | 1, pageNum, 0);
+
+ if ((pageNum == 0 || pageNum == 1) && !_vm->skipFlag() && !_vm->shouldQuit())
+ _screen->updateScreen();
+}
+
+void DarkmoonSequenceHelper::animCommand(int index, int del) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ uint32 end = 0;
+
+ for (const DarkMoonAnimCommand *s = _config->animData[index]; s->command != 0xFF && !_vm->skipFlag() && !_vm->shouldQuit(); s++) {
+ int palIndex = s->pal + _config->animPalOffs;
+ int x = s->x1;
+ if (x >= Screen::SCREEN_W)
+ x >>= 1;
+ int y = s->y1;
+ int x2 = 0;
+ uint16 shapeW = 0;
+ uint16 shapeH = 0;
+
+ switch (s->command) {
+ case 0:
+ // flash palette
+ if (_vm->_configRenderMode != Common::kRenderEGA && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ delay(s->delay);
+ if (_vm->_configRenderMode != Common::kRenderEGA && _config->animCmdRestorePal && s->pal)
+ setPaletteWithoutTextColor(0);
+ break;
+
+ case 1:
+ // draw shape, then restore background
+ shapeW = _shapes[s->obj][2];
+ shapeH = _shapes[s->obj][3];
+
+ if (_config->animCmd1ShapeFrame == 18) {
+ _screen->setScreenDim(18);
+ x -= (_screen->_curDim->sx << 3);
+ y -= _screen->_curDim->sy;
+ if (x < 0)
+ shapeW -= ((-x >> 3) + 1);
+ else
+ x2 = x;
+ }
+
+ _screen->drawShape(0, _shapes[s->obj], x, y, _config->animCmd1ShapeFrame);
+
+ if (_vm->_configRenderMode != Common::kRenderEGA && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ else
+ _screen->updateScreen();
+
+ delay(s->delay);
+
+ if (_config->animCmd1ShapeFrame == 0) {
+ if (_vm->_configRenderMode != Common::kRenderEGA && s->pal)
+ setPaletteWithoutTextColor(0);
+ _screen->copyRegion(x - 8, y - 8, x, y, (shapeW + 1) << 3, shapeH, 2, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ _screen->copyRegion(x2, y, x2 + (_screen->_curDim->sx << 3), y + _screen->_curDim->sy, (shapeW + 1) << 3, shapeH, 2, 0, Screen::CR_NO_P_CHECK);
+ }
+
+ _screen->updateScreen();
+ break;
+
+ case 2:
+ // draw shape
+ _screen->drawShape(_screen->_curPage, _shapes[s->obj], x, y, 0);
+
+ if (_vm->_configRenderMode != Common::kRenderEGA && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ else if (!_screen->_curPage)
+ _screen->updateScreen();
+
+ delay(s->delay);
+
+ if (_vm->_configRenderMode != Common::kRenderEGA && _config->animCmdRestorePal && s->pal)
+ setPaletteWithoutTextColor(0);
+ break;
+
+ case 3:
+ case 4:
+ // fade shape in or out or restore background
+ if (!_config->shpBackgroundFading)
+ break;
+
+ if (_vm->_configRenderMode == Common::kRenderEGA) {
+ if (palIndex)
+ _screen->drawShape(0, _shapes[s->obj], s->x1, y, 0);
+ else
+ _screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ delay(s->delay /** 7*/);
+ } else {
+ _screen->enableShapeBackgroundFading(true);
+ _screen->setShapeFadingLevel(1);
+
+ end = _system->getMillis() + s->delay * _vm->tickLength();
+
+ if (palIndex) {
+ _screen->setFadeTable(_fadingTables[palIndex - 1]);
+
+ _screen->copyRegion(s->x1 - 8, s->y1 - 8, 0, 0, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 4, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(4, _shapes[s->obj], s->x1 & 7, 0, 0);
+ _screen->copyRegion(0, 0, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 4, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ _screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 0, Screen::CR_NO_P_CHECK);
+ }
+ _screen->updateScreen();
+
+ _vm->delayUntil(end);
+ _screen->enableShapeBackgroundFading(false);
+ _screen->setShapeFadingLevel(0);
+ }
+ break;
+
+ case 5:
+ // copy region
+ if (_config->animCmd5SetPal && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+
+ _screen->copyRegion(s->x2 << 3, s->y2, s->x1, s->y1, s->w << 3, s->h, s->obj ? _config->animCmd5AltPage : 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ delay(s->delay);
+ break;
+
+ case 6:
+ // play sound effect
+ if (s->obj != 0xFF)
+ _vm->snd_playSoundEffect(s->obj);
+ break;
+
+ case 7:
+ // restore background (only used in EGA mode)
+ delay(s->delay);
+ _screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ break;
+
+ default:
+ error("DarkmoonSequenceHelper::animCommand(): Unknown animation opcode encountered.");
+ break;
+ }
+ }
+
+ if (del > 0)
+ delay(del);
+}
+
+void DarkmoonSequenceHelper::printText(int index, int color) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ _screen->setClearScreenDim(17);
+ uint8 col1 = 15;
+
+ if (_vm->_configRenderMode != Common::kRenderEGA) {
+ _palettes[0]->copy(*_palettes[0], color, 1, 255);
+ setPalette(0);
+ col1 = 255;
+ }
+
+ char *temp = new char[strlen(_config->strings[index]) + 1];
+ char *str = temp;
+ strcpy(str, _config->strings[index]);
+
+ const ScreenDim *dm = _screen->_curDim;
+ int fontHeight = _screen->getFontHeight() + 1;
+
+ for (int yOffs = 0; *str; yOffs += fontHeight) {
+ char *cr = strchr(str, 13);
+
+ if (cr)
+ *cr = 0;
+
+ uint32 len = strlen(str);
+ _screen->printText(str, (dm->sx + ((dm->w - len) >> 1)) << 3, dm->sy + yOffs, col1, dm->unkA);
+
+ if (cr) {
+ *cr = 13;
+ str = cr + 1;
+ } else {
+ str += len;
+ }
+ }
+
+ delete[] temp;
+ _screen->updateScreen();
+}
+
+void DarkmoonSequenceHelper::fadeText() {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+ if (_vm->_configRenderMode != Common::kRenderEGA)
+ _screen->fadeTextColor(_palettes[0], 255, 8);
+ _screen->clearCurDim();
+}
+
+void DarkmoonSequenceHelper::update(int srcPage) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ _screen->copyRegion(0, 0, 8, 8, 304, 128, srcPage, 0, Screen::CR_NO_P_CHECK);
+
+ if (_vm->_configRenderMode != Common::kRenderEGA)
+ setPaletteWithoutTextColor(0);
+}
+
+void DarkmoonSequenceHelper::setPaletteWithoutTextColor(int index) {
+ if (_vm->_configRenderMode == Common::kRenderEGA || _vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ if (!memcmp(_palettes[11]->getData(), _palettes[index]->getData(), 765))
+ return;
+
+ _palettes[11]->copy(*_palettes[index], 0, 255);
+ _palettes[11]->copy(*_palettes[0], 255, 1, 255);
+ setPalette(11);
+
+ _screen->updateScreen();
+ _system->delayMillis(10);
+}
+
+void DarkmoonSequenceHelper::setPalette(int index) {
+ _screen->setScreenPalette(*_palettes[index]);
+}
+
+void DarkmoonSequenceHelper::fadePalette(int index, int del) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+ if (_vm->_configRenderMode == Common::kRenderEGA) {
+ setPalette(index);
+ _screen->updateScreen();
+ } else {
+ _screen->fadePalette(*_palettes[index], del * _vm->tickLength());
+ }
+}
+
+void DarkmoonSequenceHelper::copyPalette(int srcIndex, int destIndex) {
+ _palettes[destIndex]->copy(*_palettes[srcIndex]);
+}
+
+void DarkmoonSequenceHelper::initDelayedPaletteFade(int palIndex, int rate) {
+ _palettes[11]->copy(*_palettes[0]);
+
+ _fadePalIndex = palIndex;
+ _fadePalRate = rate;
+ _fadePalTimer = _system->getMillis() + 2 * _vm->_tickLength;
+}
+
+bool DarkmoonSequenceHelper::processDelayedPaletteFade() {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return true;
+
+ if (_vm->_configRenderMode == Common::kRenderEGA || !_fadePalRate || (_system->getMillis() <= _fadePalTimer))
+ return false;
+
+ if (_screen->delayedFadePalStep(_palettes[_fadePalIndex], _palettes[0], _fadePalRate)) {
+ setPaletteWithoutTextColor(0);
+ _fadePalTimer = _system->getMillis() + 3 * _vm->_tickLength;
+ } else {
+ _fadePalRate = 0;
+ }
+
+ return false;
+}
+
+void DarkmoonSequenceHelper::delay(uint32 ticks) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ uint32 end = _system->getMillis() + ticks * _vm->_tickLength;
+
+ if (_config->palFading) {
+ do {
+ if (processDelayedPaletteFade())
+ break;
+ _vm->updateInput();
+ } while (end > _system->getMillis());
+ processDelayedPaletteFade();
+
+ } else {
+ _vm->delayUntil(end);
+ }
+}
+
+void DarkmoonSequenceHelper::waitForSongNotifier(int index, bool introUpdateAnim) {
+ int seq = 0;
+ while (_vm->sound()->checkTrigger() < index && !(_vm->skipFlag() || _vm->shouldQuit())) {
+ if (introUpdateAnim) {
+ animCommand(30 | seq);
+ seq ^= 1;
+ }
+
+ if (_config->palFading)
+ processDelayedPaletteFade();
+
+ _vm->updateInput();
+ }
+}
+
+const char *const DarkmoonSequenceHelper::_palFilesIntroVGA[] = {
+ "PALETTE1.PAL",
+ "PALETTE3.PAL",
+ "PALETTE2.PAL",
+ "PALETTE4.PAL",
+ 0
+};
+
+const char *const DarkmoonSequenceHelper::_palFilesIntroEGA[] = {
+ "PALETTE0.PAL",
+ "PALETTE3.PAL",
+ "PALETTE2.PAL",
+ "PALETTE4.PAL",
+ 0
+};
+
+const char *const DarkmoonSequenceHelper::_palFilesFinaleVGA[] = {
+ "FINALE_0.PAL",
+ "FINALE_0.PAL",
+ "FINALE_1.PAL",
+ "FINALE_2.PAL",
+ "FINALE_3.PAL",
+ "FINALE_4.PAL",
+ "FINALE_5.PAL",
+ "FINALE_6.PAL",
+ "FINALE_7.PAL",
+ 0
+};
+
+const char *const DarkmoonSequenceHelper::_palFilesFinaleEGA[] = {
+ "FINALE_0.PAL",
+ "FINALE_0.PAL",
+ "FINALE_1.PAL",
+ "FINALE_2.PAL",
+ "FINALE_3.PAL",
+ "FINALE_4.PAL",
+ "FINALE_5.PAL",
+ "FINALE_0.PAL",
+ "FINALE_0.PAL",
+ 0
+};
+
+void DarkMoonEngine::seq_nightmare() {
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+ if (_flags.lang == Common::JA_JPN)
+ _screen->clearCurDim();
+ _screen->copyRegion(0, 0, 0, 120, 176, 24, 12, 2, Screen::CR_NO_P_CHECK);
+
+ initDialogueSequence();
+ gui_drawDialogueBox();
+
+ _txt->printDialogueText(99, 0);
+ snd_playSoundEffect(54);
+
+ static const uint8 seqX[] = { 0, 20, 0, 20 };
+ static const uint8 seqY[] = { 0, 0, 96, 96 };
+ static const uint8 seqDelay[] = { 12, 7, 7, 12 };
+
+ for (const int8 *i = _dreamSteps; *i != -1; ++i) {
+ drawSequenceBitmap("DREAM", 0, seqX[*i], seqY[*i], 0);
+ delay(seqDelay[*i] * _tickLength);
+ }
+
+ _txt->printDialogueText(20, _okStrings[0]);
+
+ restoreAfterDialogueSequence();
+
+ _screen->setFont(of);
+}
+
+void DarkMoonEngine::seq_kheldran() {
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+
+ initDialogueSequence();
+ gui_drawDialogueBox();
+
+ static const char file[] = "KHELDRAN";
+ _screen->set16bitShadingLevel(4);
+ _txt->printDialogueText(_kheldranStrings[0]);
+ drawSequenceBitmap(file, 0, 0, 0, 0);
+ _txt->printDialogueText(20, _moreStrings[0]);
+ snd_playSoundEffect(56);
+ drawSequenceBitmap(file, 0, 20, 0, 0);
+ delay(10 * _tickLength);
+ drawSequenceBitmap(file, 0, 0, 96, 0);
+ delay(10 * _tickLength);
+ drawSequenceBitmap(file, 0, 20, 96, 0);
+ delay(7 * _tickLength);
+ _txt->printDialogueText(76, _okStrings[0]);
+
+ restoreAfterDialogueSequence();
+
+ _screen->setFont(of);
+}
+
+void DarkMoonEngine::seq_dranDragonTransformation() {
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+
+ initDialogueSequence();
+ gui_drawDialogueBox();
+
+ static const char file[] = "DRANX";
+ drawSequenceBitmap(file, 0, 0, 0, 0);
+ _txt->printDialogueText(120, _moreStrings[0]);
+ snd_playSoundEffect(56);
+ drawSequenceBitmap(file, 0, 20, 0, 0);
+ delay(7 * _tickLength);
+ drawSequenceBitmap(file, 0, 0, 96, 0);
+ delay(7 * _tickLength);
+ drawSequenceBitmap(file, 0, 20, 96, 0);
+ delay(18 * _tickLength);
+
+ restoreAfterDialogueSequence();
+
+ _screen->setFont(of);
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/sequence/sequences_eob.cpp b/engines/kyra/sequence/sequences_eob.cpp
new file mode 100644
index 0000000000..a04c5f75cd
--- /dev/null
+++ b/engines/kyra/sequence/sequences_eob.cpp
@@ -0,0 +1,1152 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/engine/eob.h"
+#include "kyra/graphics/screen_eob.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+
+#include "common/system.h"
+
+#include "base/version.h"
+
+namespace Kyra {
+
+class EoBIntroPlayer {
+public:
+ EoBIntroPlayer(EoBEngine *vm, Screen_EoB *screen);
+ ~EoBIntroPlayer() {}
+
+ void start();
+
+private:
+ void openingCredits();
+ void tower();
+ void orb();
+ void waterdeepEntry();
+ void king();
+ void hands();
+ void waterdeepExit();
+ void tunnel();
+
+ void loadAndSetPalette(const char *filename);
+ void copyBlurRegion(int x1, int y1, int x2, int y2, int w, int h, int step);
+ void boxMorphTransition(int targetDestX, int targetDestY, int targetFinalX, int targetFinalY, int targetSrcX, int targetSrcY, int targetFinalW, int targetFinalH, int originX1, int originY1, int originW, int originH);
+ void whirlTransition();
+
+ EoBEngine *_vm;
+ Screen_EoB *_screen;
+
+ const char *const *_filesOpening;
+ const char *const *_filesTower;
+ const char *const *_filesOrb;
+ const char *const *_filesWdEntry;
+ const char *const *_filesKing;
+ const char *const *_filesHands;
+ const char *const *_filesWdExit;
+ const char *const *_filesTunnel;
+ const uint8 *_openingFrmDelay;
+ const uint8 *_wdEncodeX;
+ const uint8 *_wdEncodeY;
+ const uint8 *_wdEncodeWH;
+ const uint16 *_wdDsX;
+ const uint8 *_wdDsY;
+ const uint8 *_tvlX1;
+ const uint8 *_tvlY1;
+ const uint8 *_tvlX2;
+ const uint8 *_tvlY2;
+ const uint8 *_tvlW;
+ const uint8 *_tvlH;
+};
+
+EoBIntroPlayer::EoBIntroPlayer(EoBEngine *vm, Screen_EoB *screen) : _vm(vm), _screen(screen) {
+ int temp = 0;
+ _filesOpening = _vm->staticres()->loadStrings(kEoB1IntroFilesOpening, temp);
+ _filesTower = _vm->staticres()->loadStrings(kEoB1IntroFilesTower, temp);
+ _filesOrb = _vm->staticres()->loadStrings(kEoB1IntroFilesOrb, temp);
+ _filesWdEntry = _vm->staticres()->loadStrings(kEoB1IntroFilesWdEntry, temp);
+ _filesKing = _vm->staticres()->loadStrings(kEoB1IntroFilesKing, temp);
+ _filesHands = _vm->staticres()->loadStrings(kEoB1IntroFilesHands, temp);
+ _filesWdExit = _vm->staticres()->loadStrings(kEoB1IntroFilesWdExit, temp);
+ _filesTunnel = _vm->staticres()->loadStrings(kEoB1IntroFilesTunnel, temp);
+ _openingFrmDelay = _vm->staticres()->loadRawData(kEoB1IntroOpeningFrmDelay, temp);
+ _wdEncodeX = _vm->staticres()->loadRawData(kEoB1IntroWdEncodeX, temp);
+ _wdEncodeY = _vm->staticres()->loadRawData(kEoB1IntroWdEncodeY, temp);
+ _wdEncodeWH = _vm->staticres()->loadRawData(kEoB1IntroWdEncodeWH, temp);
+ _wdDsX = _vm->staticres()->loadRawDataBe16(kEoB1IntroWdDsX, temp);
+ _wdDsY = _vm->staticres()->loadRawData(kEoB1IntroWdDsY, temp);
+ _tvlX1 = _vm->staticres()->loadRawData(kEoB1IntroTvlX1, temp);
+ _tvlY1 = _vm->staticres()->loadRawData(kEoB1IntroTvlY1, temp);
+ _tvlX2 = _vm->staticres()->loadRawData(kEoB1IntroTvlX2, temp);
+ _tvlY2 = _vm->staticres()->loadRawData(kEoB1IntroTvlY2, temp);
+ _tvlW = _vm->staticres()->loadRawData(kEoB1IntroTvlW, temp);
+ _tvlH = _vm->staticres()->loadRawData(kEoB1IntroTvlH, temp);
+}
+
+void EoBIntroPlayer::start() {
+ _vm->_allowSkip = true;
+ openingCredits();
+
+ if (!_vm->shouldQuit() && !_vm->skipFlag()) {
+ _vm->snd_playSong(2);
+ _screen->loadBitmap((_vm->_configRenderMode == Common::kRenderCGA || _vm->_configRenderMode == Common::kRenderEGA) ? "TITLE-E.CMP" : "TITLE-V.CMP", 3, 5, 0);
+ _screen->convertPage(5, 2, _vm->_cgaMappingDefault);
+ _screen->crossFadeRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _vm->delay(120 * _vm->_tickLength);
+ }
+
+ Common::SeekableReadStream *s = _vm->resource()->createReadStream("TEXT.RAW");
+ if (s) {
+ s->seek(768);
+ _screen->loadFileDataToPage(s, 5, s->size() - 768);
+ delete s;
+ } else {
+ _screen->loadBitmap("TEXT.CMP", 3, 5, 0);
+ }
+ _screen->convertPage(5, 6, _vm->_cgaMappingAlt);
+
+ tower();
+ orb();
+ waterdeepEntry();
+ king();
+ hands();
+ waterdeepExit();
+ tunnel();
+
+ whirlTransition();
+ _vm->snd_stopSound();
+ _vm->_allowSkip = false;
+}
+
+void EoBIntroPlayer::openingCredits() {
+ loadAndSetPalette(_filesOpening[5]);
+
+ _screen->loadBitmap(_filesOpening[4], 5, 3, 0);
+ _screen->convertPage(3, 0, _vm->_cgaMappingAlt);
+ _screen->updateScreen();
+
+ _vm->snd_playSong(1);
+ _vm->delay(_openingFrmDelay[0] * _vm->_tickLength);
+
+ for (int i = 0; i < 4 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ _screen->loadBitmap(_filesOpening[i], 5, 3, 0);
+ uint32 nextFrameTimer = _vm->_system->getMillis() + _openingFrmDelay[i + 1] * _vm->_tickLength;
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->crossFadeRegion(0, 50, 0, 50, 320, 102, 4, 0);
+ _vm->delayUntil(nextFrameTimer);
+ }
+}
+
+void EoBIntroPlayer::tower() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ _screen->loadBitmap(_filesTower[1], 5, 3, 0);
+ _screen->setCurPage(2);
+ uint8 *shp = _screen->encodeShape(0, 0, 16, 56, true, _vm->_cgaMappingAlt);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->clearCurPage();
+
+ for (int i = 0; i < 200; i += 64)
+ _screen->copyRegion(128, 104, 96, i, 128, 64, 4, 2, Screen::CR_NO_P_CHECK);
+
+ _screen->fillRect(0, 184, 319, 199, 12);
+ int cp = _screen->setCurPage(0);
+ whirlTransition();
+ loadAndSetPalette(_filesTower[0]);
+
+ _screen->setCurPage(cp);
+ _screen->clearCurPage();
+
+ for (int i = 0; i < 200; i += 64)
+ _screen->copyRegion(128, 104, 0, i, 128, 64, 4, 2, Screen::CR_NO_P_CHECK);
+
+ _screen->setCurPage(0);
+
+ for (int i = 0; i < 64 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 2) {
+ uint32 end = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ _screen->copyRegion(0, 142 - i, 96, 0, 128, i + 1, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 96, i + 1, 128, 167 - i, 2, 0, Screen::CR_NO_P_CHECK);
+ if (!i)
+ _screen->copyRegion(0, 0, 0, 168, 320, 32, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 0; i < 24 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 2) {
+ uint32 end = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ _screen->copyRegion(0, 79 - i, 96, 0, 24, 65 + i, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(104, 79 - i, 200, 0, 24, 65 + i, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(24, 110, 120, i + 31, 80, 34, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(152, 0, 120, 32, 80, i + 1, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 96, 65 + i, 128, 103 - i, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 0; i < 56 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 2) {
+ uint32 end = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ _screen->copyRegion(0, 56, 96, i, 24, 54, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(104, 56, 200, i, 24, 54, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 110, 96, 54 + i, 128, 34, 4, 0, Screen::CR_NO_P_CHECK);
+
+ if (i < 32) {
+ _screen->fillRect(128, 0, 255, i + 1, 12, 2);
+ _screen->copyRegion(152, 0, 120, 32, 80, i + 25, 4, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ _screen->fillRect(128, 0, 255, i + 1, 12, 2);
+ _screen->copyRegion(152, i + 1, 120, 32 + i + 1, 80, 23, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(152, 0, 152, 32, 80, i + 1, 4, 2, Screen::CR_NO_P_CHECK);
+ }
+
+ _screen->drawShape(2, shp, 128, i - 55, 0);
+ _screen->copyRegion(128, 0, 96, 0, 128, i + 1, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 96, i + 89, 128, 79 - i, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 32, 0, 168, 320, 32, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(65 * _vm->_tickLength);
+ delete[] shp;
+}
+
+void EoBIntroPlayer::orb() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ uint8 *shp[5];
+ _screen->loadBitmap(_filesOrb[0], 5, 3, 0);
+ _screen->setCurPage(2);
+ shp[4] = _screen->encodeShape(0, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ _screen->loadBitmap(_filesOrb[1], 5, 3, 0);
+ shp[3] = _screen->encodeShape(16, 0, 16, 104, true, _vm->_cgaMappingAlt);
+
+ _screen->fillRect(0, 0, 127, 103, 12);
+ for (int i = 1; i < 4; i++) {
+ copyBlurRegion(128, 0, 0, 0, 128, 104, i);
+ shp[3 - i] = _screen->encodeShape(0, 0, 16, 104, true, _vm->_cgaMappingAlt);
+ }
+
+ _screen->fillRect(0, 0, 159, 135, 12);
+ _screen->setCurPage(0);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->clearCurPage();
+
+ _vm->snd_playSoundEffect(6);
+
+ for (int i = -1; i < 4 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ if (i >= 0)
+ _screen->drawShape(2, shp[i], 16, 16, 0);
+ _screen->drawShape(2, shp[4], 0, 0, 0);
+ _screen->copyRegion(0, 0, 80, 24, 160, 136, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 64, 0, 168, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(40 * _vm->_tickLength);
+
+ _vm->snd_playSoundEffect(6);
+
+ for (int i = 3; i > -2 && !_vm->shouldQuit() && !_vm->skipFlag(); i--) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ _screen->fillRect(16, 16, 143, 119, 12, 2);
+ if (i >= 0)
+ _screen->drawShape(2, shp[i], 16, 16, 0);
+ _screen->drawShape(2, shp[4], 0, 0, 0);
+ _screen->copyRegion(0, 0, 80, 24, 160, 136, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->delay(40 * _vm->_tickLength);
+
+ for (int i = 0; i < 5; i++)
+ delete[] shp[i];
+}
+
+void EoBIntroPlayer::waterdeepEntry() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ uint8 *shp[4];
+ uint8 *shp2[31];
+ uint8 *shp3[3];
+
+ loadAndSetPalette(_filesWdEntry[0]);
+ _screen->loadBitmap(_filesWdEntry[1], 5, 3, 0);
+ _screen->setCurPage(2);
+ shp[3] = _screen->encodeShape(0, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ for (int i = 1; i < 4; i++) {
+ copyBlurRegion(0, 0, 0, 0, 160, 136, i);
+ shp[3 - i] = _screen->encodeShape(0, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ }
+ _screen->setCurPage(0);
+
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _vm->snd_playSoundEffect(6);
+
+ for (int i = 0; i < 4 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ _screen->drawShape(0, shp[i], 80, 24, 0);
+ delete[] shp[i];
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 80, 0, 168, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(50 * _vm->_tickLength);
+
+ _screen->setCurPage(2);
+ shp[0] = _screen->encodeShape(20, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ _screen->loadBitmap(_filesWdEntry[2], 5, 3, 0);
+ shp[1] = _screen->encodeShape(0, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ shp[2] = _screen->encodeShape(20, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ _screen->loadBitmap(_filesWdEntry[3], 5, 3, 0);
+
+ for (int i = 0; i < 31; i++)
+ shp2[i] = _screen->encodeShape(_wdEncodeX[i], 136 + (_wdEncodeY[i] << 3), _wdEncodeWH[i], _wdEncodeWH[i] << 3, true, _vm->_cgaMappingAlt);
+ for (int i = 0; i < 3; i++)
+ shp3[i] = _screen->encodeShape(5 * i, 152, 5, 32, true, _vm->_cgaMappingAlt);
+
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+
+ for (int i = 0; i < 3 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ _screen->fillRect(0, 0, 159, 135, 12, 2);
+ _screen->drawShape(2, shp[i], 0, 0, 0);
+ _screen->copyRegion(0, 0, 80, 24, 160, 136, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 0, 80, 24, 160, 136, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(4 * _vm->_tickLength);
+ _screen->copyRegion(160, 0, 80, 24, 160, 136, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _screen->updateScreen();
+ _vm->delay(4 * _vm->_tickLength);
+ _screen->copyRegion(0, 184, 40, 184, 232, 16, 4, 0, Screen::CR_NO_P_CHECK);
+
+ int cx = 264;
+ int cy = 11;
+
+ for (int i = 0; i < 70 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+
+ _screen->copyRegion(cx - 2, cy - 2, 0, 0, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(4, shp3[((i & 3) == 3) ? 1 : (i & 3)], cx, cy, 0);
+ _screen->copyRegion(cx - 2, cy - 2, cx - 82, cy + 22, 48, 36, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, cx - 2, cy - 2, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ cx--;
+ cy++;
+
+ for (int ii = 0; ii < 5; ii++) {
+ int s = _vm->_rnd.getRandomNumber(255) % 31;
+ _screen->drawShape(0, shp2[s], _wdDsX[s] - 80, _wdDsY[s] + 24, 0);
+ }
+
+ if (!(_vm->_rnd.getRandomNumber(255) & 7))
+ _vm->snd_playSoundEffect(_vm->_rnd.getRandomBit() ? 5 : 14);
+
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 0; i < 3; i++) {
+ delete[] shp[i];
+ delete[] shp3[i];
+ }
+
+ for (int i = 0; i < 31; i++)
+ delete[] shp2[i];
+}
+
+void EoBIntroPlayer::king() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ _screen->loadBitmap(_filesKing[0], 5, 3, 0);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+
+ int x = 15;
+ int y = 14;
+ int w = 1;
+ int h = 1;
+
+ for (int i = 0; i < 10 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(x << 3, y << 3, x << 3, y << 3, w << 3, h << 3, 4, 0, Screen::CR_NO_P_CHECK);
+ if (x > 6)
+ x --;
+ if (y > 0)
+ y -= 2;
+ w += 3;
+ if (x + w > 34)
+ w = 34 - x;
+ h += 3;
+ if (y + h > 23)
+ h = 23 - y;
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->delay(25 * _vm->_tickLength);
+
+ uint8 *shp[4];
+ int16 dy[4];
+ int16 stepY[4];
+
+ static const uint8 advEncX[] = { 0, 6, 12, 19 };
+ static const uint8 advEncW[] = { 6, 6, 7, 6 };
+ static const int8 modY[] = { -4, -8, -2, -2, 1, 0, 0, 0 };
+
+ _screen->loadBitmap(_filesKing[1], 5, 3, 0);
+ _screen->setCurPage(2);
+ for (int i = 0; i < 4; i++) {
+ shp[i] = _screen->encodeShape(advEncX[i], 0, advEncW[i], 98, true, _vm->_cgaMappingAlt);
+ dy[i] = 180 + ((_vm->_rnd.getRandomNumber(255) & 3) << 3);
+ stepY[i] = (i * 5) & 3;
+ }
+
+ _screen->copyPage(0, 4);
+
+ for (bool runloop = true; runloop && !_vm->shouldQuit() && !_vm->skipFlag();) {
+ runloop = false;
+ uint32 end = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+
+ for (int i = 0; i < 4; i++) {
+ if (dy[i] <= 82)
+ continue;
+ stepY[i] = (stepY[i] + 1) & 7;
+ dy[i] += modY[stepY[i]];
+
+ if (dy[i] < 82)
+ dy[i] = 82;
+
+ if (dy[i] < 180) {
+ _screen->copyRegion((advEncX[i] + 8) << 3, dy[i] - 2, 0, dy[i] - 2, advEncW[i] << 3, 182 - dy[i], 4, 4, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(4, shp[i], 0, dy[i], 0);
+ _screen->copyRegion(0, dy[i] - 2, (advEncX[i] + 8) << 3, dy[i] - 2, advEncW[i] << 3, 182 - dy[i], 4, 0, Screen::CR_NO_P_CHECK);
+ }
+
+ runloop = true;
+ }
+
+ if (!(_vm->_rnd.getRandomNumber(255) & 3))
+ _vm->snd_playSoundEffect(7);
+
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 96, 0, 160, 320, 32, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(70 * _vm->_tickLength);
+
+ for (int i = 0; i < 4; i++)
+ delete[] shp[i];
+}
+
+void EoBIntroPlayer::hands() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ _screen->setCurPage(2);
+ uint8 *shp1 = _screen->encodeShape(0, 140, 21, 60, true, _vm->_cgaMappingAlt);
+ uint8 *shp2 = _screen->encodeShape(21, 140, 12, 60, true, _vm->_cgaMappingAlt);
+ _screen->loadBitmap(_filesHands[0], 3, 5, 0);
+
+ _screen->fillRect(0, 160, 319, 199, 12, 0);
+ _screen->fillRect(0, 0, 191, 63, 157, 2);
+ _screen->drawShape(2, shp1, 0, 4, 0);
+ _screen->drawShape(2, shp2, 151, 4, 0);
+ boxMorphTransition(25, 8, 18, 4, 3, 0, 21, 8, 6, 0, 28, 23);
+ _screen->copyRegion(0, 128, 0, 176, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->updateScreen();
+ _vm->delay(15 * _vm->_tickLength);
+ _vm->snd_playSoundEffect(11);
+
+ for (int i = -22; i <= 20 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 167, 63, 157);
+ _screen->drawShape(2, shp1, i, 4, 0);
+ _screen->drawShape(2, shp2, 105 - i, 4, 0);
+ _screen->copyRegion(0, 0, 144, 32, 168, 64, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSoundEffect(10);
+
+ delete[] shp1;
+ delete[] shp2;
+ _vm->delay(15 * _vm->_tickLength);
+
+ _screen->setCurPage(4);
+ shp1 = _screen->encodeShape(17, 0, 11, 120, true, _vm->_cgaMappingAlt);
+ shp2 = _screen->encodeShape(28, 112, 1, 31, true, _vm->_cgaMappingAlt);
+ uint8 *shp3 = _screen->encodeShape(9, 138, 14, 54, true, _vm->_cgaMappingAlt);
+
+ _screen->setCurPage(2);
+ _screen->fillRect(0, 0, 135, 63, 157);
+ _screen->drawShape(2, shp1, 32, -80, 0);
+ _screen->drawShape(2, shp2, 40, -16, 0);
+ boxMorphTransition(18, 16, 10, 12, 0, 0, 17, 8, 17, 3, 25, 10);
+ _vm->delay(15 * _vm->_tickLength);
+
+ for (int i = -80; i <= 0 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 135, 63, 157);
+ _screen->drawShape(2, shp1, 32, i, 0);
+ _screen->drawShape(2, shp2, 40, i + 64, 0);
+ _screen->copyRegion(0, 0, 80, 96, 136, 64, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSoundEffect(12);
+ _vm->delay(5 * _vm->_tickLength);
+
+ for (int i = 0; i > -54 && !_vm->shouldQuit() && !_vm->skipFlag(); i -= 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 135, 63, 157);
+ _screen->drawShape(2, shp3, 12, 64 + i, 0);
+ _screen->drawShape(2, shp1, 32, i, 0);
+ _screen->copyRegion(0, 0, 80, 96, 136, 64, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ delete[] shp1;
+ delete[] shp2;
+ delete[] shp3;
+ _vm->delay(15 * _vm->_tickLength);
+
+ _screen->setCurPage(4);
+ shp1 = _screen->encodeShape(0, 0, 17, 136, true, _vm->_cgaMappingAlt);
+ shp2 = _screen->encodeShape(0, 136, 9, 48, true, _vm->_cgaMappingAlt);
+
+ _screen->setCurPage(2);
+ _screen->fillRect(0, 0, 143, 95, 157);
+ _screen->drawShape(2, shp1, -56, -56, 0);
+ _screen->drawShape(2, shp2, 52, 49, 0);
+ boxMorphTransition(9, 6, 0, 0, 0, 0, 18, 12, 8, 11, 21, 10);
+ _vm->delay(15 * _vm->_tickLength);
+ _vm->snd_playSoundEffect(11);
+
+ for (int i = -56; i <= -8 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 143, 95, 157);
+ _screen->drawShape(2, shp1, i, i, 0);
+ _screen->drawShape(2, shp2, (i == -8) ? 55 : 52, (i == -8) ? 52 : 49, 0);
+ _screen->copyRegion(0, 0, 0, 0, 144, 96, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSoundEffect(10);
+ delete[] shp1;
+ delete[] shp2;
+ _vm->delay(30 * _vm->_tickLength);
+
+ _screen->setCurPage(4);
+ shp1 = _screen->encodeShape(28, 0, 11, 40, true, _vm->_cgaMappingAlt);
+ shp2 = _screen->encodeShape(28, 40, 10, 72, true, _vm->_cgaMappingAlt);
+
+ _screen->setCurPage(2);
+ _screen->fillRect(0, 0, 87, 112, 157);
+ _screen->drawShape(2, shp2, 0, 90, 0);
+ boxMorphTransition(20, 13, 15, 6, 0, 0, 11, 14, 0, 0, 24, 16);
+ _vm->delay(15 * _vm->_tickLength);
+
+ int dy = 90;
+ for (int i = -40; i <= 0 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 87, 112, 157);
+ _screen->drawShape(2, shp2, 0, dy, 0);
+ _screen->copyRegion(0, 0, 120, 48, 88, 112, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ dy -= 5;
+ }
+
+ _vm->snd_playSoundEffect(13);
+
+ for (int i = -40; i <= 0 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 87, 39, 157);
+ _screen->drawShape(2, shp1, 0, i, 0);
+ _screen->copyRegion(0, 0, 120, 48, 88, 112, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ delete[] shp1;
+ delete[] shp2;
+ _vm->delay(48 * _vm->_tickLength);
+}
+
+void EoBIntroPlayer::waterdeepExit() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ uint8 *shp2[31];
+ uint8 *shp3[3];
+
+ _screen->loadBitmap(_filesWdExit[0], 5, 3, 0);
+ _screen->setCurPage(2);
+ for (int i = 0; i < 31; i++)
+ shp2[i] = _screen->encodeShape(_wdEncodeX[i], 136 + (_wdEncodeY[i] << 3), _wdEncodeWH[i], _wdEncodeWH[i] << 3, true, _vm->_cgaMappingAlt);
+ for (int i = 0; i < 3; i++)
+ shp3[i] = _screen->encodeShape(5 * i + 15, 152, 5, 32, true, _vm->_cgaMappingAlt);
+ uint8 *shp1 = _screen->encodeShape(31, 136, 5, 32, true, _vm->_cgaMappingAlt);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->copyRegion(0, 0, 0, 136, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _screen->copyRegion(160, 0, 80, 24, 160, 136, 4, 0, Screen::CR_NO_P_CHECK);
+
+ int cx = 140;
+ int cy = 128;
+
+ for (int i = 0; i < 70 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ int fx = cx - 2;
+ if (fx < 160)
+ fx = 160;
+ int fy = cy - 2;
+ if (fy > 98)
+ fy = 98;
+
+ _screen->copyRegion(fx, fy, 0, 0, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(4, shp3[((i & 3) == 3) ? 1 : (i & 3)], cx, cy, 0);
+ _screen->drawShape(4, shp1, 160, 104, 0);
+ _screen->copyRegion(fx, fy, fx - 80, fy + 24, 48, 36, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, fx, fy, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ cx++;
+ cy--;
+
+ for (int ii = 0; ii < 5; ii++) {
+ int s = _vm->_rnd.getRandomNumber(255) % 31;
+ _screen->drawShape(0, shp2[s], _wdDsX[s] - 80, _wdDsY[s] + 24, 0);
+ }
+
+ if (!(_vm->_rnd.getRandomNumber(255) & 7))
+ _vm->snd_playSoundEffect(_vm->_rnd.getRandomBit() ? 5 : 14);
+
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 0; i < 3; i++)
+ delete[] shp3[i];
+
+ for (int i = 0; i < 31; i++)
+ delete[] shp2[i];
+ delete[] shp1;
+
+ _screen->setCurPage(0);
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _screen->copyRegion(0, 136, 0, 0, 48, 36, 0, 4, Screen::CR_NO_P_CHECK);
+
+ loadAndSetPalette(_filesWdExit[1]);
+ _screen->loadBitmap(_filesWdExit[2], 3, 5, 0);
+ _screen->convertPage(5, 2, _vm->_cgaMappingAlt);
+ whirlTransition();
+ _vm->delay(6 * _vm->_tickLength);
+
+ _screen->copyRegion(0, 144, 0, 184, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+
+ cx = 0;
+ cy = 136;
+ int dy = 0;
+ for (int i = 0; i < 19 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(cx, cy, 80, dy + 16, 160, 8, 2, 0, Screen::CR_NO_P_CHECK);
+ cy += 8;
+ dy += 8;
+ if (i == 6) {
+ cx = 160;
+ cy = 0;
+ }
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSong(3);
+ _vm->delay(60 * _vm->_tickLength);
+
+ for (int i = 0; i < 56 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(0, 136 + i, 80, 16, 160, 56 - i, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(160, 0, 80, 72 - i, 160, 96 + i, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 1; i < 48 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(160, i, 80, 16, 160, 152, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->loadBitmap(_filesWdExit[3], 3, 5, 0);
+ _screen->convertPage(5, 2, _vm->_cgaMappingAlt);
+ _vm->delay(30 * _vm->_tickLength);
+ _screen->setCurPage(0);
+ _screen->fillRect(0, 16, 319, 31, 12);
+ _screen->fillRect(0, 136, 319, 199, 12);
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ loadAndSetPalette(_filesWdExit[4]);
+ _screen->updateScreen();
+ _vm->delay(50 * _vm->_tickLength);
+}
+
+void EoBIntroPlayer::tunnel() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ _screen->setCurPage(4);
+ uint8 *shp2 = _screen->encodeShape(20, 0, 20, 120, true, _vm->_cgaMappingAlt);
+ uint8 *shp1 = _screen->encodeShape(0, 0, 20, 120, true, _vm->_cgaMappingAlt);
+ _vm->drawBlockObject(1, 4, shp2, 160, 0, 0);
+ _vm->drawBlockObject(1, 4, shp1, 0, 0, 0);
+ delete[] shp1;
+ delete[] shp2;
+
+ for (int i = 0; i < 3 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 8 * _vm->_tickLength;
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ _vm->snd_playSoundEffect(7);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _vm->snd_playSoundEffect(7);
+ end = _vm->_system->getMillis() + 8 * _vm->_tickLength;
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 160, 0, 184, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(18 * _vm->_tickLength);
+ _screen->copyRegion(160, 0, 80, 32, 160, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(5 * _vm->_tickLength);
+ _screen->copyRegion(0, 122, 80, 32, 160, 60, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(160, 122, 80, 92, 160, 60, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(5 * _vm->_tickLength);
+ _screen->copyRegion(160, 0, 80, 32, 160, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ for (int i = 0; i < 6; i++)
+ _screen->copyRegion(i * 48, 185, 56, (i << 3) + 24, 48, 8, 2, 2, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(5 * _vm->_tickLength);
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 2, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->loadBitmap(_filesTunnel[0], 5, 3, 0);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->updateScreen();
+ _vm->delay(40 * _vm->_tickLength);
+
+ _screen->copyRegion(264, 0, 136, 56, 48, 48, 4, 0, Screen::CR_NO_P_CHECK);
+ _vm->snd_playSoundEffect(8);
+ _screen->copyRegion(0, 0, 0, 0, 320, 184, 0, 2, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(16 * _vm->_tickLength);
+ _vm->snd_playSoundEffect(4);
+
+ for (int i = 0; i < 30 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ if (i == 0)
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _screen->copyRegion(80, 25 + (_vm->_rnd.getRandomNumber(255) & 7), 80, 24, 160, 144, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSoundEffect(9);
+
+ for (int i = 0; i < 6 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(_tvlX1[i] << 3, _tvlY1[i], _tvlX2[i] << 3, _tvlY2[i], _tvlW[i] << 3, _tvlH[i], 4, 2, Screen::CR_NO_P_CHECK);
+ for (int ii = 0; ii < 4 && !_vm->shouldQuit() && !_vm->skipFlag(); ii++) {
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(80, 25 + (_vm->_rnd.getRandomNumber(255) & 7), 80, 24, 160, 144, 2, 0, Screen::CR_NO_P_CHECK);
+ }
+ }
+ _screen->copyRegion(0, 0, 0, 0, 320, 168, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(40 * _vm->_tickLength);
+
+ _screen->loadBitmap(_filesTunnel[1], 5, 3, 0);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _vm->snd_playSoundEffect(6);
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(2 * _vm->_tickLength);
+ _screen->copyRegion(160, 0, 80, 32, 160, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(2 * _vm->_tickLength);
+ _screen->copyRegion(0, 120, 80, 30, 160, 64, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(160, 120, 80, 94, 160, 64, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 176, 0, 184, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->setCurPage(0);
+ _screen->updateScreen();
+ _vm->delay(50 * _vm->_tickLength);
+}
+
+void EoBIntroPlayer::loadAndSetPalette(const char *filename) {
+ if (_vm->_configRenderMode == Common::kRenderCGA || _vm->_configRenderMode == Common::kRenderEGA)
+ return;
+ _screen->loadPalette(filename, _screen->getPalette(0));
+ _screen->getPalette(0).fill(0, 1, 0);
+ _screen->setScreenPalette(_screen->getPalette(0));
+}
+
+void EoBIntroPlayer::copyBlurRegion(int x1, int y1, int x2, int y2, int w, int h, int step) {
+ const uint8 *ptr2 = _screen->getCPagePtr(3) + y1 * 320 + x1;
+
+ if (step == 1) {
+ while (h > 0) {
+ int dx = x2;
+ for (int i = 0; i < w; i += 2) {
+ _screen->setPagePixel(3, dx++, y2, ptr2[i]);
+ _screen->setPagePixel(3, dx++, y2, 0);
+ }
+ dx = x2;
+ y2++;
+ ptr2 += 320;
+ for (int i = 0; i < w; i += 2) {
+ _screen->setPagePixel(3, dx++, y2, 0);
+ _screen->setPagePixel(3, dx++, y2, ptr2[i + 1]);
+ }
+ y2++;
+ ptr2 += 320;
+ h -= 2;
+ }
+ } else if (step == 2) {
+ while (h > 0) {
+ int dx = x2;
+ for (int i = 0; i < w; i += 2) {
+ _screen->setPagePixel(3, dx++, y2, ptr2[i]);
+ _screen->setPagePixel(3, dx++, y2, 0);
+ }
+ dx = x2;
+ y2++;
+ ptr2 += 320;
+ for (int i = 0; i < w; i++)
+ _screen->setPagePixel(3, dx++, y2, 0);
+
+ y2++;
+ ptr2 += 320;
+ h -= 2;
+ }
+ } else if (step == 3) {
+ for (int i = 0; i < h; i++) {
+ int dx = x2;
+ if ((i % 3) == 0) {
+ int ii = 0;
+ for (; ii < w - 3; ii += 3) {
+ _screen->setPagePixel(3, dx++, y2, ptr2[ii]);
+ _screen->setPagePixel(3, dx++, y2, 0);
+ _screen->setPagePixel(3, dx++, y2, 0);
+ }
+ for (; ii < w; ii++)
+ _screen->setPagePixel(3, dx++, y2, 0);
+ } else {
+ for (int ii = 0; ii < w; ii++)
+ _screen->setPagePixel(3, dx++, y2, 0);
+ }
+ y2++;
+ ptr2 += 320;
+ }
+ }
+}
+
+void EoBIntroPlayer::boxMorphTransition(int targetDestX, int targetDestY, int targetFinalX, int targetFinalY, int targetSrcX, int targetSrcY, int targetFinalW, int targetFinalH, int originX1, int originY1, int originW, int originH) {
+ int originX2 = originX1 + originW;
+ int originY2 = originY1 + originH;
+ if (originY2 > 21)
+ originY2 = 21;
+
+ int w = 1;
+ int h = 1;
+ for (bool runloop = true; runloop && !_vm->shouldQuit() && !_vm->skipFlag();) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(targetSrcX << 3, targetSrcY << 3, targetDestX << 3, targetDestY << 3, w << 3, h << 3, 2, 0, Screen::CR_NO_P_CHECK);
+ if (originX1 < targetDestX)
+ _screen->copyRegion(312, 0, originX1 << 3, 0, 8, 176, 0, 0, Screen::CR_NO_P_CHECK);
+ if (originY1 < targetDestY)
+ _screen->copyRegion(0, 192, 0, originY1 << 3, 320, 8, 0, 0, Screen::CR_NO_P_CHECK);
+ if ((targetFinalX + targetFinalW) <= originX2)
+ _screen->copyRegion(312, 0, originX2 << 3, 0, 8, 176, 0, 0, Screen::CR_NO_P_CHECK);
+ if ((targetFinalY + targetFinalH) <= originY2)
+ _screen->copyRegion(0, 192, 0, originY2 << 3, 320, 8, 0, 0, Screen::CR_NO_P_CHECK);
+
+ if (!(targetDestX != targetFinalX || targetDestY != targetFinalY || w != targetFinalW || h != targetFinalH || originX1 < targetFinalX || originY1 < targetFinalY || (targetFinalX + targetFinalW) < originX2 || (targetFinalY + targetFinalH) < originY2))
+ runloop = false;
+
+ int v = targetFinalX - targetDestX;
+ v = (v < 0) ? -1 : ((v > 0) ? 1 : 0);
+ targetDestX += v;
+ v = targetFinalY - targetDestY;
+ v = (v < 0) ? -1 : ((v > 0) ? 1 : 0);
+ targetDestY += v;
+
+ if (w != targetFinalW)
+ w += 2;
+ if (w > targetFinalW)
+ w = targetFinalW;
+
+ if (h != targetFinalH)
+ h += 2;
+ if (h > targetFinalH)
+ h = targetFinalH;
+
+ if (++originX1 > targetFinalX)
+ originX1 = targetFinalX;
+
+ if (++originY1 > targetFinalY)
+ originY1 = targetFinalY;
+
+ if ((targetFinalX + targetFinalW) < originX2)
+ originX2--;
+
+ if ((targetFinalY + targetFinalH) < originY2)
+ originY2--;
+
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+}
+
+void EoBIntroPlayer::whirlTransition() {
+ for (int i = 0; i < 2; i++) {
+ for (int ii = 0; ii < 8; ii++) {
+ uint32 e = _vm->_system->getMillis() + 3;
+ if (ii & 1) {
+ for (int iii = i + ii; iii < 320; iii += 8)
+ _screen->drawClippedLine(iii, 0, iii, 199, 12);
+ } else {
+ for (int iii = i + ii; iii < 200; iii += 8)
+ _screen->drawClippedLine(0, iii, 319, iii, 12);
+ }
+ _screen->updateScreen();
+ uint32 c = _vm->_system->getMillis();
+ if (e > c)
+ _vm->_system->delayMillis(e - c);
+ }
+ }
+}
+
+int EoBEngine::mainMenu() {
+ int menuChoice = _menuChoiceInit;
+ _menuChoiceInit = 0;
+
+ Screen::FontId of = _screen->_currentFont;
+
+ while (menuChoice >= 0 && !shouldQuit()) {
+ switch (menuChoice) {
+ case 0: {
+ if (_configRenderMode != Common::kRenderEGA)
+ _screen->loadPalette("EOBPAL.COL", _screen->getPalette(0));
+ _screen->loadEoBBitmap("INTRO", _cgaMappingDefault, 5, 3, 2);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->_curPage = 2;
+ of = _screen->setFont(Screen::FID_6_FNT);
+ Common::String versionString(Common::String::format("ScummVM %s", gScummVMVersion));
+ _screen->printText(versionString.c_str(), 280 - versionString.size() * 6, 153, _screen->getPagePixel(2, 0, 0), 0);
+ _screen->setFont(of);
+ _screen->fillRect(0, 159, 319, 199, _screen->getPagePixel(2, 0, 0));
+ gui_drawBox(77, 165, 173, 29, 14, 13, 12);
+ gui_drawBox(76, 164, 175, 31, 14, 13, -1);
+ _screen->_curPage = 0;
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _allowImport = true;
+ menuChoice = mainMenuLoop();
+ _allowImport = false;
+ } break;
+
+ case 1:
+ // load game in progress
+ menuChoice = -1;
+ break;
+
+ case 2:
+ // create new party
+ menuChoice = -2;
+ break;
+
+ case 3:
+ // quit
+ menuChoice = -5;
+ break;
+
+ case 4:
+ // intro
+ _sound->loadSoundFile("SOUND");
+ _screen->hideMouse();
+ seq_playIntro();
+ _screen->showMouse();
+ _sound->loadSoundFile("ADLIB");
+ menuChoice = 0;
+ break;
+ }
+ }
+
+ return shouldQuit() ? -5 : menuChoice;
+}
+
+int EoBEngine::mainMenuLoop() {
+ int sel = -1;
+ do {
+ _screen->setScreenDim(28);
+ _gui->simpleMenu_setup(8, 0, _mainMenuStrings, -1, 0, 0);
+
+ while (sel == -1 && !shouldQuit())
+ sel = _gui->simpleMenu_process(8, _mainMenuStrings, 0, -1, 0);
+ } while ((sel < 0 || sel > 5) && !shouldQuit());
+
+ return sel + 1;
+}
+
+void EoBEngine::seq_playIntro() {
+ EoBIntroPlayer(this, _screen).start();
+}
+
+void EoBEngine::seq_playFinale() {
+ Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT");
+ _screen->loadFileDataToPage(s, 5, 32000);
+ delete s;
+
+ snd_playSoundEffect(20);
+
+ _txt->resetPageBreakString();
+ _txt->setWaitButtonMode(1);
+ _txt->setupField(12, true);
+ gui_drawBox(0, 0, 176, 175, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ _txt->printDialogueText(51, _moreStrings[0]);
+
+ if (!checkScriptFlags(0x1FFE)) {
+ _screen->fadeToBlack();
+ return;
+ }
+
+ _txt->printDialogueText(_finBonusStrings[0]);
+ for (int i = 0; i < 6; i++) {
+ _txt->printDialogueText(_finBonusStrings[1]);
+ if (_characters[i].flags & 1)
+ _txt->printDialogueText(_characters[i].name);
+ }
+
+ uint32 password = 0;
+ for (int i = 0; i < 4; i++) {
+ if (!(_characters[i].flags & 1))
+ continue;
+
+ int len = strlen(_characters[i].name);
+ for (int ii = 0; ii < len; ii++) {
+ uint32 c = _characters[i].name[ii];
+ password += (c * c);
+ }
+ }
+
+ _txt->printDialogueText(Common::String::format(_finBonusStrings[2], password).c_str(), true);
+ _screen->fadeToBlack();
+}
+
+void EoBEngine::seq_xdeath() {
+ uint8 *shapes1[5];
+ uint8 *shapes2;
+
+ _screen->loadShapeSetBitmap("XDEATH2", 5, 3);
+ for (int i = 0; i < 4; i++)
+ shapes1[i] = _screen->encodeShape(i / 2 * 14, i / 2 * 88, 14, 88, true, _cgaMappingDefault);
+ _screen->loadShapeSetBitmap("XDEATH3", 5, 3);
+ shapes2 = _screen->encodeShape(22, 0, 16, 95, true, _cgaMappingDefault);
+ _screen->loadEoBBitmap("XDEATH1", _cgaMappingDefault, 5, 3, -1);
+ _screen->convertPage(3, 2, _cgaMappingDefault);
+ _screen->setCurPage(0);
+
+ for (int i = 0; i < 10; i++) {
+ if (i == 2)
+ snd_playSoundEffect(72);
+ else if (i == 4 || i == 6)
+ snd_playSoundEffect(54);
+ else
+ snd_playSoundEffect(34);
+
+ if (i < 6) {
+ _screen->copyRegion((i % 3) * 104, i / 3 * 88, 32, 10, 104, 88, 2, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ snd_playSoundEffect(42);
+ _screen->drawShape(0, shapes1[i - 6], 32, 10, 0);
+ }
+
+ _screen->updateScreen();
+ delay(4 * _tickLength);
+ }
+
+ const ScreenDim *dm = _screen->getScreenDim(5);
+ _screen->modifyScreenDim(5, dm->sx, 8, dm->w, dm->h);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 0, 5, Screen::CR_NO_P_CHECK);
+
+ for (int i = 0; i < 19; i++) {
+ snd_playSoundEffect(119);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 5, 2, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(2, shapes2, 24, i * 5 - 90, 5);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ delay(2 * _tickLength);
+ }
+
+ _screen->modifyScreenDim(5, dm->sx, 0, dm->w, dm->h);
+
+ snd_playSoundEffect(5);
+ delay(60 * _tickLength);
+
+ for (int i = 0; i < 4; i++)
+ delete[] shapes1[i];
+ delete[] shapes2;
+
+ gui_drawPlayField(false);
+ gui_drawAllCharPortraitsWithStats();
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/sequence/sequences_hof.cpp b/engines/kyra/sequence/sequences_hof.cpp
new file mode 100644
index 0000000000..5f41faad15
--- /dev/null
+++ b/engines/kyra/sequence/sequences_hof.cpp
@@ -0,0 +1,3515 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/kyra_hof.h"
+#include "kyra/graphics/screen_hof.h"
+#include "kyra/graphics/screen_lol.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+#include "kyra/sequence/sequences_hof.h"
+#include "kyra/engine/timer.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+enum SequenceID {
+ kSequenceNoLooping = -1,
+ kSequenceVirgin = 0,
+ kSequenceWestwood,
+ kSequenceTitle,
+ kSequenceOverview,
+ kSequenceLibrary,
+ kSequenceHand,
+ kSequencePoint,
+ kSequenceZanfaun,
+
+ kSequenceFunters,
+ kSequenceFerb,
+ kSequenceFish,
+ kSequenceFheep,
+ kSequenceFarmer,
+ kSequenceFuards,
+ kSequenceFirates,
+ kSequenceFrash,
+
+ kSequenceHoFDemoVirgin,
+ kSequenceHoFDemoWestwood,
+ kSequenceHoFDemoTitle,
+ kSequenceHoFDemoHill,
+ kSequenceHoFDemoOuthome,
+ kSequenceHoFDemoWharf,
+ kSequenceHoFDemoDinob,
+ kSequenceHoFDemoFisher,
+
+// The following enums remain active even if LoL is disabled
+ kSequenceLoLDemoScene1,
+ kSequenceLoLDemoText1,
+ kSequenceLoLDemoScene2,
+ kSequenceLoLDemoText2,
+ kSequenceLoLDemoScene3,
+ kSequenceLoLDemoText3,
+ kSequenceLoLDemoScene4,
+ kSequenceLoLDemoText4,
+ kSequenceLoLDemoScene5,
+ kSequenceLoLDemoText5,
+ kSequenceLoLDemoScene6,
+
+ kSequenceArraySize
+};
+
+enum NestedSequenceID {
+ kNestedSequenceFiggle = 0,
+
+ kNestedSequenceOver1,
+ kNestedSequenceOver2,
+ kNestedSequenceForest,
+ kNestedSequenceDragon,
+ kNestedSequenceDarm,
+ kNestedSequenceLibrary2,
+ kNestedSequenceLibrary3,
+ kNestedSequenceMarco,
+ kNestedSequenceHand1a,
+ kNestedSequenceHand1b,
+ kNestedSequenceHand1c,
+ kNestedSequenceHand2,
+ kNestedSequenceHand3,
+ kNestedSequenceHand4,
+
+ kNestedSequenceHoFDemoWharf2,
+ kNestedSequenceHoFDemoDinob2,
+ kNestedSequenceHoFDemoWater,
+ kNestedSequenceHoFDemoBail,
+ kNestedSequenceHoFDemoDig,
+
+ kNestedSequenceArraySize
+};
+
+typedef int (SeqPlayer_HOF::*SeqProc)(WSAMovie_v2 *, int, int, int);
+
+struct SeqPlayerConfig {
+ SeqPlayerConfig(const HoFSeqData *data, const SeqProc *callbacks, const SeqProc *nestedCallbacks) : seq(data->seq), seqProc(callbacks), numSeq(data->numSeq), nestedSeq(data->nestedSeq), nestedSeqProc(nestedCallbacks), numNestedSeq(data->numNestedSeq) {}
+ const HoFSequence *seq;
+ const SeqProc *seqProc;
+ int numSeq;
+ const HoFNestedSequence *nestedSeq;
+ const SeqProc *nestedSeqProc;
+ int numNestedSeq;
+};
+
+class SeqPlayer_HOF {
+public:
+ SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system, bool startupSaveLoadable = false);
+ ~SeqPlayer_HOF();
+
+ int play(SequenceID firstScene, SequenceID loopStartScene);
+ void pause(bool toggle);
+
+ static SeqPlayer_HOF *instance() { return _instance; }
+
+private:
+ // Init
+ void setupCallbacks();
+
+ // Playback loop
+ void runLoop();
+ void playScenes();
+
+ bool checkAbortPlayback();
+ bool checkPlaybackStatus();
+
+ bool _abortRequested;
+ uint32 _pauseStart;
+
+ // Sequence transitions
+ void doTransition(int type);
+ void nestedFrameAnimTransition(int srcPage, int dstPage, int delaytime, int steps, int x, int y, int w, int h, int openClose, int directionFlags);
+ void nestedFrameFadeTransition(const char *cmpFile);
+
+ // Animations
+ void playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int numFrames, int frameRate, int x, int y, const SeqProc callback, Palette *fadePal1, Palette *fadePal2, int fadeRate, bool restoreScreen);
+ void playDialogueAnimation(uint16 strID, uint16 soundID, int textColor, int textPosX, int textPosY, int textWidth, WSAMovie_v2 *wsaObj, int animStartFrame, int animLastFrame, int animPosX, int animPosY);
+
+ void startNestedAnimation(int animSlot, int sequenceID);
+ void closeNestedAnimation(int animSlot);
+ void unloadNestedAnimation(int animSlot);
+ void doNestedFrameTransition(int transitionType, int animSlot);
+ void updateAllNestedAnimations();
+ bool updateNestedAnimation(int animSlot);
+
+ struct AnimSlot {
+ SeqProc callback;
+ WSAMovie_v2 *movie;
+ const FrameControl *control;
+ int16 flags;
+ uint16 startFrame;
+ uint16 endFrame;
+ uint16 frameDelay;
+ uint32 nextFrame;
+ uint16 currentFrame;
+ uint16 lastFrame;
+ uint16 x;
+ uint16 y;
+ uint16 fadeInTransitionType;
+ uint16 fadeOutTransitionType;
+ };
+
+ AnimSlot _animSlots[8];
+
+ bool _updateAnimations;
+ uint32 _animDuration;
+ int _animCurrentFrame;
+ int _callbackCurrentFrame;
+
+ // The only reason to declare these here (instead of just locally) is being able to increase them after pausing the Engine
+ uint32 _specialAnimTimeOutTotal;
+ uint32 _specialAnimFrameTimeOut;
+
+ // Subtitles/Dialogue/Sound
+ void playSoundEffect(uint16 id, int16 vol);
+ void playSoundAndDisplaySubTitle(uint16 id);
+ void printFadingText(uint16 strID, int x, int y, const uint8 *colorMap, uint8 textcolor);
+
+ int displaySubTitle(uint16 strID, uint16 posX, uint16 posY, int duration, uint16 width);
+ void updateSubTitles();
+ char *preprocessString(const char *str, int width);
+ void waitForSubTitlesTimeout();
+ uint32 ticksTillSubTitlesTimeout();
+ void resetAllTextSlots();
+
+ void fadeOutMusic();
+
+ struct TextSlot {
+ uint16 strIndex;
+ uint16 x;
+ uint16 y;
+ uint16 width;
+ int32 duration;
+ uint32 startTime;
+ int16 textcolor;
+ };
+
+ TextSlot _textSlots[10];
+
+ char *_tempString;
+
+ uint8 _textColor[2];
+ uint8 _textColorMap[16];
+ int _textDuration[33];
+
+ const char *const *_sequenceStrings;
+ const char *const *_sequenceSoundList;
+ int _sequenceSoundListSize;
+
+ static const uint8 _textColorPresets[];
+
+ // HOF credits
+ void playHoFTalkieCredits();
+ void displayHoFTalkieScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed, int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData = 0, const char *const *specialData = 0);
+
+ bool _talkieFinaleExtraFlag;
+
+ // HOF+LOL demo specific
+ void updateDemoAdText(int bottom, int top);
+
+ ActiveItemAnim _hofDemoActiveItemAnim[5];
+ const HoFSeqItemAnimData *_hofDemoAnimData;
+
+ uint32 _fisherAnimCurTime;
+ int _scrollProgressCounter;
+
+ uint8 *_hofDemoShapeData;
+ uint8 *_hofDemoItemShapes[20];
+
+ // Misc
+ void delayTicks(uint32 ticks);
+ void delayUntil(uint32 dest);
+ void setCountDown(uint32 ticks);
+ bool countDownRunning();
+
+ uint32 _countDownRemainder;
+ uint32 _countDownLastUpdate;
+
+ enum SeqPlayerTargetInfo {
+ kHoF = 0,
+ kHoFDemo,
+ kLoLDemo
+ };
+
+ SeqPlayerTargetInfo _target;
+ int _firstScene, _loopStartScene, _curScene, _preventSkipBeforeScene, _lastScene;
+ bool _startupSaveLoadable, _isFinale, _preventLooping;
+
+ SeqPlayerConfig *_config;
+
+ MainMenu *_menu;
+ int _result;
+
+ bool _abortPlayback;
+
+ KyraEngine_v1 *_vm;
+ Screen_v2 *_screen;
+ // We might consider getting rid of Screen_HoF, since there are only 2 methods left in that class anyway
+ Screen_HoF *_screenHoF;
+ OSystem *_system;
+
+ static SeqPlayer_HOF *_instance;
+
+private:
+ // Sequence specific callback functions
+ int cbHOF_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_title(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_library(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_hand(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_point(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+ int cbHOF_over1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_over2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_forest(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_dragon(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_darm(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_library2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_marco(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_hand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_hand1b(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_hand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_hand2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_hand3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+ int cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_ferb(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_fish(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_fheep(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_farmer(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_firates(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+ int cbHOF_figgle(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+ int cbHOFDEMO_virgin(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_title(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_hill(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_outhome(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_wharf(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_dinob(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_fisher(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+ int cbHOFDEMO_wharf2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_dinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_water(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_bail(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbHOFDEMO_dig(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+#ifdef ENABLE_LOL
+ int cbLOLDEMO_scene1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbLOLDEMO_scene2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbLOLDEMO_scene3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbLOLDEMO_scene4(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbLOLDEMO_scene5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbLOLDEMO_text5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+ int cbLOLDEMO_scene6(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+#endif // ENABLE_LOL
+};
+
+SeqPlayer_HOF *SeqPlayer_HOF::_instance = 0;
+
+SeqPlayer_HOF::SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system, bool startupSaveLoadable) : _vm(vm), _screen(screen), _system(system), _startupSaveLoadable(startupSaveLoadable) {
+ // We use a static pointer for pauseEngine functionality. Since we don't
+ // ever need more than one SeqPlayer_HOF object at the same time we keep
+ // this simple and just add an assert to detect typos, regressions, etc.
+ assert(_instance == 0);
+
+ memset(_animSlots, 0, sizeof(_animSlots));
+ memset(_textSlots, 0, sizeof(_textSlots));
+ memset(_hofDemoActiveItemAnim, 0, sizeof(_hofDemoActiveItemAnim));
+
+ _screenHoF = _vm->game() == GI_KYRA2 ? (Screen_HoF*)screen : 0;
+ _config = 0;
+ _result = 0;
+ _sequenceSoundList = 0;
+ _hofDemoAnimData = 0;
+ _hofDemoShapeData = 0;
+ _isFinale = false;
+ _preventLooping = false;
+ _menu = 0;
+ _abortRequested = false;
+ _pauseStart = 0;
+
+ _updateAnimations = false;
+ _animDuration = 0;
+ _animCurrentFrame = 0;
+ _callbackCurrentFrame = 0;
+
+ _abortPlayback = false;
+ _curScene = 0;
+ _preventSkipBeforeScene = -1;
+ _lastScene = 0;
+
+ _scrollProgressCounter = 0;
+ _fisherAnimCurTime = 0;
+
+ _tempString = new char[200];
+
+ _countDownRemainder = 0;
+ _countDownLastUpdate = 0;
+
+ int tempSize = 0;
+ _vm->resource()->unloadAllPakFiles();
+ _vm->resource()->loadPakFile(StaticResource::staticDataFilename());
+ const char *const *files = _vm->staticres()->loadStrings(k2SeqplayPakFiles, tempSize);
+ _vm->resource()->loadFileList(files, tempSize);
+
+ _sequenceStrings = _vm->staticres()->loadStrings(k2SeqplayStrings, tempSize);
+ uint8 multiplier = (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) ? 12 : 8;
+ for (int i = 0; i < MIN(33, tempSize); i++)
+ _textDuration[i] = (int)strlen(_sequenceStrings[i]) * multiplier;
+
+ if (_sequenceSoundList) {
+ for (int i = 0; i < _sequenceSoundListSize; i++) {
+ if (_sequenceSoundList[i])
+ delete[] _sequenceSoundList[i];
+ }
+ delete[] _sequenceSoundList;
+ _sequenceSoundList = 0;
+ }
+
+ const char *const *seqSoundList = _vm->staticres()->loadStrings(k2SeqplaySfxFiles, _sequenceSoundListSize);
+
+ // replace sequence talkie files with localized versions
+ const char *const *tlkfiles = _vm->staticres()->loadStrings(k2SeqplayTlkFiles, tempSize);
+ char **tmpSndLst = new char *[_sequenceSoundListSize];
+
+ for (int i = 0; i < _sequenceSoundListSize; i++) {
+ const int len = strlen(seqSoundList[i]);
+
+ tmpSndLst[i] = new char[len + 1];
+ tmpSndLst[i][0] = 0;
+
+ if (tlkfiles && len > 1) {
+ for (int ii = 0; ii < tempSize; ii++) {
+ if (strlen(tlkfiles[ii]) > 1 && !scumm_stricmp(&seqSoundList[i][1], &tlkfiles[ii][1]))
+ strcpy(tmpSndLst[i], tlkfiles[ii]);
+ }
+ }
+
+ if (tmpSndLst[i][0] == 0)
+ strcpy(tmpSndLst[i], seqSoundList[i]);
+ }
+
+ tlkfiles = seqSoundList = 0;
+ _vm->staticres()->unloadId(k2SeqplayTlkFiles);
+ _vm->staticres()->unloadId(k2SeqplaySfxFiles);
+ _sequenceSoundList = tmpSndLst;
+
+ if (_vm->gameFlags().platform == Common::kPlatformPC98)
+ _vm->sound()->loadSoundFile("SOUND.DAT");
+
+ _screen->loadFont(_screen->FID_GOLDFONT_FNT, "GOLDFONT.FNT");
+ _screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
+
+ if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
+ if (_vm->game() == GI_KYRA2) {
+ _hofDemoAnimData = _vm->staticres()->loadHoFSeqItemAnimData(k2SeqplayShapeAnimData, tempSize);
+ uint8 *shp = _vm->resource()->fileData("ICONS.SHP", 0);
+ uint32 outsize = READ_LE_UINT16(shp + 4);
+ _hofDemoShapeData = new uint8[outsize];
+ Screen::decodeFrame4(shp + 10, _hofDemoShapeData, outsize);
+ for (int i = 0; i < 20; i++)
+ _hofDemoItemShapes[i] = _screen->getPtrToShape(_hofDemoShapeData, i);
+ delete[] shp;
+ }
+ } else {
+ const MainMenu::StaticData data = {
+ { _sequenceStrings[97], _sequenceStrings[96], _sequenceStrings[95], _sequenceStrings[98], 0 },
+ { 0x01, 0x04, 0x0C, 0x04, 0x00, 0xD7, 0xD6 },
+ { 0xD8, 0xDA, 0xD9, 0xD8 },
+ (_vm->gameFlags().lang == Common::JA_JPN) ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT, 240
+ };
+
+ _menu = new MainMenu(_vm);
+ _menu->init(data, MainMenu::Animation());
+ }
+
+ _instance = this;
+}
+
+SeqPlayer_HOF::~SeqPlayer_HOF() {
+ _instance = 0;
+
+ if (_sequenceSoundList) {
+ for (int i = 0; i < _sequenceSoundListSize; i++) {
+ if (_sequenceSoundList[i])
+ delete[] _sequenceSoundList[i];
+ }
+ delete[] _sequenceSoundList;
+ _sequenceSoundList = NULL;
+ }
+
+ delete[] _tempString;
+ delete[] _hofDemoShapeData;
+ delete _menu;
+
+ if (_vm->game() != GI_LOL)
+ _screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+}
+
+int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
+ bool incompatibleData = false;
+ AudioResourceSet soundSet = kMusicIntro;
+ _firstScene = firstScene;
+ _loopStartScene = loopStartScene;
+ _preventLooping = false;
+ _result = 0;
+
+ if (firstScene >= kSequenceArraySize || firstScene < kSequenceVirgin || loopStartScene >= kSequenceArraySize || loopStartScene < kSequenceNoLooping) {
+ return 0;
+ } else if (firstScene >= kSequenceLoLDemoScene1) {
+#ifndef ENABLE_LOL
+ error("SeqPlayer_HOF::play(): The Lands of Lore sub engine (including this non-interactive demo) has been disabled in this build");
+#endif
+ incompatibleData = (_vm->game() != GI_LOL);
+ _firstScene -= kSequenceLoLDemoScene1;
+ if (loopStartScene != kSequenceNoLooping)
+ _loopStartScene -= kSequenceLoLDemoScene1;
+ _lastScene = kSequenceLoLDemoScene6 - kSequenceLoLDemoScene1;
+ _target = kLoLDemo;
+ _screen->_charWidth = 0;
+ } else if (firstScene >= kSequenceHoFDemoVirgin) {
+ incompatibleData = (_vm->game() != GI_KYRA2 || !_vm->gameFlags().isDemo || _vm->gameFlags().isTalkie);
+ _firstScene -= kSequenceHoFDemoVirgin;
+ if (loopStartScene != kSequenceNoLooping)
+ _loopStartScene -= kSequenceHoFDemoVirgin;
+ _lastScene = kSequenceHoFDemoFisher - kSequenceHoFDemoVirgin;
+ _target = kHoFDemo;
+ _screen->_charWidth = -2;
+ } else {
+ _isFinale = _preventLooping = firstScene > kSequenceZanfaun;
+ incompatibleData = (_vm->game() != GI_KYRA2 || (_vm->gameFlags().isDemo && (!_vm->gameFlags().isTalkie || _isFinale)));
+ _target = kHoF;
+ _screen->_charWidth = -2;
+ if (_isFinale) {
+ soundSet = kMusicFinale;
+ _lastScene = kSequenceFrash;
+ } else {
+ _lastScene = kSequenceZanfaun;
+ }
+ }
+
+ if (incompatibleData)
+ error("SeqPlayer_HOF::play(): Specified sequences do not match the available sequence data for this target");
+
+ _vm->sound()->selectAudioResourceSet(soundSet);
+ _vm->sound()->loadSoundFile(0);
+
+ setupCallbacks();
+ runLoop();
+
+ return _result;
+}
+
+void SeqPlayer_HOF::pause(bool toggle) {
+ if (toggle) {
+ _pauseStart = _system->getMillis();
+ } else {
+ uint32 pausedTime = _system->getMillis() - _pauseStart;
+ _pauseStart = 0;
+
+ _countDownLastUpdate += pausedTime;
+ _fisherAnimCurTime += pausedTime;
+ _specialAnimTimeOutTotal += pausedTime;
+ _specialAnimFrameTimeOut += pausedTime;
+
+ for (int i = 0; i < 10; i++) {
+ if (_textSlots[i].duration != -1)
+ _textSlots[i].startTime += pausedTime;
+ }
+
+ for (int i = 0; i < 8; i++) {
+ if (_animSlots[i].flags != -1)
+ _animSlots[i].nextFrame += pausedTime;
+ }
+ }
+}
+
+void SeqPlayer_HOF::setupCallbacks() {
+#define SCB(x) &SeqPlayer_HOF::cbHOF_##x
+ static const SeqProc seqCallbacksHoF[] = { 0, SCB(westwood), SCB(title), SCB(overview), SCB(library), SCB(hand), SCB(point), SCB(zanfaun), SCB(funters), SCB(ferb), SCB(fish), SCB(fheep), SCB(farmer), SCB(fuards), SCB(firates), SCB(frash) };
+ static const SeqProc nestedSeqCallbacksHoF[] = { SCB(figgle), SCB(over1), SCB(over2), SCB(forest), SCB(dragon), SCB(darm), SCB(library2), SCB(library2), SCB(marco), SCB(hand1a), SCB(hand1b), SCB(hand1c), SCB(hand2), SCB(hand3), 0 };
+#undef SCB
+#define SCB(x) &SeqPlayer_HOF::cbHOFDEMO_##x
+ static const SeqProc seqCallbacksHoFDemo[] = { SCB(virgin), SCB(westwood), SCB(title), SCB(hill), SCB(outhome), SCB(wharf), SCB(dinob), SCB(fisher) };
+ static const SeqProc nestedSeqCallbacksHoFDemo[] = { SCB(wharf2), SCB(dinob2), SCB(water), SCB(bail), SCB(dig), 0 };
+#undef SCB
+#ifdef ENABLE_LOL
+#define SCB(x) &SeqPlayer_HOF::cbLOLDEMO_##x
+ static const SeqProc seqCallbacksLoLDemo[] = { SCB(scene1), 0, SCB(scene2), 0, SCB(scene3), 0, SCB(scene4), 0, SCB(scene5), SCB(text5), SCB(scene6), 0 };
+#undef SCB
+#else
+ static const SeqProc seqCallbacksLoLDemo[] = { 0 };
+#endif
+ static const SeqProc nestedSeqCallbacksLoLDemo[] = { 0 };
+
+ static const SeqProc *const seqCallbacks[] = { seqCallbacksHoF, seqCallbacksHoFDemo, seqCallbacksLoLDemo};
+ static const SeqProc *const nestedSeqCallbacks[] = { nestedSeqCallbacksHoF, nestedSeqCallbacksHoFDemo, nestedSeqCallbacksLoLDemo};
+
+ int tmpSize = 0;
+ delete _config;
+ _config = new SeqPlayerConfig(_vm->staticres()->loadHoFSequenceData(k2SeqplaySeqData, tmpSize), seqCallbacks[_target], nestedSeqCallbacks[_target]);
+}
+
+void SeqPlayer_HOF::runLoop() {
+ memset(_animSlots, 0, sizeof(_animSlots));
+ memset(_textSlots, 0, sizeof(_textSlots));
+ memset(_hofDemoActiveItemAnim, 0, sizeof(_hofDemoActiveItemAnim));
+ for (int i = 0; i < 8; ++i)
+ _animSlots[i].flags = -1;
+
+ _screen->clearPage(10);
+ _screen->clearPage(12);
+ _screen->hideMouse();
+ int oldPage = _screen->setCurPage(2);
+
+ for (int i = 0; i < 4; ++i)
+ _screen->getPalette(i).clear();
+
+ _updateAnimations = false;
+ _animCurrentFrame = 0;
+ _textColor[0] = _textColor[1] = 0;
+ _curScene = _firstScene;
+
+ do {
+ playScenes();
+ doTransition(0);
+ resetAllTextSlots();
+ fadeOutMusic();
+ _firstScene = ((!_startupSaveLoadable || _preventLooping) && _curScene >= _loopStartScene) ? kSequenceNoLooping : _loopStartScene;
+ } while (!_vm->shouldQuit() && _firstScene != kSequenceNoLooping);
+
+ checkPlaybackStatus();
+
+ for (int i = 0; i < 8; i++)
+ unloadNestedAnimation(i);
+
+ if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie)
+ _screen->fadeToBlack();
+ else if (!_isFinale && !_startupSaveLoadable)
+ _result = 1;
+
+ if (!_result)
+ delayTicks(75);
+
+ _screen->setCurPage(oldPage);
+ _screen->_charWidth = 0;
+ _screen->showMouse();
+}
+
+void SeqPlayer_HOF::playScenes() {
+ _vm->sound()->stopAllSoundEffects();
+ _curScene = _firstScene;
+
+ _screen->copyPalette(1, 0);
+ WSAMovie_v2 anim(_vm);
+ _abortRequested = false;
+
+ _scrollProgressCounter = 0;
+
+ while (!_vm->shouldQuit()) {
+ if (checkAbortPlayback())
+ if (checkPlaybackStatus())
+ break;
+
+ _callbackCurrentFrame = 0;
+
+ if (_curScene > _lastScene)
+ break;
+
+ const Kyra::HoFSequence &sq = _config->seq[_curScene];
+
+ if (sq.flags & 2) {
+ _screen->loadBitmap(sq.cpsFile, 2, 2, &_screen->getPalette(0));
+ _screen->setScreenPalette(_screen->getPalette(0));
+ } else {
+ _screen->setCurPage(2);
+ _screen->clearPage(2);
+ _screen->loadPalette("GOLDFONT.COL", _screen->getPalette(0));
+ }
+
+ if (_config->seqProc[_curScene] && !(_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie))
+ (this->*_config->seqProc[_curScene])(0, 0, 0, -1);
+
+ if (sq.flags & 1) {
+ anim.open(sq.wsaFile, 0, &_screen->getPalette(0));
+ if (!(sq.flags & 2))
+ anim.displayFrame(0, 2, sq.xPos, sq.yPos, 0x4000, 0, 0);
+ }
+
+ if (sq.flags & 4) {
+ int cp = _screen->setCurPage(2);
+ Screen::FontId cf = _screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
+
+ if (sq.stringIndex1 != -1)
+ _screen->printText(_sequenceStrings[sq.stringIndex1], (320 - _screen->getTextWidth(_sequenceStrings[sq.stringIndex1])) / 2, 100 - _screen->getFontHeight(), 1, 0);
+
+ if (sq.stringIndex2 != -1)
+ _screen->printText(_sequenceStrings[sq.stringIndex2], (320 - _screen->getTextWidth(_sequenceStrings[sq.stringIndex2])) / 2, 100, 1, 0);
+
+ _screen->setFont(cf);
+ _screen->setCurPage(cp);
+ }
+
+ _screen->copyPage(2, 12);
+ _screen->copyPage(0, 2);
+ _screen->copyPage(2, 10);
+ _screen->copyPage(12, 2);
+
+ doTransition(sq.fadeInTransitionType);
+
+ if (!(checkAbortPlayback() || _vm->shouldQuit() || _result)) {
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ }
+
+ if (sq.flags & 1) {
+ playAnimation(&anim, sq.startFrame, sq.numFrames, sq.duration, sq.xPos, sq.yPos, _config->seqProc[_curScene], &_screen->getPalette(1), &_screen->getPalette(0), 30, 0);
+ anim.close();
+ } else {
+ _animDuration = sq.duration;
+ setCountDown(_animDuration);
+
+ while (!checkAbortPlayback() && !_vm->shouldQuit() && (countDownRunning() || _updateAnimations)) {
+ uint32 endFrame = (_system->getMillis() + _vm->tickLength()) & ~(_vm->tickLength() - 1);
+ updateAllNestedAnimations();
+
+ if (_config->seqProc[_curScene])
+ (this->*_config->seqProc[_curScene])(0, 0, 0, 0);
+
+ updateSubTitles();
+
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ _screen->copyPage(12, 2);
+
+ do {
+ if (checkAbortPlayback())
+ if (checkPlaybackStatus())
+ break;
+ } while (_system->getMillis() < endFrame);
+ }
+ }
+
+ if (_config->seqProc[_curScene] && !(_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie))
+ (this->*_config->seqProc[_curScene])(0, 0, 0, -2);
+
+ uint32 textTimeOut = ticksTillSubTitlesTimeout();
+ setCountDown(sq.timeout < textTimeOut ? textTimeOut : sq.timeout);
+
+ while (!checkAbortPlayback() && !_vm->shouldQuit() && (countDownRunning() || _updateAnimations)) {
+ updateAllNestedAnimations();
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ _screen->copyPage(12, 2);
+ }
+
+ doTransition(sq.fadeOutTransitionType);
+ _curScene++;
+ }
+
+ resetAllTextSlots();
+ _vm->sound()->haltTrack();
+ _vm->sound()->voiceStop();
+
+ if ((!checkAbortPlayback() || _vm->shouldQuit()) && _vm->gameFlags().isDemo)
+ _curScene = -1;
+}
+
+bool SeqPlayer_HOF::checkAbortPlayback() {
+ Common::Event event;
+
+ if (_vm->skipFlag()) {
+ _abortRequested = true;
+ _vm->resetSkipFlag();
+ }
+
+ if (_abortRequested)
+ return true;
+
+ while (_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ if (event.kbd.keycode == Common::KEYCODE_q && event.kbd.hasFlags(Common::KBD_CTRL)) {
+ _abortRequested = true;
+ _vm->quitGame();
+ return true;
+ } else if (event.kbd.keycode != Common::KEYCODE_ESCAPE && event.kbd.keycode != Common::KEYCODE_RETURN && event.kbd.keycode != Common::KEYCODE_SPACE) {
+ continue;
+ }
+ // fall through
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_RBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ _abortRequested = true;
+ return true;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool SeqPlayer_HOF::checkPlaybackStatus() {
+ _updateAnimations = false;
+
+ if (_curScene <= _preventSkipBeforeScene || (_curScene == _loopStartScene && !_isFinale)) {
+ _abortRequested = false;
+ return false;
+ }
+
+ if (_loopStartScene == kSequenceNoLooping) {
+ doTransition(0);
+ fadeOutMusic();
+ _abortPlayback = true;
+ }
+
+ return true;
+}
+
+void SeqPlayer_HOF::doTransition(int type) {
+ for (int i = 0; i < 8; i++)
+ closeNestedAnimation(i);
+
+ switch (type) {
+ case 0:
+ _screen->fadeToBlack(36);
+ _screen->getPalette(0).clear();
+ _screen->getPalette(1).clear();
+ break;
+
+ case 1:
+ playSoundAndDisplaySubTitle(_vm->_rnd.getRandomBit());
+
+ _screen->getPalette(0).fill(0, 256, 0x3F);
+ _screen->fadePalette(_screen->getPalette(0), 16);
+
+ _screen->copyPalette(1, 0);
+ break;
+
+ case 3:
+ _screen->copyPage(2, 0);
+ _screen->fadePalette(_screen->getPalette(0), 16);
+ _screen->copyPalette(1, 0);
+ break;
+
+ case 4:
+ _screen->copyPage(2, 0);
+ _screen->fadePalette(_screen->getPalette(0), 36);
+ _screen->copyPalette(1, 0);
+ break;
+
+ case 5:
+ _screen->copyPage(2, 0);
+ break;
+
+ case 6:
+ // UNUSED
+ // seq_loadBLD("library.bld");
+ break;
+
+ case 7:
+ // UNUSED
+ // seq_loadBLD("marco.bld");
+ break;
+
+ case 8:
+ _screen->fadeToBlack(16);
+ _screen->getPalette(0).clear();
+ _screen->getPalette(1).clear();
+
+ delayTicks(120);
+ break;
+
+ case 9: {
+ Palette &pal = _screen->getPalette(0);
+ for (int i = 0; i < 255; i++)
+ pal.fill(i, 1, (pal[3 * i] + pal[3 * i + 1] + pal[3 * i + 2]) / 3);
+ pal.fill(255, 1, 0x3F);
+
+ _screen->fadePalette(pal, 64);
+ _screen->copyPalette(1, 0);
+ } break;
+
+ default:
+ break;
+ }
+}
+
+void SeqPlayer_HOF::nestedFrameAnimTransition(int srcPage, int dstPage, int delaytime, int steps, int x, int y, int w, int h, int openClose, int directionFlags) {
+ if (openClose) {
+ for (int i = 1; i < steps; i++) {
+ uint32 endtime = _system->getMillis() + delaytime * _vm->tickLength();
+
+ int w2 = (((w * 256) / steps) * i) / 256;
+ int h2 = (((h * 256) / steps) * i) / 256;
+
+ int ym = (directionFlags & 2) ? (h - h2) : 0;
+ int xm = (directionFlags & 1) ? (w - w2) : 0;
+
+ _screen->wsaFrameAnimationStep(0, 0, x + xm, y + ym, w, h, w2, h2, srcPage, dstPage, 0);
+
+ _screen->copyPage(dstPage, 6);
+ _screen->copyPage(dstPage, 0);
+ _screen->updateScreen();
+
+ _screen->copyPage(12, dstPage);
+ delayUntil(endtime);
+ }
+
+ _screen->wsaFrameAnimationStep(0, 0, x, y, w, h, w, h, srcPage, dstPage, 0);
+ _screen->copyPage(dstPage, 6);
+ _screen->copyPage(dstPage, 0);
+ _screen->updateScreen();
+ } else {
+ _screen->copyPage(12, dstPage);
+ for (int i = steps; i; i--) {
+ uint32 endtime = _system->getMillis() + delaytime * _vm->tickLength();
+
+ int w2 = (((w * 256) / steps) * i) / 256;
+ int h2 = (((h * 256) / steps) * i) / 256;
+
+ int ym = (directionFlags & 2) ? (h - h2) : 0;
+ int xm = (directionFlags & 1) ? (w - w2) : 0;
+
+ _screen->wsaFrameAnimationStep(0, 0, x + xm, y + ym, w, h, w2, h2, srcPage, dstPage, 0);
+
+ _screen->copyPage(dstPage, 6);
+ _screen->copyPage(dstPage, 0);
+ _screen->updateScreen();
+
+ _screen->copyPage(12, dstPage);
+ delayUntil(endtime);
+ }
+ }
+}
+
+void SeqPlayer_HOF::nestedFrameFadeTransition(const char *cmpFile) {
+ _screen->copyPage(10, 2);
+ _screen->copyPage(4, 10);
+ _screen->clearPage(6);
+ _screen->loadBitmap(cmpFile, 6, 6, 0);
+ _screen->copyPage(12, 4);
+
+ for (int i = 0; i < 3; i++) {
+ uint32 endtime = _system->getMillis() + 4 * _vm->tickLength();
+ assert(_screenHoF);
+ _screenHoF->cmpFadeFrameStep(4, 320, 200, 0, 0, 2, 320, 200, 0, 0, 320, 200, 6);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->updateScreen();
+ delayUntil(endtime);
+ }
+
+ _screen->copyPage(4, 0);
+ _screen->updateScreen();
+ _screen->copyPage(4, 2);
+ _screen->copyPage(4, 6);
+ _screen->copyPage(10, 4);
+}
+
+void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastFrame, int frameRate, int x, int y, const SeqProc callback, Palette *fadePal1, Palette *fadePal2, int fadeRate, bool restoreScreen) {
+ bool finished = false;
+ uint32 startTime = _system->getMillis();
+
+ int origW = wsaObj ? wsaObj->width() : 0;
+ int origH = wsaObj ? wsaObj->height() : 0;
+ int drwX = x;
+ int drwY = y;
+ int drwW = origW;
+ int drwH = origH;
+
+ _animDuration = frameRate;
+
+ if (wsaObj) {
+ if (x < 0) {
+ drwW += x;
+ drwX = 0;
+ }
+
+ if (y < 0) {
+ drwH += y;
+ drwY = 0;
+ }
+
+ if (x + origW > 319)
+ origW = 320 - x;
+
+ if (y + origH > 199)
+ origW = 200 - y;
+ }
+
+ int8 frameStep = (startFrame > lastFrame) ? -1 : 1;
+ _animCurrentFrame = startFrame;
+
+ while (!_vm->shouldQuit() && !finished) {
+ if (checkAbortPlayback())
+ if (checkPlaybackStatus())
+ break;
+
+ setCountDown(_animDuration);
+
+ if (wsaObj || callback)
+ _screen->copyPage(12, 2);
+
+ int frameIndex = _animCurrentFrame;
+ if (wsaObj)
+ frameIndex %= wsaObj->frames();
+
+ if (callback)
+ (this->*callback)(wsaObj, x, y, frameIndex);
+
+ if (wsaObj)
+ wsaObj->displayFrame(frameIndex, 2, x, y, 0, 0, 0);
+
+ _screen->copyPage(2, 12);
+
+ updateAllNestedAnimations();
+ updateSubTitles();
+
+ if ((wsaObj || callback) && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ }
+
+ while (!_vm->shouldQuit()) {
+ if (checkAbortPlayback())
+ if (checkPlaybackStatus())
+ break;
+
+ if (fadePal1 && fadePal2) {
+ if (!_screen->timedPaletteFadeStep(fadePal1->getData(), fadePal2->getData(), _system->getMillis() - startTime, fadeRate * _vm->tickLength()) && !wsaObj)
+ break;
+ }
+
+ if ((wsaObj || callback) && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ }
+
+ updateSubTitles();
+
+ if (!countDownRunning())
+ break;
+ }
+
+ if (wsaObj) {
+ _animCurrentFrame += frameStep;
+ if ((frameStep > 0 && _animCurrentFrame >= lastFrame) || (frameStep < 0 && _animCurrentFrame < lastFrame))
+ finished = true;
+ }
+
+ if (restoreScreen && (wsaObj || callback)) {
+ _screen->copyPage(12, 2);
+ _screen->copyRegion(drwX, drwY, drwX, drwY, drwW, drwH, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ }
+ }
+}
+
+void SeqPlayer_HOF::playDialogueAnimation(uint16 strID, uint16 soundID, int textColor, int textPosX, int textPosY, int textWidth, WSAMovie_v2 *wsaObj, int animStartFrame, int animLastFrame, int animPosX, int animPosY) {
+ int dur = int(strlen(_sequenceStrings[strID])) * (_vm->gameFlags().isTalkie ? 7 : 15);
+ if (_vm->textEnabled()) {
+ int slot = displaySubTitle(strID, textPosX, textPosY, dur, textWidth);
+ if (slot >= 0)
+ _textSlots[slot].textcolor = textColor;
+ }
+ _specialAnimTimeOutTotal = _system->getMillis() + dur * _vm->tickLength();
+ int curframe = animStartFrame;
+
+ if (soundID && _vm->speechEnabled()) {
+ while (_vm->sound()->voiceIsPlaying() && !_abortPlayback)
+ delayTicks(1);
+ playSoundAndDisplaySubTitle(soundID);
+ }
+
+ while (_system->getMillis() < _specialAnimTimeOutTotal && !_abortPlayback) {
+ if (animLastFrame < 0) {
+ int t = ABS(animLastFrame);
+ if (t < curframe)
+ curframe = t;
+ }
+
+ if (ABS(animLastFrame) < curframe)
+ curframe = animStartFrame;
+
+ _specialAnimFrameTimeOut = _system->getMillis() + _animDuration * _vm->tickLength();
+ setCountDown(_animDuration);
+
+ if (wsaObj)
+ wsaObj->displayFrame(curframe % wsaObj->frames(), 2, animPosX, animPosY, 0, 0, 0);
+
+ _screen->copyPage(2, 12);
+ updateSubTitles();
+ delayUntil(MIN(_specialAnimFrameTimeOut, _specialAnimTimeOutTotal));
+
+ if (_vm->speechEnabled() && !_vm->textEnabled() && !_vm->snd_voiceIsPlaying())
+ break;
+
+ if (checkAbortPlayback())
+ if (checkPlaybackStatus())
+ break;
+
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ curframe++;
+ }
+
+ if (_abortPlayback)
+ _vm->sound()->voiceStop();
+
+ if (ABS(animLastFrame) < curframe)
+ curframe = ABS(animLastFrame);
+
+ if (curframe == animStartFrame)
+ curframe++;
+
+ _animCurrentFrame = curframe;
+}
+
+void SeqPlayer_HOF::startNestedAnimation(int animSlot, int sequenceID) {
+ if (_animSlots[animSlot].flags != -1)
+ return;
+
+ if (_target == kLoLDemo) {
+ return;
+ } else if (_target == kHoFDemo) {
+ assert(sequenceID >= kNestedSequenceHoFDemoWharf2);
+ sequenceID -= kNestedSequenceHoFDemoWharf2;
+ }
+
+ HoFNestedSequence s = _config->nestedSeq[sequenceID];
+
+ if (!_animSlots[animSlot].movie) {
+ _animSlots[animSlot].movie = new WSAMovie_v2(_vm);
+ assert(_animSlots[animSlot].movie);
+ }
+
+ _animSlots[animSlot].movie->close();
+
+ _animSlots[animSlot].movie->open(s.wsaFile, 0, 0);
+
+ if (!_animSlots[animSlot].movie->opened()) {
+ delete _animSlots[animSlot].movie;
+ _animSlots[animSlot].movie = 0;
+ return;
+ }
+
+ _animSlots[animSlot].endFrame = s.endFrame;
+ _animSlots[animSlot].startFrame = _animSlots[animSlot].currentFrame = s.startframe;
+ _animSlots[animSlot].frameDelay = s.frameDelay;
+ _animSlots[animSlot].callback = _config->nestedSeqProc[sequenceID];
+ _animSlots[animSlot].control = s.wsaControl;
+
+ _animSlots[animSlot].flags = s.flags | 1;
+ _animSlots[animSlot].x = s.x;
+ _animSlots[animSlot].y = s.y;
+ _animSlots[animSlot].fadeInTransitionType = s.fadeInTransitionType;
+ _animSlots[animSlot].fadeOutTransitionType = s.fadeOutTransitionType;
+ _animSlots[animSlot].lastFrame = 0xFFFF;
+
+ doNestedFrameTransition(s.fadeInTransitionType, animSlot);
+
+ if (!s.fadeInTransitionType)
+ updateNestedAnimation(animSlot);
+
+ _animSlots[animSlot].nextFrame = _system->getMillis() & ~(_vm->tickLength() - 1);
+}
+
+void SeqPlayer_HOF::closeNestedAnimation(int animSlot) {
+ if (_animSlots[animSlot].flags == -1)
+ return;
+
+ _animSlots[animSlot].flags = -1;
+ doNestedFrameTransition(_animSlots[animSlot].fadeOutTransitionType, animSlot);
+ _animSlots[animSlot].movie->close();
+}
+
+void SeqPlayer_HOF::unloadNestedAnimation(int animSlot) {
+ if (_animSlots[animSlot].movie) {
+ _animSlots[animSlot].movie->close();
+ delete _animSlots[animSlot].movie;
+ _animSlots[animSlot].movie = 0;
+ }
+}
+
+void SeqPlayer_HOF::doNestedFrameTransition(int transitionType, int animSlot) {
+ int xa = 0, ya = 0;
+ transitionType--;
+ if (!_animSlots[animSlot].movie || _abortPlayback || _vm->shouldQuit())
+ return;
+
+ switch (transitionType) {
+ case 0:
+ xa = -_animSlots[animSlot].movie->xAdd();
+ ya = -_animSlots[animSlot].movie->yAdd();
+ _animSlots[animSlot].movie->displayFrame(0, 8, xa, ya, 0, 0, 0);
+ nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
+ _animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 1, 2);
+ break;
+
+ case 1:
+ xa = -_animSlots[animSlot].movie->xAdd();
+ ya = -_animSlots[animSlot].movie->yAdd();
+ _animSlots[animSlot].movie->displayFrame(0, 8, xa, ya, 0, 0, 0);
+ nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
+ _animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 1, 1);
+ break;
+
+ case 2:
+ waitForSubTitlesTimeout();
+ xa = -_animSlots[animSlot].movie->xAdd();
+ ya = -_animSlots[animSlot].movie->yAdd();
+ _animSlots[animSlot].movie->displayFrame(21, 8, xa, ya, 0, 0, 0);
+ nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
+ _animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 0, 2);
+ break;
+
+ case 3:
+ _screen->copyPage(2, 10);
+ _animSlots[animSlot].movie->displayFrame(0, 2, 0, 0, 0, 0, 0);
+ _screen->copyPage(2, 12);
+ nestedFrameFadeTransition("scene2.cmp");
+ break;
+
+ case 4:
+ _screen->copyPage(2, 10);
+ _animSlots[animSlot].movie->displayFrame(0, 2, 0, 0, 0, 0, 0);
+ _screen->copyPage(2, 12);
+ nestedFrameFadeTransition("scene3.cmp");
+ break;
+
+ default:
+ break;
+ }
+}
+
+void SeqPlayer_HOF::updateAllNestedAnimations() {
+ for (int i = 0; i < 8; i++) {
+ if (_animSlots[i].flags != -1) {
+ if (updateNestedAnimation(i))
+ closeNestedAnimation(i);
+ }
+ }
+}
+
+bool SeqPlayer_HOF::updateNestedAnimation(int animSlot) {
+ uint16 currentFrame = _animSlots[animSlot].currentFrame;
+ uint32 curTick = _system->getMillis() & ~(_vm->tickLength() - 1);
+
+ if (_animSlots[animSlot].callback && currentFrame != _animSlots[animSlot].lastFrame) {
+ _animSlots[animSlot].lastFrame = currentFrame;
+ currentFrame = (this->*_animSlots[animSlot].callback)(_animSlots[animSlot].movie, _animSlots[animSlot].x, _animSlots[animSlot].y, currentFrame);
+ }
+
+ if (_animSlots[animSlot].movie) {
+ if (_animSlots[animSlot].flags & 0x20) {
+ _animSlots[animSlot].movie->displayFrame(_animSlots[animSlot].control[currentFrame].index, 2, _animSlots[animSlot].x, _animSlots[animSlot].y, 0x4000, 0, 0);
+ _animSlots[animSlot].frameDelay = _animSlots[animSlot].control[currentFrame].delay;
+ } else {
+ _animSlots[animSlot].movie->displayFrame(currentFrame % _animSlots[animSlot].movie->frames(), 2, _animSlots[animSlot].x, _animSlots[animSlot].y, 0x4000, 0, 0);
+ }
+ }
+
+ if (_animSlots[animSlot].flags & 0x10) {
+ currentFrame = (curTick - _animSlots[animSlot].nextFrame) / (_animSlots[animSlot].frameDelay * _vm->tickLength());
+ } else {
+ int diff = (curTick - _animSlots[animSlot].nextFrame) / (_animSlots[animSlot].frameDelay * _vm->tickLength());
+ if (diff > 0) {
+ currentFrame++;
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+ _animSlots[animSlot].nextFrame += ((curTick - _animSlots[animSlot].nextFrame) * 2 / 3);
+ else
+ _animSlots[animSlot].nextFrame = curTick;
+ }
+ }
+
+ bool res = false;
+
+ if (currentFrame >= _animSlots[animSlot].endFrame) {
+ int sw = ((_animSlots[animSlot].flags & 0x1E) - 2);
+ switch (sw) {
+ case 0:
+ res = true;
+ currentFrame = _animSlots[animSlot].endFrame;
+ _screen->copyPage(2, 12);
+ break;
+
+ case 6:
+ case 8:
+ currentFrame = _animSlots[animSlot].endFrame - 1;
+ break;
+
+ case 2:
+ case 10:
+ currentFrame = _animSlots[animSlot].startFrame;
+ break;
+
+ default:
+ currentFrame = _animSlots[animSlot].endFrame - 1;
+ res = true;
+ }
+ }
+
+ _animSlots[animSlot].currentFrame = currentFrame;
+ return res;
+}
+
+void SeqPlayer_HOF::playSoundEffect(uint16 id, int16 vol) {
+ assert(id < _sequenceSoundListSize);
+ _vm->sound()->voicePlay(_sequenceSoundList[id], 0, vol);
+}
+
+void SeqPlayer_HOF::playSoundAndDisplaySubTitle(uint16 id) {
+ assert(id < _sequenceSoundListSize);
+
+ if (id < 12 && !_vm->gameFlags().isDemo && _vm->textEnabled())
+ displaySubTitle(id, 160, 168, _textDuration[id], 160);
+
+ _vm->sound()->voicePlay(_sequenceSoundList[id], 0);
+}
+
+void SeqPlayer_HOF::printFadingText(uint16 strID, int x, int y, const uint8 *colorMap, uint8 textcolor) {
+ uint8 cmap[16];
+
+ if (checkAbortPlayback())
+ checkPlaybackStatus();
+
+ if (_abortPlayback || _abortRequested || _vm->shouldQuit() || _result)
+ return;
+
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+ _screen->getPalette(0).fill(254, 2, 63);
+ _screen->setPaletteIndex(252, 63, 32, 48);
+ cmap[0] = colorMap[0];
+ cmap[1] = 253;
+ memcpy(&cmap[2], &colorMap[2], 14);
+ uint8 col0 = _textColor[0];
+
+ _textColor[0] = 253;
+ _screen->setTextColorMap(cmap);
+ resetAllTextSlots();
+ displaySubTitle(strID, x, y, 128, 120);
+ updateSubTitles();
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ _screen->getPalette(0).copy(_screen->getPalette(0), textcolor, 1, 253);
+ _screen->fadePalette(_screen->getPalette(0), 24);
+
+ _textColor[0] = textcolor;
+ _screen->setTextColorMap(colorMap);
+ resetAllTextSlots();
+ displaySubTitle(strID, x, y, 128, 120);
+ updateSubTitles();
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ _screen->getPalette(0).fill(253, 1, 0);
+ _screen->fadePalette(_screen->getPalette(0), 1);
+
+ _screen->copyPage(2, 12);
+ resetAllTextSlots();
+
+ _textColor[0] = col0;
+
+ _screen->setFont(of);
+}
+
+int SeqPlayer_HOF::displaySubTitle(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width) {
+ for (int i = 0; i < 10; i++) {
+ if (_textSlots[i].duration != -1) {
+ if (i < 9)
+ continue;
+ else
+ return -1;
+ }
+
+ _textSlots[i].strIndex = strIndex;
+ _textSlots[i].x = posX;
+ _textSlots[i].y = posY;
+ _textSlots[i].duration = duration * _vm->tickLength();
+ _textSlots[i].width = width;
+ _textSlots[i].startTime = _system->getMillis();
+ _textSlots[i].textcolor = -1;
+
+ return i;
+ }
+ return -1;
+}
+
+void SeqPlayer_HOF::updateSubTitles() {
+ int curPage = _screen->setCurPage(2);
+ char outputStr[70];
+
+ for (int i = 0; i < 10; i++) {
+ if (_textSlots[i].startTime + _textSlots[i].duration > _system->getMillis() && _textSlots[i].duration != -1) {
+
+ char *srcStr = preprocessString(_sequenceStrings[_textSlots[i].strIndex], _textSlots[i].width);
+ int yPos = _textSlots[i].y;
+
+ while (*srcStr) {
+ uint32 linePos = 0;
+ for (; *srcStr; linePos++) {
+ if (*srcStr == '\r')
+ break;
+ outputStr[linePos] = *srcStr;
+ srcStr++;
+ }
+ outputStr[linePos] = 0;
+ if (*srcStr == '\r')
+ srcStr++;
+
+ uint8 textColor = (_textSlots[i].textcolor >= 0) ? _textSlots[i].textcolor : _textColor[0];
+ _screen->printText(outputStr, _textSlots[i].x - (_screen->getTextWidth(outputStr) / 2), yPos, textColor, 0);
+ yPos += 10;
+ }
+ } else {
+ _textSlots[i].duration = -1;
+ }
+ }
+
+ _screen->setCurPage(curPage);
+}
+
+char *SeqPlayer_HOF::preprocessString(const char *srcStr, int width) {
+ char *dstStr = _tempString;
+ int lineStart = 0;
+ int linePos = 0;
+
+ while (*srcStr) {
+ while (*srcStr && *srcStr != ' ')
+ dstStr[lineStart + linePos++] = *srcStr++;
+ dstStr[lineStart + linePos] = 0;
+
+ int len = _screen->getTextWidth(&dstStr[lineStart]);
+ if (width >= len && *srcStr) {
+ dstStr[lineStart + linePos++] = *srcStr++;
+ } else {
+ dstStr[lineStart + linePos] = '\r';
+ lineStart += linePos + 1;
+ linePos = 0;
+ if (*srcStr)
+ srcStr++;
+ }
+ }
+ dstStr[lineStart + linePos] = 0;
+
+ return strlen(_tempString) ? dstStr : 0;
+}
+
+void SeqPlayer_HOF::waitForSubTitlesTimeout() {
+ uint32 timeOut = _system->getMillis() + ticksTillSubTitlesTimeout() * _vm->tickLength();
+
+ if (_vm->textEnabled()) {
+ delayUntil(timeOut);
+ } else if (_vm->speechEnabled()) {
+ while (_vm->snd_voiceIsPlaying())
+ delayTicks(1);
+ }
+
+ resetAllTextSlots();
+}
+
+uint32 SeqPlayer_HOF::ticksTillSubTitlesTimeout() {
+ uint32 longest = 0;
+
+ for (int i = 0; i < 10; i++) {
+ uint32 timeOut = (_textSlots[i].duration + _textSlots[i].startTime);
+ uint32 curtime = _system->getMillis();
+ if (_textSlots[i].duration != -1 && timeOut > curtime) {
+ timeOut -= curtime;
+ if (longest < timeOut)
+ longest = timeOut;
+ }
+ }
+
+ uint32 tl = _vm->tickLength();
+ return (longest + (tl - 1)) / tl;
+}
+
+void SeqPlayer_HOF::resetAllTextSlots() {
+ for (int i = 0; i < 10; i++)
+ _textSlots[i].duration = -1;
+}
+
+void SeqPlayer_HOF::fadeOutMusic() {
+ _vm->sound()->beginFadeOut();
+ delayTicks(80);
+}
+
+void SeqPlayer_HOF::playHoFTalkieCredits() {
+ static const uint8 colormap[] = {0, 0, 102, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ static const ScreenDim d = { 0x00, 0x0C, 0x28, 0xB4, 0xFF, 0x00, 0x00, 0x00 };
+
+ _screen->loadBitmap("finale.cps", 3, 3, &_screen->getPalette(0));
+ _screen->setFont(Screen::FID_GOLDFONT_FNT);
+
+ int talkieCreditsSize, talkieCreditsSpecialSize;
+ const uint8 *talkieCredits = _vm->staticres()->loadRawData(k2SeqplayCredits, talkieCreditsSize);
+ const char *const *talkieCreditsSpecial = _vm->staticres()->loadStrings(k2SeqplayCreditsSpecial, talkieCreditsSpecialSize);
+
+ _vm->sound()->selectAudioResourceSet(kMusicIngame);
+ _vm->sound()->loadSoundFile(3);
+ _vm->sound()->playTrack(3);
+
+ _screen->setTextColorMap(colormap);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->updateScreen();
+ _screen->fadeFromBlack();
+
+ _screen->_charWidth = -2;
+ uint8 *dataPtr = new uint8[0xAFD];
+ memcpy(dataPtr, talkieCredits, talkieCreditsSize);
+ _vm->staticres()->unloadId(k2SeqplayCredits);
+
+ displayHoFTalkieScrollText(dataPtr, &d, 2, 6, 5, 1, Screen::FID_GOLDFONT_FNT, Screen::FID_GOLDFONT_FNT, 0, talkieCreditsSpecial);
+ delayTicks(8);
+
+ delete[] dataPtr;
+ _vm->staticres()->unloadId(k2SeqplayCreditsSpecial);
+ _vm->sound()->selectAudioResourceSet(kMusicFinale);
+ _vm->sound()->loadSoundFile(0);
+}
+
+void SeqPlayer_HOF::displayHoFTalkieScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed,
+ int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData, const char *const *specialData) {
+ if (!data)
+ return;
+
+ static const char mark[] = { 5, 13, 0 };
+
+ _screen->clearPage(tempPage1);
+ _screen->clearPage(tempPage2);
+ _screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, 0, tempPage1);
+
+ struct ScrollTextData {
+ int16 x;
+ int16 y;
+ uint8 *text;
+ byte unk1;
+ byte height;
+ byte adjust;
+
+ ScrollTextData() {
+ x = 0; // 0 11
+ y = 0; // 2 13
+ text = 0; // 4 15
+ unk1 = 0; // 8 19
+ height = 0; // 9 20
+ adjust = 0; // 10 21
+ }
+ };
+
+ ScrollTextData *textData = new ScrollTextData[36];
+ uint8 *ptr = data;
+
+ bool loop = true;
+ int cnt = 0;
+
+ while (loop) {
+ uint32 loopEnd = _system->getMillis() + speed * _vm->tickLength();
+
+ while (cnt < 35 && *ptr) {
+ uint16 cH;
+
+ if (cnt)
+ cH = textData[cnt].y + textData[cnt].height + (textData[cnt].height >> 3);
+ else
+ cH = d->h;
+
+ char *str = (char *)ptr;
+
+ ptr = (uint8 *)strpbrk(str, mark);
+ if (!ptr)
+ ptr = (uint8 *)strchr(str, 0);
+
+ textData[cnt + 1].unk1 = *ptr;
+ *ptr = 0;
+ if (textData[cnt + 1].unk1)
+ ptr++;
+
+ if (*str == 3 || *str == 4)
+ textData[cnt + 1].adjust = *str++;
+ else
+ textData[cnt + 1].adjust = 0;
+
+ _screen->setFont(fid1);
+
+ if (*str == 1) {
+ _screen->setFont(fid2);
+ str++;
+ } else if (*str == 2) {
+ str++;
+ }
+
+ textData[cnt + 1].height = _screen->getFontHeight();
+
+ switch (textData[cnt + 1].adjust) {
+ case 3:
+ textData[cnt + 1].x = 157 - _screen->getTextWidth(str);
+ break;
+ case 4:
+ textData[cnt + 1].x = 161;
+ break;
+ default:
+ textData[cnt + 1].x = (((d->w << 3) - _screen->getTextWidth(str)) >> 1) + 1;
+ }
+
+ if (textData[cnt].unk1 == 5)
+ cH -= (textData[cnt].height + (textData[cnt].height >> 3));
+
+ textData[cnt + 1].y = cH;
+ textData[cnt + 1].text = (uint8 *)str;
+ cnt++;
+ }
+
+ _screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage1, tempPage2);
+
+ int cnt2 = 0;
+ bool palCycle = 0;
+
+ while (cnt2 < cnt) {
+ const char *str = (const char *)textData[cnt2 + 1].text;
+ const char *str2 = str;
+ int16 cW = textData[cnt2 + 1].x - 10;
+ int16 cH = textData[cnt2 + 1].y;
+ int x = (d->sx << 3) + cW;
+ int y = d->sy + cH;
+ int col1 = 255;
+
+ if (cH < d->h) {
+ _screen->setCurPage(tempPage2);
+ _screen->setFont(fid1);
+ if (textData[cnt2 + 1].height != _screen->getFontHeight())
+ _screen->setFont(fid2);
+
+ if (specialData) {
+ if (!strcmp(str, specialData[0])) {
+ col1 = 112;
+ char cChar[2] = " ";
+ while (*str2) {
+ cChar[0] = *str2;
+ _screen->printText(cChar, x, y, col1++, 0);
+ x += _screen->getCharWidth((uint8)*str2++);
+ }
+ palCycle = true;
+ } else if (!strcmp(str, specialData[1])) {
+ col1 = 133;
+ char cChar[2] = " ";
+ while (*str2) {
+ cChar[0] = *str2;
+ _screen->printText(cChar, x, y, col1--, 0);
+ x += _screen->getCharWidth((uint8)*str2++);
+ }
+ palCycle = true;
+ } else {
+ _screen->printText(str, x, y, col1, 0);
+ }
+ } else {
+ _screen->printText(str, x, y, col1, 0);
+ }
+ _screen->setCurPage(0);
+ }
+
+ textData[cnt2 + 1].y -= step;
+ cnt2++;
+ }
+
+ _screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage2, 0);
+ _screen->updateScreen();
+
+ if (textData[1].y < -10) {
+ textData[1].text += strlen((char *)textData[1].text);
+ textData[1].text[0] = textData[1].unk1;
+ cnt--;
+ memmove(&textData[1], &textData[2], cnt * sizeof(ScrollTextData));
+ }
+
+ if (palCycle) {
+ for (int col = 133; col > 112; col--)
+ _screen->getPalette(0).copy(_screen->getPalette(0), col - 1, 1, col);
+ _screen->getPalette(0).copy(_screen->getPalette(0), 133, 1, 112);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+
+ delayUntil(loopEnd);
+
+ if ((cnt < 36) && ((d->sy + d->h) > (textData[cnt].y + textData[cnt].height)) && !_abortPlayback) {
+ delayTicks(500);
+ cnt = 0;
+ }
+
+ if (checkAbortPlayback())
+ if (checkPlaybackStatus())
+ loop = false;
+
+ if (!cnt || _abortPlayback)
+ loop = false;
+ }
+
+ _vm->sound()->beginFadeOut();
+ _screen->fadeToBlack();
+
+ _abortPlayback = _abortRequested = false;
+
+ delete[] textData;
+}
+
+void SeqPlayer_HOF::updateDemoAdText(int bottom, int top) {
+ int dstY, dstH, srcH;
+
+ static const ScreenDim d = { 0x00, 0x00, 0x28, 0x320, 0xFF, 0xFE, 0x00, 0x00 };
+
+ if (_scrollProgressCounter - (top - 1) < 0) {
+ dstY = top - _scrollProgressCounter;
+ dstH = _scrollProgressCounter;
+ srcH = 0;
+ } else {
+ dstY = 0;
+ srcH = _scrollProgressCounter - top;
+ dstH = (400 - srcH <= top) ? 400 - srcH : top;
+ }
+
+ if (dstH > 0) {
+ if (_hofDemoAnimData) {
+ for (int i = 0; i < 4; i++) {
+ const HoFSeqItemAnimData *def = &_hofDemoAnimData[i];
+ ActiveItemAnim *a = &_hofDemoActiveItemAnim[i];
+
+ _screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4);
+ _screen->drawShape(4, _hofDemoItemShapes[def->itemIndex + def->frames[a->currentFrame]], 12, def->y - 8, 0, 0);
+ if (_callbackCurrentFrame % 2 == 0)
+ a->currentFrame = (a->currentFrame + 1) % 20;
+ }
+ }
+ _screen->copyRegionEx(4, 0, srcH, 2, 2, dstY + bottom, 320, dstH, &d);
+ }
+}
+
+void SeqPlayer_HOF::delayTicks(uint32 ticks) {
+ uint32 len = ticks * _vm->tickLength();
+ while (len && !_vm->shouldQuit() && !checkAbortPlayback()) {
+ uint32 step = (len >= 10) ? 10 : len;
+ _system->delayMillis(step);
+ len -= step;
+ }
+}
+
+void SeqPlayer_HOF::delayUntil(uint32 dest) {
+ for (uint32 ct = _system->getMillis(); ct < dest && !_vm->shouldQuit() && !checkAbortPlayback(); ) {
+ uint32 step = (dest - ct >= 10) ? 10 : (dest - ct);
+ _system->delayMillis(step);
+ ct = _system->getMillis();
+ }
+}
+
+void SeqPlayer_HOF::setCountDown(uint32 ticks) {
+ _countDownRemainder = ticks * _vm->tickLength();
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+ _countDownRemainder = _countDownRemainder * 2 / 3;
+ _countDownLastUpdate = _system->getMillis() & ~(_vm->tickLength() - 1);
+}
+
+bool SeqPlayer_HOF::countDownRunning() {
+ uint32 cur = _system->getMillis();
+ uint32 step = cur - _countDownLastUpdate;
+ _countDownLastUpdate = cur;
+ _countDownRemainder = (step <= _countDownRemainder) ? _countDownRemainder - step : 0;
+ return _countDownRemainder;
+}
+
+#define CASE_ALT(dosCase, towns98Case)\
+ case dosCase:\
+ case towns98Case:\
+ if (!((_callbackCurrentFrame == towns98Case && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == dosCase && _vm->gameFlags().platform == Common::kPlatformDOS)))\
+ break;
+
+int SeqPlayer_HOF::cbHOF_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == -2) {
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+ delayTicks(300);
+ } else if (!frm) {
+ _vm->sound()->playTrack(2);
+ }
+
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_title(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 1) {
+ _vm->sound()->playTrack(3);
+ } else if (frm == 25 && _startupSaveLoadable) {
+ int cp = _screen->setCurPage(0);
+ _screen->showMouse();
+ _system->updateScreen();
+ _result = _menu->handle(11) + 1;
+ _updateAnimations = false;
+
+ if (_result == 1 || _result == 3) {
+ _curScene = _lastScene;
+ _preventLooping = true;
+ }
+
+ if (_result == 2) {
+ _result = 0;
+ } else if (_result == 4) {
+ setCountDown(200);
+ _vm->quitGame();
+ }
+
+ _screen->hideMouse();
+ _screen->setCurPage(cp);
+ } else if (frm == 25) {
+ setCountDown(200);
+ }
+
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint8 *tmpPal = _screen->getPalette(3).getData() + 0x101;
+ memset(tmpPal, 0, 256);
+ uint32 frameEnd = 0;
+
+ switch (_callbackCurrentFrame) {
+ case 0:
+ _updateAnimations = true;
+ fadeOutMusic();
+ _vm->sound()->playTrack(4);
+ frameEnd = _system->getMillis() + 60 * _vm->tickLength();
+
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xFF;
+ _screen->setTextColorMap(_textColorMap);
+
+ delayUntil(frameEnd);
+ break;
+
+ case 1:
+ assert(_screenHoF);
+ _screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x40, 0, 0, 0, 0x100, true);
+ for (int i = 0; i < 256; i++)
+ tmpPal[_screen->getPalette(3)[i]] = 1;
+
+ for (int i = 0; i < 256; i++) {
+ int v = (tmpPal[i] == 1) ? i : _screen->getPalette(3)[i];
+ v *= 3;
+ _screen->getPalette(2)[3 * i] = _screen->getPalette(0)[v];
+ _screen->getPalette(2)[3 * i + 1] = _screen->getPalette(0)[v + 1];
+ _screen->getPalette(2)[3 * i + 2] = _screen->getPalette(0)[v + 2];
+ }
+ break;
+
+ case 40:
+ startNestedAnimation(0, kNestedSequenceOver1);
+ break;
+
+ case 60:
+ startNestedAnimation(1, kNestedSequenceOver2);
+ break;
+
+ case 120:
+ playSoundAndDisplaySubTitle(0);
+ break;
+
+ case 200:
+ waitForSubTitlesTimeout();
+ _screen->fadePalette(_screen->getPalette(2), 64);
+ break;
+
+ case 201:
+ _screen->setScreenPalette(_screen->getPalette(2));
+ _screen->updateScreen();
+ _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3).getData());
+ _screen->copyPage(2, 12);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->updateScreen();
+ closeNestedAnimation(0);
+ closeNestedAnimation(1);
+ break;
+
+ case 282:
+ startNestedAnimation(0, kNestedSequenceForest);
+ playSoundAndDisplaySubTitle(1);
+ break;
+
+ CASE_ALT(434, 354)
+ closeNestedAnimation(0);
+ startNestedAnimation(0, kNestedSequenceDragon);
+ break;
+
+ CASE_ALT(540, 400)
+ waitForSubTitlesTimeout();
+ closeNestedAnimation(0);
+ setCountDown(0);
+ _updateAnimations = false;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_library(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (_callbackCurrentFrame) {
+ case 0:
+ _updateAnimations = true;
+ _vm->sound()->playTrack(5);
+
+ assert(_screenHoF);
+ _screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xFF;
+
+ _screen->setTextColorMap(_textColorMap);
+ break;
+
+ case 1:
+ startNestedAnimation(0, kNestedSequenceLibrary3);
+ playSoundAndDisplaySubTitle(4);
+ break;
+
+ case 100:
+ waitForSubTitlesTimeout();
+
+ _screen->copyPage(12, 2);
+ _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3).getData());
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->updateScreen();
+ _screen->copyPage(2, 12);
+
+ closeNestedAnimation(0);
+ startNestedAnimation(0, kNestedSequenceDarm);
+ break;
+
+ case 104:
+ playSoundAndDisplaySubTitle(5);
+ break;
+
+ case 240:
+ waitForSubTitlesTimeout();
+ closeNestedAnimation(0);
+ startNestedAnimation(0, kNestedSequenceLibrary2);
+ break;
+
+ case 340:
+ closeNestedAnimation(0);
+ _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3).getData());
+ _screen->copyPage(2, 12);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->updateScreen();
+
+ startNestedAnimation(0, kNestedSequenceMarco);
+ playSoundAndDisplaySubTitle(6);
+ break;
+
+ CASE_ALT(660, 480)
+ _screen->copyPage(2, 12);
+ waitForSubTitlesTimeout();
+ closeNestedAnimation(0);
+ setCountDown(0);
+ _updateAnimations = false;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_hand(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (_callbackCurrentFrame) {
+ case 0:
+ _updateAnimations = true;
+ _vm->sound()->playTrack(6);
+
+ assert(_screenHoF);
+ _screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xFF;
+
+ _screen->setTextColorMap(_textColorMap);
+ break;
+
+ case 1:
+ startNestedAnimation(0, kNestedSequenceHand1a);
+ startNestedAnimation(1, kNestedSequenceHand1b);
+ startNestedAnimation(2, kNestedSequenceHand1c);
+ playSoundAndDisplaySubTitle(7);
+ break;
+
+ case 201:
+ waitForSubTitlesTimeout();
+ _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3).getData());
+ _screen->copyPage(2, 12);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->updateScreen();
+ closeNestedAnimation(0);
+ closeNestedAnimation(1);
+ closeNestedAnimation(2);
+ startNestedAnimation(0, kNestedSequenceHand2);
+ playSoundAndDisplaySubTitle(8);
+ break;
+
+ CASE_ALT(395, 260)
+ waitForSubTitlesTimeout();
+ closeNestedAnimation(0);
+ startNestedAnimation(1, kNestedSequenceHand3);
+ playSoundAndDisplaySubTitle(9);
+ break;
+
+ CASE_ALT(500, 365)
+ waitForSubTitlesTimeout();
+ closeNestedAnimation(1);
+ startNestedAnimation(0, kNestedSequenceHand4);
+ break;
+
+ CASE_ALT(540, 405)
+ playSoundAndDisplaySubTitle(10);
+ break;
+
+ CASE_ALT(630, 484)
+ waitForSubTitlesTimeout();
+ closeNestedAnimation(0);
+ setCountDown(0);
+ _updateAnimations = false;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_point(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == -2) {
+ waitForSubTitlesTimeout();
+ setCountDown(0);
+ }
+
+ switch (_callbackCurrentFrame) {
+ case -2:
+ waitForSubTitlesTimeout();
+ break;
+
+ case 0:
+ _vm->sound()->playTrack(7);
+
+ _textColor[1] = 0xF7;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xFF;
+ _screen->setTextColorMap(_textColorMap);
+ assert(_screenHoF);
+ _screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
+ break;
+
+ case 1:
+ playSoundAndDisplaySubTitle(11);
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == -2) {
+ waitForSubTitlesTimeout();
+ setCountDown(0);
+ return 0;
+ }
+
+ switch (_callbackCurrentFrame) {
+ case 0:
+ _vm->sound()->playTrack(8);
+
+ _textColor[1] = 0xFD;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xFF;
+ _screen->setTextColorMap(_textColorMap);
+ break;
+
+ case 1:
+ if (_vm->gameFlags().isTalkie) {
+ playDialogueAnimation(21, 13, -1, 140, 70, 160, wsaObj, 0, 8, x, y);
+ } else {
+ displaySubTitle(21, 140, 70, 200, 160);
+ _animDuration = 200;
+ }
+ break;
+
+ case 2:
+ case 11:
+ case 21:
+ if (!_vm->gameFlags().isTalkie)
+ _animDuration = 12;
+ break;
+
+ case 9:
+ if (_vm->gameFlags().isTalkie)
+ playDialogueAnimation(13, 14, -1, 140, (_vm->gameFlags().lang == Common::FR_FRA
+ || _vm->gameFlags().lang == Common::DE_DEU) ? 50 : 70, 160, wsaObj, 9, 15, x, y);
+ break;
+
+ case 10:
+ if (!_vm->gameFlags().isTalkie) {
+ waitForSubTitlesTimeout();
+ displaySubTitle(13, 140, 50, _textDuration[13], 160);
+ _animDuration = 300;
+ }
+ break;
+
+ case 16:
+ if (_vm->gameFlags().isTalkie)
+ playDialogueAnimation(18, 15, -1, 140, (_vm->gameFlags().lang == Common::FR_FRA) ? 50 :
+ (_vm->gameFlags().lang == Common::DE_DEU ? 40 : 70), 160, wsaObj, 10, 16, x, y);
+ break;
+
+ case 17:
+ if (_vm->gameFlags().isTalkie)
+ _animDuration = 12;
+ break;
+
+ case 20:
+ if (!_vm->gameFlags().isTalkie) {
+ waitForSubTitlesTimeout();
+ displaySubTitle(18, 160, 50, _textDuration[18], 160);
+ _animDuration = 200;
+ }
+ break;
+
+ case 26:
+ waitForSubTitlesTimeout();
+ break;
+
+ case 46:
+ if (_vm->gameFlags().isTalkie) {
+ playDialogueAnimation(16, 16, -1, 200, 50, 120, wsaObj, 46, 46, x, y);
+ } else {
+ waitForSubTitlesTimeout();
+ displaySubTitle(16, 200, 50, _textDuration[16], 120);
+ }
+
+ setCountDown(120);
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_over1(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 2)
+ waitForSubTitlesTimeout();
+ else if (frm == 3)
+ playSoundAndDisplaySubTitle(12);
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_over2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 1)
+ playSoundAndDisplaySubTitle(12);
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_forest(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 11)
+ waitForSubTitlesTimeout();
+ else if (frm == 12)
+ playSoundAndDisplaySubTitle(2);
+
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_dragon(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 11)
+ waitForSubTitlesTimeout();
+ else if (frm == 3)
+ playSoundAndDisplaySubTitle(3);
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_darm(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_library2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_marco(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 36) {
+ waitForSubTitlesTimeout();
+ setCountDown(0);
+ }
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_hand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_hand1b(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 15)
+ frm = 12;
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_hand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 8)
+ frm = 4;
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_hand2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_hand3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint32 frameEnd = 0;
+ int subTitleX = 0;
+ int subTitleY = 0;
+ int subTitleW = 0;
+ int subTitleFirstFrame = 0;
+ int subTitleLastFrame = 0;
+ uint16 voiceIndex = 0;
+
+ switch (frm) {
+ case -2:
+ doTransition(9);
+ break;
+
+ case 0:
+ _vm->sound()->playTrack(3);
+
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColor[0] = _textColorMap[1] = 0xFF;
+ _screen->setTextColorMap(_textColorMap);
+
+ frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+ printFadingText(81, 240, 70, _textColorMap, 252);
+ printFadingText(82, 240, 90, _textColorMap, _textColor[0]);
+ _screen->copyPage(2, 12);
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 28 : 24);
+ delayUntil(frameEnd);
+ _textColor[0] = 1;
+
+ if (_vm->gameFlags().isTalkie) {
+ subTitleY = (_vm->gameFlags().lang == Common::FR_FRA) ? 70 : 78;
+ subTitleFirstFrame = 9;
+ subTitleLastFrame = 15;
+ voiceIndex = 34;
+ } else {
+ subTitleY = (_vm->gameFlags().lang == Common::FR_FRA) ? 78 : 70;
+ subTitleFirstFrame = 0;
+ subTitleLastFrame = 8;
+ }
+ subTitleX = (_vm->gameFlags().lang == Common::FR_FRA) ? 84 : 88;
+ subTitleW = 100;
+
+ playDialogueAnimation(22, voiceIndex, 187, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
+ break;
+
+ case 9:
+ case 16:
+ if (!((frm == 9 && !_vm->gameFlags().isTalkie) || (frm == 16 && _vm->gameFlags().isTalkie)))
+ break;
+
+ _animDuration = 12;
+
+ if (_vm->gameFlags().lang == Common::FR_FRA) {
+ subTitleX = 80;
+ subTitleW = 112;
+ } else {
+ subTitleX = (_vm->gameFlags().lang == Common::DE_DEU) ? 84 : 96;
+ subTitleW = 100;
+ }
+
+ if (_vm->gameFlags().isTalkie) {
+ subTitleFirstFrame = 0;
+ subTitleLastFrame = 8;
+ voiceIndex = 35;
+ } else {
+ subTitleFirstFrame = 9;
+ subTitleLastFrame = 15;
+ }
+ subTitleY = 70;
+
+ playDialogueAnimation(23, voiceIndex, 137, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
+ if (_vm->gameFlags().isTalkie)
+ _animCurrentFrame = 17;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_ferb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint32 frameEnd = 0;
+ int subTitleX = 0;
+ int subTitleY = 0;
+ int subTitleW = 0;
+ int subTitleFirstFrame = 0;
+ int subTitleLastFrame = 0;
+ uint16 voiceIndex = 0;
+
+ switch (frm) {
+ case -2:
+ doTransition(9);
+ frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+ printFadingText(34, 240, _vm->gameFlags().isTalkie ? 60 : 40, _textColorMap, 252);
+ printFadingText(35, 240, _vm->gameFlags().isTalkie ? 70 : 50, _textColorMap, _textColor[0]);
+ printFadingText(36, 240, _vm->gameFlags().isTalkie ? 90 : 70, _textColorMap, 252);
+ printFadingText(37, 240, _vm->gameFlags().isTalkie ? 100 : 90, _textColorMap, _textColor[0]);
+ printFadingText(38, 240, _vm->gameFlags().isTalkie ? 120 : 110, _textColorMap, 252);
+ printFadingText(39, 240, _vm->gameFlags().isTalkie ? 130 : 120, _textColorMap, _textColor[0]);
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+ printFadingText(103, 240, 130, _textColorMap, _textColor[0]);
+ delayUntil(frameEnd);
+ setCountDown(0);
+ break;
+
+ case 0:
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColor[0] = _textColorMap[1] = 255;
+ _screen->setTextColorMap(_textColorMap);
+ break;
+
+ case 5:
+ if (!_vm->gameFlags().isTalkie)
+ playSoundAndDisplaySubTitle(18);
+ _animDuration = 16;
+
+ if (_vm->gameFlags().isTalkie) {
+ subTitleFirstFrame = 5;
+ subTitleLastFrame = 8;
+ voiceIndex = 22;
+ } else {
+ subTitleLastFrame = 14;
+ }
+ subTitleX = 116;
+ subTitleY = 90;
+ subTitleW = 60;
+
+ playDialogueAnimation(24, voiceIndex, 149, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
+ break;
+
+ case 11:
+ if (_vm->gameFlags().isTalkie)
+ playDialogueAnimation(24, 22, 149, 116, 90, 60, wsaObj, 11, 14, x, y);
+ break;
+
+ case 16:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 23 : 19);
+ _animDuration = _vm->gameFlags().isTalkie ? 20 : 16;
+
+ if (_vm->gameFlags().lang == Common::FR_FRA) {
+ subTitleY = 48;
+ subTitleW = 88;
+ } else {
+ subTitleY = 60;
+ subTitleW = 100;
+ }
+ subTitleX = 60;
+
+ if (_vm->gameFlags().isTalkie)
+ voiceIndex = 36;
+
+ playDialogueAnimation(25, voiceIndex, 143, subTitleX, subTitleY, subTitleW, wsaObj, 16, 25, x, y);
+ _animDuration = 16;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_fish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint32 frameEnd = 0;
+ int subTitleX = 0;
+ int subTitleY = 0;
+ int subTitleW = 0;
+ uint16 voiceIndex = 0;
+
+ switch (frm) {
+ case -2:
+ doTransition(9);
+ frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+
+ printFadingText(40, 240, _vm->gameFlags().isTalkie ? 55 : 40, _textColorMap, 252);
+ printFadingText(41, 240, _vm->gameFlags().isTalkie ? 65 : 50, _textColorMap, _textColor[0]);
+ printFadingText(42, 240, _vm->gameFlags().isTalkie ? 75 : 60, _textColorMap, _textColor[0]);
+ printFadingText(43, 240, _vm->gameFlags().isTalkie ? 95 : 80, _textColorMap, 252);
+ printFadingText(44, 240, _vm->gameFlags().isTalkie ? 105 : 90, _textColorMap, _textColor[0]);
+ printFadingText(93, 240, _vm->gameFlags().isTalkie ? 125 : 110, _textColorMap, 252);
+ printFadingText(94, 240, _vm->gameFlags().isTalkie ? 135 : 120, _textColorMap, _textColor[0]);
+ delayUntil(frameEnd);
+ setCountDown(0);
+ break;
+
+ case 0:
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColor[0] = _textColorMap[1] = 0xFF;
+ _screen->setTextColorMap(_textColorMap);
+ break;
+
+ case 4:
+ subTitleX = 94;
+ subTitleY = 42;
+ subTitleW = 100;
+ if (_vm->gameFlags().isTalkie)
+ voiceIndex = 37;
+ playDialogueAnimation(26, voiceIndex, 149, subTitleX, subTitleY, subTitleW, wsaObj, 3, 12, x, y);
+ break;
+
+ case 14:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 19 : 15);
+ break;
+
+ case 23:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 20 : 16);
+ break;
+
+ case 29:
+ subTitleX = (_vm->gameFlags().lang == Common::DE_DEU) ? 82 : ((_vm->gameFlags().lang == Common::FR_FRA) ? 92 : 88);
+ subTitleY = 40;
+ subTitleW = 100;
+
+ if (_vm->gameFlags().isTalkie) {
+ if (_vm->gameFlags().lang == Common::DE_DEU)
+ subTitleY = 35;
+ voiceIndex = 38;
+ }
+
+ playDialogueAnimation(27, voiceIndex, 187, subTitleX, subTitleY, subTitleW, wsaObj, 28, 34, x, y);
+ break;
+
+ case 45:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 21 : 17);
+ break;
+
+ case 50:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 29 : 25);
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_fheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint32 frameEnd = 0;
+ int subTitleX = 0;
+ int subTitleY = 0;
+ int subTitleW = 0;
+ int subTitleFirstFrame = 0;
+ int subTitleLastFrame = 0;
+ uint16 voiceIndex = 0;
+
+ switch (frm) {
+ case -2:
+ _screen->copyPage(12, 2);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ doTransition(9);
+ frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+ printFadingText(49, 240, 20, _textColorMap, 252);
+ printFadingText(50, 240, 30, _textColorMap, _textColor[0]);
+ printFadingText(51, 240, 40, _textColorMap, _textColor[0]);
+ printFadingText(52, 240, 50, _textColorMap, _textColor[0]);
+ printFadingText(53, 240, 60, _textColorMap, _textColor[0]);
+ printFadingText(54, 240, 70, _textColorMap, _textColor[0]);
+ printFadingText(55, 240, 80, _textColorMap, _textColor[0]);
+ printFadingText(56, 240, 90, _textColorMap, _textColor[0]);
+ printFadingText(57, 240, 100, _textColorMap, _textColor[0]);
+ printFadingText(58, 240, 110, _textColorMap, _textColor[0]);
+ printFadingText(60, 240, 120, _textColorMap, _textColor[0]);
+ printFadingText(61, 240, 130, _textColorMap, _textColor[0]);
+ printFadingText(62, 240, 140, _textColorMap, _textColor[0]);
+ printFadingText(63, 240, 150, _textColorMap, _textColor[0]);
+ printFadingText(64, 240, 160, _textColorMap, _textColor[0]);
+
+ delayUntil(frameEnd);
+ setCountDown(0);
+ break;
+
+ case 0:
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColor[0] = _textColorMap[1] = 0xFF;
+ _screen->setTextColorMap(_textColorMap);
+ break;
+
+ case 2:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 25 : 21);
+
+ if (_vm->gameFlags().lang == Common::FR_FRA) {
+ subTitleX = 92;
+ subTitleY = 72;
+ } else {
+ subTitleX = (_vm->gameFlags().lang == Common::DE_DEU) ? 90 : 98;
+ subTitleY = 84;
+ }
+
+ if (_vm->gameFlags().isTalkie) {
+ subTitleFirstFrame = 8;
+ subTitleLastFrame = 9;
+ voiceIndex = 39;
+ } else {
+ subTitleFirstFrame = 2;
+ subTitleLastFrame = -8;
+ }
+ subTitleW = 100;
+
+ playDialogueAnimation(28, voiceIndex, -1, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
+ if (_vm->gameFlags().isTalkie)
+ _animCurrentFrame = 4;
+ break;
+
+ case 9:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 24 : 20);
+ _animDuration = 100;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_farmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint32 frameEnd = 0;
+ int subTitleX = 0;
+ int subTitleY = 0;
+ int subTitleW = 0;
+ uint16 voiceIndex = 0;
+
+ switch (frm) {
+ case -2:
+ _screen->copyPage(12, 2);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ doTransition(9);
+ frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+ printFadingText(45, 240, 40, _textColorMap, 252);
+ printFadingText(46, 240, 50, _textColorMap, _textColor[0]);
+ printFadingText(47, 240, 60, _textColorMap, _textColor[0]);
+ printFadingText(83, 240, 80, _textColorMap, 252);
+ printFadingText(48, 240, 90, _textColorMap, _textColor[0]);
+ printFadingText(65, 240, 110, _textColorMap, 252);
+ printFadingText(66, 240, 120, _textColorMap, _textColor[0]);
+ printFadingText(67, 240, 130, _textColorMap, _textColor[0]);
+ printFadingText(68, 240, 140, _textColorMap, _textColor[0]);
+ printFadingText(69, 240, 150, _textColorMap, _textColor[0]);
+ if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+ printFadingText(104, 240, 160, _textColorMap, _textColor[0]);
+ delayUntil(frameEnd);
+ setCountDown(0);
+ break;
+
+ case 0:
+ _textColor[1] = 1 + (_screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 254) & 0xFF);
+ memset(_textColorMap, _textColor[1], 16);
+ _textColorMap[1] = _textColor[0] = 1 + (_screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 254) & 0xFF);
+ _screen->setTextColorMap(_textColorMap);
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 30 : 26);
+ break;
+
+ case 6:
+ if (_vm->gameFlags().isTalkie)
+ playSoundAndDisplaySubTitle(18);
+ break;
+
+ case 12:
+ if (!_vm->gameFlags().isTalkie)
+ playSoundAndDisplaySubTitle(14);
+
+ subTitleX = 90;
+ subTitleY = 30;
+ subTitleW = 100;
+
+ if (_vm->gameFlags().isTalkie) {
+ if (_vm->gameFlags().lang == Common::FR_FRA || _vm->gameFlags().lang == Common::DE_DEU) {
+ subTitleX = 75;
+ subTitleY = 25;
+ }
+ voiceIndex = 40;
+ }
+
+ playDialogueAnimation(29, voiceIndex, 150, subTitleX, subTitleY, subTitleW, wsaObj, 12, -21, x, y);
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint32 frameEnd = 0;
+ int subTitleX = 0;
+ int subTitleY = 0;
+ int subTitleW = 0;
+ int subTitleFirstFrame = 0;
+ int subTitleLastFrame = 0;
+
+ uint16 voiceIndex = 0;
+
+ switch (frm) {
+ case -2:
+ doTransition(9);
+ frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+ printFadingText(70, 240, 20, _textColorMap, 252);
+ printFadingText(71, 240, 30, _textColorMap, _textColor[0]);
+ printFadingText(72, 240, 40, _textColorMap, _textColor[0]);
+ printFadingText(73, 240, 50, _textColorMap, _textColor[0]);
+ printFadingText(74, 240, 60, _textColorMap, _textColor[0]);
+ printFadingText(75, 240, 70, _textColorMap, _textColor[0]);
+ printFadingText(101, 240, 80, _textColorMap, _textColor[0]);
+ printFadingText(102, 240, 90, _textColorMap, _textColor[0]);
+ printFadingText(87, 240, 100, _textColorMap, _textColor[0]);
+ printFadingText(88, 240, 110, _textColorMap, _textColor[0]);
+ printFadingText(89, 240, 120, _textColorMap, _textColor[0]);
+ printFadingText(90, 240, 130, _textColorMap, _textColor[0]);
+ printFadingText(91, 240, 140, _textColorMap, _textColor[0]);
+ printFadingText(92, 240, 150, _textColorMap, _textColor[0]);
+ delayUntil(frameEnd);
+ setCountDown(0);
+ break;
+
+ case 0:
+ for (int i = 0; i < 0x300; i++)
+ _screen->getPalette(0)[i] &= 0x3F;
+ _textColor[1] = 0xCf;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColor[0] = _textColorMap[1] = 0xFE;
+
+ _screen->setTextColorMap(_textColorMap);
+ break;
+
+ case 6:
+ _animDuration = 20;
+
+ if (_vm->gameFlags().isTalkie) {
+ subTitleX = 82;
+ subTitleFirstFrame = 16;
+ subTitleLastFrame = 21;
+ voiceIndex = 41;
+ } else {
+ subTitleX = 62;
+ subTitleFirstFrame = 9;
+ subTitleLastFrame = 13;
+ }
+ subTitleY = (_vm->gameFlags().lang == Common::FR_FRA || _vm->gameFlags().lang == Common::DE_DEU) ? 88 :100;
+ subTitleW = 80;
+
+ playDialogueAnimation(30, voiceIndex, 137, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
+ if (_vm->gameFlags().isTalkie)
+ _animCurrentFrame = 8;
+ break;
+
+ case 9:
+ case 16:
+ if (_vm->gameFlags().isTalkie) {
+ if (frm == 16)
+ break;
+ subTitleX = 64;
+ subTitleFirstFrame = 9;
+ subTitleLastFrame = 13;
+ voiceIndex = 42;
+ } else {
+ if (frm == 9)
+ break;
+ subTitleX = 80;
+ subTitleFirstFrame = 16;
+ subTitleLastFrame = 21;
+ }
+ subTitleY = 100;
+ subTitleW = 100;
+
+ playDialogueAnimation(31, voiceIndex, 143, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
+ if (_vm->gameFlags().isTalkie)
+ _animCurrentFrame = 21;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_firates(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ uint32 frameEnd = 0;
+ int subTitleX = 0;
+ int subTitleY = 0;
+ int subTitleW = 0;
+ uint16 voiceIndex = 0;
+
+ switch (frm) {
+ case -2:
+ _screen->copyPage(12, 2);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ doTransition(9);
+ frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+ printFadingText(76, 240, 40, _textColorMap, 252);
+ printFadingText(77, 240, 50, _textColorMap, 252);
+ printFadingText(78, 240, 60, _textColorMap, _textColor[0]);
+ printFadingText(79, 240, 70, _textColorMap, _textColor[0]);
+ printFadingText(80, 240, 80, _textColorMap, _textColor[0]);
+ printFadingText(84, 240, 100, _textColorMap, 252);
+ printFadingText(85, 240, 110, _textColorMap, _textColor[0]);
+ printFadingText(99, 240, 130, _textColorMap, 252);
+ printFadingText(100, 240, 140, _textColorMap, _textColor[0]);
+ delayUntil(frameEnd);
+ setCountDown(0);
+ break;
+
+ case 0:
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColor[0] = _textColorMap[1] = 0xFF;
+ _screen->setTextColorMap(_textColorMap);
+ break;
+
+ case 6:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 31 : 27);
+ break;
+
+ case 14:
+ case 15:
+ if (!((frm == 15 && !_vm->gameFlags().isTalkie) || (frm == 14 && _vm->gameFlags().isTalkie)))
+ break;
+
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 31 : 27);
+
+ if (_vm->gameFlags().lang == Common::DE_DEU) {
+ subTitleX = 82;
+ subTitleY = 84;
+ subTitleW = 140;
+ } else {
+ subTitleX = 74;
+ subTitleY = (_vm->gameFlags().lang == Common::FR_FRA) ? 96: 108;
+ subTitleW = 80;
+ }
+
+ if (_vm->gameFlags().isTalkie)
+ voiceIndex = 43;
+
+ playDialogueAnimation(32, voiceIndex, 137, subTitleX, subTitleY, subTitleW, wsaObj, 14, 16, x, y);
+ break;
+
+ case 28:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 32 : 28);
+ break;
+
+ case 29:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 33 : 29);
+ break;
+
+ case 31:
+ if (_vm->gameFlags().isTalkie)
+ voiceIndex = 44;
+
+ subTitleX = 90;
+ subTitleY = (_vm->gameFlags().lang == Common::DE_DEU) ? 60 : 76;
+ subTitleW = 80;
+
+ playDialogueAnimation(33, voiceIndex, 143, subTitleX, subTitleY, subTitleW, wsaObj, 31, 34, x, y);
+ break;
+
+ case 35:
+ _animDuration = 300;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ int tmp = 0;
+
+ switch (frm) {
+ case -2:
+ _screen->setCurPage(2);
+ _screen->clearCurPage();
+ _screen->copyPage(2, 12);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ _callbackCurrentFrame = 0;
+ startNestedAnimation(0, kNestedSequenceFiggle);
+ break;
+
+ case -1:
+ if (_vm->gameFlags().isTalkie)
+ playHoFTalkieCredits();
+ _talkieFinaleExtraFlag = _vm->gameFlags().isTalkie;
+ break;
+
+ case 0:
+ if (_callbackCurrentFrame == 1) {
+ _vm->sound()->playTrack(4);
+ _textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xFF;
+ memset(_textColorMap, _textColor[1], 16);
+ _textColor[0] = _textColorMap[1] = 0xFF;
+ _screen->setTextColorMap(_textColorMap);
+ }
+ _animDuration = 10;
+ break;
+
+ case 1:
+ if (_callbackCurrentFrame < 20 && _talkieFinaleExtraFlag) {
+ _animCurrentFrame = 0;
+ } else {
+ _animDuration = _vm->gameFlags().isTalkie ? 500 : (300 + _vm->_rnd.getRandomNumberRng(1, 300));
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 26 : 22);
+ if (_talkieFinaleExtraFlag) {
+ _callbackCurrentFrame = 3;
+ _talkieFinaleExtraFlag = false;
+ }
+ }
+ break;
+
+ case 2:
+ _animDuration = 20;
+ break;
+
+ case 3:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 27 : 23);
+ _animDuration = _vm->gameFlags().isTalkie ? 500 : (300 + _vm->_rnd.getRandomNumberRng(1, 300));
+ break;
+
+ case 4:
+ _animDuration = 10;
+ break;
+
+ case 5:
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 27 : 23);
+ tmp = _callbackCurrentFrame / 6;
+ if (tmp == 2)
+ _animDuration = _vm->gameFlags().isTalkie ? 7 : (1 + _vm->_rnd.getRandomNumberRng(1, 10));
+ else if (tmp < 2)
+ _animDuration = _vm->gameFlags().isTalkie ? 500 : (300 + _vm->_rnd.getRandomNumberRng(1, 300));
+ break;
+
+ case 6:
+ _animDuration = 10;
+ tmp = _callbackCurrentFrame / 6;
+ if (tmp == 2)
+ _animCurrentFrame = 4;
+ else if (tmp < 2)
+ _animCurrentFrame = 0;
+ break;
+
+ case 7:
+ _callbackCurrentFrame = 0;
+ _animDuration = 5;
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 26 : 22);
+ break;
+
+ case 11:
+ if (_callbackCurrentFrame < 8)
+ _animCurrentFrame = 8;
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_figgle(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (_callbackCurrentFrame == 10)
+ setCountDown(0);
+ if (_callbackCurrentFrame == 10 || _callbackCurrentFrame == 5 || _callbackCurrentFrame == 7)
+ playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 45 : 30);
+
+ _callbackCurrentFrame++;
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_virgin(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (!frm)
+ delayTicks(50);
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (!frm)
+ _vm->sound()->playTrack(2);
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_title(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (!frm) {
+ _vm->sound()->playTrack(3);
+ } else if (frm == 25) {
+ delayTicks(60);
+ setCountDown(0);
+ doTransition(0);
+ }
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_hill(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (!frm) {
+ _vm->sound()->playTrack(4);
+ } else if (frm == 25) {
+ startNestedAnimation(0, kNestedSequenceHoFDemoWater);
+ _animDuration--;
+ } else if (frm > 25 && frm < 50) {
+ if (_animDuration > 3)
+ _animDuration--;
+ } else if (frm == 95) {
+ _animDuration = 70;
+ } else if (frm == 96) {
+ _animDuration = 7;
+ } else if (frm == 129) {
+ closeNestedAnimation(0);
+ }
+
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_outhome(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (frm) {
+ case 12:
+ playSoundAndDisplaySubTitle(4);
+ break;
+
+ case 32:
+ playSoundAndDisplaySubTitle(7);
+ break;
+
+ case 36:
+ playSoundAndDisplaySubTitle(10);
+ break;
+
+ case 57:
+ playSoundAndDisplaySubTitle(9);
+ break;
+
+ case 80:
+ case 96:
+ case 149:
+ _animDuration = 70;
+ break;
+
+ case 81:
+ case 97:
+ _animDuration = 5;
+ break;
+
+ case 110:
+ playSoundAndDisplaySubTitle(5);
+ break;
+
+ case 137:
+ playSoundAndDisplaySubTitle(6);
+ break;
+ }
+
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_wharf(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (!_callbackCurrentFrame)
+ startNestedAnimation(0, kNestedSequenceHoFDemoWharf2);
+
+ switch (frm) {
+ case 0:
+ playSoundAndDisplaySubTitle(11);
+ break;
+
+ case 5:
+ if ((_callbackCurrentFrame / 8) <= 2 || _animSlots[0].flags != -1)
+ _animCurrentFrame = 0;
+ else
+ closeNestedAnimation(0);
+ break;
+
+ case 6:
+ closeNestedAnimation(0);
+ break;
+
+ case 8:
+ case 10:
+ playSoundAndDisplaySubTitle(2);
+ break;
+
+ case 13:
+ playSoundAndDisplaySubTitle(7);
+ break;
+
+ case 16:
+ playSoundAndDisplaySubTitle(12);
+ break;
+
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_dinob(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 0) {
+ if (!(_callbackCurrentFrame/8)) {
+ startNestedAnimation(0, kNestedSequenceHoFDemoDinob2);
+ _animCurrentFrame = 0;
+ }
+ } else if (frm == 3) {
+ if (_animSlots[0].flags != -1) {
+ _animCurrentFrame = 0;
+ } else {
+ closeNestedAnimation(0);
+ _screen->copyPage(2, 12);
+ }
+ } else if (frm == 4) {
+ closeNestedAnimation(0);
+ }
+
+ _callbackCurrentFrame++;
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_fisher(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (((_system->getMillis() - _fisherAnimCurTime) / (5 * _vm->tickLength())) > 0) {
+ _fisherAnimCurTime = _system->getMillis();
+ if (!_callbackCurrentFrame) {
+ startNestedAnimation(0, kNestedSequenceHoFDemoBail);
+ startNestedAnimation(1, kNestedSequenceHoFDemoDig);
+ }
+
+ if (_scrollProgressCounter >= 0x18F && !_callbackCurrentFrame)
+ return 0;
+
+ if (!_callbackCurrentFrame) {
+ _screen->loadBitmap("adtext.cps", 4, 4, 0);
+ _screen->loadBitmap("adtext2.cps", 6, 6, 0);
+ _screen->copyPageMemory(6, 0, 4, 64000, 1024);
+ _screen->copyPageMemory(6, 1023, 6, 0, 64000);
+ _scrollProgressCounter = 0;
+ }
+
+ updateDemoAdText(24, 144);
+ _callbackCurrentFrame++;
+ if (_callbackCurrentFrame < 0x256 || _callbackCurrentFrame > 0x31C) {
+ if (_callbackCurrentFrame < 0x174 || _callbackCurrentFrame > 0x1D7) {
+ if (_callbackCurrentFrame < 0x84 || _callbackCurrentFrame > 0xE7) {
+ _scrollProgressCounter++;
+ }
+ }
+ }
+
+ if (_callbackCurrentFrame > 0x31E) {
+ closeNestedAnimation(0);
+ closeNestedAnimation(1);
+ setCountDown(0);
+ _screen->copyPage(2, 12);
+ }
+
+ } else {
+ updateDemoAdText(24, 144);
+ }
+ return 0;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_wharf2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 69)
+ _animCurrentFrame = 8;
+
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_dinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (frm) {
+ case 19:
+ playSoundAndDisplaySubTitle(13);
+ break;
+
+ case 54:
+ playSoundAndDisplaySubTitle(15);
+ break;
+
+ case 61:
+ playSoundAndDisplaySubTitle(16);
+ break;
+
+ case 69:
+ playSoundAndDisplaySubTitle(14);
+ break;
+
+ case 77:
+ playSoundAndDisplaySubTitle(13);
+ break;
+
+ case 79:
+ _animCurrentFrame = 4;
+ break;
+ }
+
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_water(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 1)
+ playSoundAndDisplaySubTitle(11);
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_bail(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ return frm;
+}
+
+int SeqPlayer_HOF::cbHOFDEMO_dig(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ return frm;
+}
+
+#ifdef ENABLE_LOL
+int SeqPlayer_HOF::cbLOLDEMO_scene1(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ Palette &tmpPal = _screen->getPalette(2);
+
+ if (!(_callbackCurrentFrame % 100)) {
+ if (_callbackCurrentFrame == 0) {
+ _vm->sound()->haltTrack();
+ _vm->sound()->playTrack(6);
+ }
+ tmpPal.copy(_screen->getPalette(0));
+
+ for (int i = 3; i < 768; i++) {
+ tmpPal[i] = ((int)tmpPal[i] * 120) / 64;
+ if (tmpPal[i] > 0x3F)
+ tmpPal[i] = 0x3F;
+ }
+
+ playSoundAndDisplaySubTitle(_vm->_rnd.getRandomBit());
+ _screen->setScreenPalette(tmpPal);
+ _screen->updateScreen();
+ _vm->delay(8);
+ } else {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->updateScreen();
+ if (_callbackCurrentFrame == 40)
+ playSoundAndDisplaySubTitle(3);
+ }
+
+ _callbackCurrentFrame++;
+ return frm;
+}
+
+int SeqPlayer_HOF::cbLOLDEMO_scene2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (frm - 17) {
+ case 0:
+ _animDuration = 8;
+ break;
+ case 3:
+ case 6:
+ case 9:
+ playSoundEffect(8, 255 - ((26 - frm) << 3));
+ break;
+ case 15:
+ playSoundAndDisplaySubTitle(9);
+ break;
+ case 18:
+ playSoundAndDisplaySubTitle(2);
+ break;
+ default:
+ break;
+ }
+ _callbackCurrentFrame++;
+ return frm;
+}
+
+int SeqPlayer_HOF::cbLOLDEMO_scene3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (frm == 1)
+ playSoundAndDisplaySubTitle(6);
+ else if (frm == 24)
+ playSoundAndDisplaySubTitle(7);
+
+ _callbackCurrentFrame++;
+ return frm;
+}
+
+int SeqPlayer_HOF::cbLOLDEMO_scene4(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (frm) {
+ case 11:
+ case 14:
+ case 17:
+ case 20:
+ playSoundEffect(8, 255 - ((22 - frm) << 3));
+ break;
+ case 22:
+ playSoundAndDisplaySubTitle(11);
+ break;
+ case 24:
+ playSoundAndDisplaySubTitle(8);
+ break;
+ case 30:
+ playSoundAndDisplaySubTitle(15);
+ break;
+ case 34:
+ playSoundAndDisplaySubTitle(14);
+ break;
+ case 38:
+ playSoundAndDisplaySubTitle(13);
+ break;
+ case 42:
+ playSoundAndDisplaySubTitle(12);
+ break;
+ default:
+ break;
+ }
+
+ _callbackCurrentFrame++;
+ return frm;
+}
+
+int SeqPlayer_HOF::cbLOLDEMO_scene5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ switch (_callbackCurrentFrame++) {
+ case 0:
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 14:
+ case 16:
+ case 18:
+ case 20:
+ case 22:
+ case 24:
+ case 26:
+ case 28:
+ case 30:
+ playSoundEffect(15, 255 - ((31 - frm) << 3));
+ break;
+ case 32:
+ playSoundAndDisplaySubTitle(16);
+ break;
+ case 42:
+ playSoundAndDisplaySubTitle(6);
+ break;
+ default:
+ break;
+ }
+ return frm;
+}
+
+int SeqPlayer_HOF::cbLOLDEMO_text5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ if (_callbackCurrentFrame++ == 100)
+ playSoundAndDisplaySubTitle(5);
+ return frm;
+}
+
+int SeqPlayer_HOF::cbLOLDEMO_scene6(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+ while (_scrollProgressCounter < 290) {
+ setCountDown(6);
+ if (!_callbackCurrentFrame) {
+ _screen->loadBitmap("adtext.cps", 4, 4, 0);
+ _screen->loadBitmap("adtext2.cps", 6, 6, 0);
+ _screen->copyPageMemory(6, 0, 4, 64000, 1024);
+ _screen->copyPageMemory(6, 1023, 6, 0, 64000);
+ _scrollProgressCounter = 0;
+ }
+
+ if (_callbackCurrentFrame % 175) {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ } else {
+ Palette &tmpPal = _screen->getPalette(2);
+ tmpPal.copy(_screen->getPalette(0));
+
+ for (int i = 3; i < 0x300; i++) {
+ tmpPal[i] = ((int)tmpPal[i] * 120) / 64;
+ if (tmpPal[i] > 0x3F)
+ tmpPal[i] = 0x3F;
+ }
+
+ playSoundAndDisplaySubTitle(_vm->_rnd.getRandomBit());
+ _screen->setScreenPalette(tmpPal);
+ _screen->updateScreen();
+ _vm->delay(8);
+ }
+
+ if (_callbackCurrentFrame == 40 || _callbackCurrentFrame == 80 || _callbackCurrentFrame == 150 || _callbackCurrentFrame == 300)
+ playSoundAndDisplaySubTitle(3);
+
+ _screen->copyPage(12, 2);
+ updateDemoAdText(70, 130);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ _callbackCurrentFrame++;
+ if (_callbackCurrentFrame < 128 || _callbackCurrentFrame > 207)
+ _scrollProgressCounter++;
+
+ while (countDownRunning())
+ delayTicks(1);
+ }
+ _screen->copyPage(2, 12);
+
+ return 0;
+}
+#endif // ENABLE_LOL
+
+#undef CASE_ALT
+
+const uint8 SeqPlayer_HOF::_textColorPresets[] = { 0x01, 0x01, 0x00, 0x3F, 0x3F, 0x3F };
+
+void KyraEngine_HoF::seq_showStarcraftLogo() {
+ WSAMovie_v2 *ci = new WSAMovie_v2(this);
+ assert(ci);
+ _screen->clearPage(2);
+ _res->loadPakFile("INTROGEN.PAK");
+ int endframe = ci->open("CI.WSA", 0, &_screen->getPalette(0));
+ _res->unloadPakFile("INTROGEN.PAK");
+ if (!ci->opened()) {
+ delete ci;
+ return;
+ }
+ _screen->hideMouse();
+ ci->displayFrame(0, 2, 0, 0, 0, 0, 0);
+ _screen->copyPage(2, 0);
+ _screen->fadeFromBlack();
+ for (int i = 1; i < endframe; i++) {
+ uint32 end = _system->getMillis() + 50;
+ if (skipFlag())
+ break;
+ ci->displayFrame(i, 2, 0, 0, 0, 0, 0);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ uint32 cur = _system->getMillis();
+ if (end > cur)
+ delay(end - cur);
+ else
+ updateInput();
+ }
+ if (!skipFlag()) {
+ uint32 end = _system->getMillis() + 50;
+ ci->displayFrame(0, 2, 0, 0, 0, 0, 0);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ uint32 cur = _system->getMillis();
+ if (end > cur)
+ delay(end - cur);
+ else
+ updateInput();
+ }
+ _screen->fadeToBlack();
+ _screen->showMouse();
+
+ _eventList.clear();
+ delete ci;
+}
+
+int KyraEngine_HoF::seq_playIntro() {
+ bool startupSaveLoadable = saveFileLoadable(0);
+ return SeqPlayer_HOF(this, _screen, _system, startupSaveLoadable).play(kSequenceVirgin, startupSaveLoadable ? kSequenceTitle : kSequenceNoLooping);
+}
+
+int KyraEngine_HoF::seq_playOutro() {
+ return SeqPlayer_HOF(this, _screen, _system).play(kSequenceFunters, kSequenceFrash);
+}
+
+int KyraEngine_HoF::seq_playDemo() {
+ SeqPlayer_HOF(this, _screen, _system).play(kSequenceHoFDemoVirgin, kSequenceHoFDemoVirgin);
+ return 4;
+}
+
+void KyraEngine_HoF::seq_pausePlayer(bool toggle) {
+ SeqPlayer_HOF *activePlayer = SeqPlayer_HOF::instance();
+ if (activePlayer)
+ activePlayer->pause(toggle);
+}
+
+#ifdef ENABLE_LOL
+int LoLEngine::playDemo() {
+ SeqPlayer_HOF(this, _screen, _system).play(kSequenceLoLDemoScene1, kSequenceLoLDemoScene1);
+ return -1;
+}
+
+void LoLEngine::pauseDemoPlayer(bool toggle) {
+ SeqPlayer_HOF *activePlayer = SeqPlayer_HOF::instance();
+ if (activePlayer)
+ activePlayer->pause(toggle);
+}
+#endif // ENABLE_LOL
+
+#pragma mark -
+#pragma mark - Ingame sequences
+#pragma mark -
+
+void KyraEngine_HoF::seq_makeBookOrCauldronAppear(int type) {
+ _screen->hideMouse();
+ showMessage(0, 0xCF);
+
+ if (type == 1)
+ seq_makeBookAppear();
+ else if (type == 2)
+ loadInvWsa("CAULDRON.WSA", 1, 6, 0, -2, -2, 1);
+
+ _screen->copyRegionToBuffer(2, 0, 0, 320, 200, _screenBuffer);
+ _screen->loadBitmap("_PLAYALL.CPS", 3, 3, 0);
+
+ static const uint8 bookCauldronRects[] = {
+ 0x46, 0x90, 0x7F, 0x2B, // unknown rect (maybe unused?)
+ 0xCE, 0x90, 0x2C, 0x2C, // book rect
+ 0xFA, 0x90, 0x46, 0x2C // cauldron rect
+ };
+
+ int x = bookCauldronRects[type*4+0];
+ int y = bookCauldronRects[type*4+1];
+ int w = bookCauldronRects[type*4+2];
+ int h = bookCauldronRects[type*4+3];
+ _screen->copyRegion(x, y, x, y, w, h, 2, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->copyBlockToPage(2, 0, 0, 320, 200, _screenBuffer);
+
+ if (type == 2) {
+ int32 countdown = _rnd.getRandomNumberRng(45, 80);
+ _timer->setCountdown(2, countdown * 60);
+ }
+
+ _screen->showMouse();
+}
+
+void KyraEngine_HoF::seq_makeBookAppear() {
+ _screen->hideMouse();
+
+ displayInvWsaLastFrame();
+
+ showMessage(0, 0xCF);
+
+ loadInvWsa("BOOK2.WSA", 0, 4, 2, -1, -1, 0);
+
+ uint8 *rect = new uint8[_screen->getRectSize(_invWsa.w, _invWsa.h)];
+ assert(rect);
+
+ _screen->copyRegionToBuffer(_invWsa.page, _invWsa.x, _invWsa.y, _invWsa.w, _invWsa.h, rect);
+
+ _invWsa.running = false;
+ snd_playSoundEffect(0xAF);
+
+ while (true) {
+ _invWsa.timer = _system->getMillis() + _invWsa.delay * _tickLength;
+
+ _screen->copyBlockToPage(_invWsa.page, _invWsa.x, _invWsa.y, _invWsa.w, _invWsa.h, rect);
+
+ _invWsa.wsa->displayFrame(_invWsa.curFrame, _invWsa.page, 0, 0, 0x4000, 0, 0);
+
+ if (_invWsa.page)
+ _screen->copyRegion(_invWsa.x, _invWsa.y, _invWsa.x, _invWsa.y, _invWsa.w, _invWsa.h, _invWsa.page, 0, Screen::CR_NO_P_CHECK);
+
+ ++_invWsa.curFrame;
+
+ if (_invWsa.curFrame >= _invWsa.lastFrame && !shouldQuit())
+ break;
+
+ switch (_invWsa.curFrame) {
+ case 39:
+ snd_playSoundEffect(0xCA);
+ break;
+
+ case 50:
+ snd_playSoundEffect(0x6A);
+ break;
+
+ case 72:
+ snd_playSoundEffect(0xCB);
+ break;
+
+ case 85:
+ snd_playSoundEffect(0x38);
+ break;
+
+ default:
+ break;
+ }
+
+ do {
+ update();
+ } while (_invWsa.timer > _system->getMillis() && !skipFlag());
+ }
+
+ closeInvWsa();
+ delete[] rect;
+ _invWsa.running = false;
+
+ _screen->showMouse();
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/sequence/sequences_hof.h b/engines/kyra/sequence/sequences_hof.h
new file mode 100644
index 0000000000..95d9260530
--- /dev/null
+++ b/engines/kyra/sequence/sequences_hof.h
@@ -0,0 +1,74 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KYRA_SEQUENCES_HOF_H
+#define KYRA_SEQUENCES_HOF_H
+
+#include "kyra/engine/kyra_v2.h"
+
+namespace Kyra {
+
+struct HoFSequence {
+ const char *wsaFile;
+ const char *cpsFile;
+ uint16 flags;
+ uint8 fadeInTransitionType;
+ uint8 fadeOutTransitionType;
+ int16 stringIndex1;
+ int16 stringIndex2;
+ uint16 startFrame;
+ uint16 numFrames;
+ uint16 duration;
+ uint16 xPos;
+ uint16 yPos;
+ uint16 timeout;
+};
+
+struct HoFNestedSequence {
+ const char *wsaFile;
+ const FrameControl *wsaControl;
+ uint16 flags;
+ uint16 startframe;
+ uint16 endFrame;
+ uint16 frameDelay;
+ uint16 x;
+ uint16 y;
+ uint16 fadeInTransitionType;
+ uint16 fadeOutTransitionType;
+};
+
+struct HoFSeqData {
+ const HoFSequence *seq;
+ int numSeq;
+ const HoFNestedSequence *nestedSeq;
+ int numNestedSeq;
+};
+
+struct HoFSeqItemAnimData {
+ int16 itemIndex;
+ uint16 y;
+ const uint16 *frames;
+};
+
+} // End of namespace Kyra
+
+#endif
diff --git a/engines/kyra/sequence/sequences_lok.cpp b/engines/kyra/sequence/sequences_lok.cpp
new file mode 100644
index 0000000000..faddf762fb
--- /dev/null
+++ b/engines/kyra/sequence/sequences_lok.cpp
@@ -0,0 +1,2116 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/kyra_lok.h"
+#include "kyra/sequence/seqplayer.h"
+#include "kyra/resource/resource.h"
+#include "kyra/engine/sprites.h"
+#include "kyra/graphics/wsamovie.h"
+#include "kyra/graphics/animator_lok.h"
+#include "kyra/engine/timer.h"
+#include "kyra/sound/sound.h"
+
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/list.h"
+
+namespace Kyra {
+
+void KyraEngine_LoK::seq_demo() {
+ snd_playTheme(0, 2);
+
+ _screen->loadBitmap("START.CPS", 7, 7, &_screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _screen->fadeFromBlack();
+ delay(60 * _tickLength);
+ _screen->fadeToBlack();
+
+ _screen->clearPage(0);
+ _screen->loadBitmap("TOP.CPS", 7, 7, 0);
+ _screen->loadBitmap("BOTTOM.CPS", 5, 5, &_screen->getPalette(0));
+ _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 0);
+ _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 0);
+ _screen->updateScreen();
+ _screen->fadeFromBlack();
+
+ _seq->playSequence(_seq_WestwoodLogo, true);
+ delay(60 * _tickLength);
+ _seq->playSequence(_seq_KyrandiaLogo, true);
+
+ _screen->fadeToBlack();
+ _screen->clearPage(2);
+ _screen->clearPage(0);
+
+ _seq->playSequence(_seq_Demo1, true);
+
+ _screen->clearPage(0);
+ _seq->playSequence(_seq_Demo2, true);
+
+ _screen->clearPage(0);
+ _seq->playSequence(_seq_Demo3, true);
+
+ _screen->clearPage(0);
+ _seq->playSequence(_seq_Demo4, true);
+
+ _screen->clearPage(0);
+ _screen->loadBitmap("FINAL.CPS", 7, 7, &_screen->getPalette(0));
+ _screen->_curPage = 0;
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0);
+ _screen->updateScreen();
+ _screen->fadeFromBlack();
+ delay(60 * _tickLength);
+ _screen->fadeToBlack();
+ _sound->haltTrack();
+}
+
+void KyraEngine_LoK::seq_intro() {
+ if (_flags.isTalkie)
+ _res->loadPakFile("INTRO.VRM");
+
+ static const IntroProc introProcTable[] = {
+ &KyraEngine_LoK::seq_introPublisherLogos,
+ &KyraEngine_LoK::seq_introLogos,
+ &KyraEngine_LoK::seq_introStory,
+ &KyraEngine_LoK::seq_introMalcolmTree,
+ &KyraEngine_LoK::seq_introKallakWriting,
+ &KyraEngine_LoK::seq_introKallakMalcolm
+ };
+
+ Common::InSaveFile *in;
+ if ((in = _saveFileMan->openForLoading(getSavegameFilename(0)))) {
+ delete in;
+ _skipIntroFlag = true;
+ } else {
+ _skipIntroFlag = !_flags.isDemo;
+ }
+
+ _seq->setCopyViewOffs(true);
+ _screen->setFont(_flags.lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+ if (_flags.platform != Common::kPlatformFMTowns && _flags.platform != Common::kPlatformPC98 && _flags.platform != Common::kPlatformAmiga)
+ snd_playTheme(0, 2);
+ _text->setTalkCoords(144);
+
+ for (int i = 0; i < ARRAYSIZE(introProcTable) && !seq_skipSequence(); ++i) {
+ if ((this->*introProcTable[i])() && !shouldQuit()) {
+ resetSkipFlag();
+ _screen->fadeToBlack();
+ _screen->clearPage(0);
+ }
+ }
+
+ _text->setTalkCoords(136);
+ delay(30 * _tickLength);
+ _seq->setCopyViewOffs(false);
+ _sound->haltTrack();
+ _sound->voiceStop();
+
+ if (_flags.isTalkie)
+ _res->unloadPakFile("INTRO.VRM");
+}
+
+bool KyraEngine_LoK::seq_introPublisherLogos() {
+ if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) {
+ _screen->loadBitmap("LOGO.CPS", 3, 3, &_screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->updateScreen();
+ _screen->fadeFromBlack();
+ delay(90 * _tickLength);
+ if (!_abortIntroFlag) {
+ _screen->fadeToBlack();
+ snd_playWanderScoreViaMap(_flags.platform == Common::kPlatformFMTowns ? 57 : 2, 0);
+ }
+ } else if (_flags.platform == Common::kPlatformMacintosh && _res->exists("MP_GOLD.CPS")) {
+ _screen->loadPalette("MP_GOLD.COL", _screen->getPalette(0));
+ _screen->loadBitmap("MP_GOLD.CPS", 3, 3, 0);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _screen->updateScreen();
+ _screen->fadeFromBlack();
+ delay(120 * _tickLength);
+ if (!_abortIntroFlag)
+ _screen->fadeToBlack();
+ }
+
+ return _abortIntroFlag;
+}
+
+bool KyraEngine_LoK::seq_introLogos() {
+ _screen->clearPage(0);
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ _screen->loadPaletteTable("INTRO.PAL", 0);
+ _screen->loadBitmap("BOTTOM.CPS", 3, 5, 0);
+ _screen->loadBitmap("TOP.CPS", 3, 3, 0);
+ _screen->copyRegion(0, 0, 0, 111, 320, 64, 2, 0);
+ _screen->copyRegion(0, 91, 0, 8, 320, 109, 2, 0);
+ _screen->copyRegion(0, 0, 0, 0, 320, 190, 0, 2);
+ } else {
+ _screen->loadBitmap("TOP.CPS", 7, 7, 0);
+ _screen->loadBitmap("BOTTOM.CPS", 5, 5, &_screen->getPalette(0));
+ _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 0);
+ _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 0);
+ }
+
+ _screen->_curPage = 0;
+ _screen->updateScreen();
+ _screen->fadeFromBlack();
+
+ if (_seq->playSequence(_seq_WestwoodLogo, skipFlag()) || shouldQuit())
+ return true;
+
+ delay(60 * _tickLength);
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ _screen->copyPalette(0, 1);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+
+ if (_seq->playSequence(_seq_KyrandiaLogo, skipFlag()) || shouldQuit())
+ return true;
+
+ _screen->setFont(of);
+ _screen->fillRect(0, 179, 319, 199, 0);
+
+ if (shouldQuit())
+ return false;
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ _screen->copyPalette(0, 2);
+ _screen->fadeToBlack();
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 4, 0);
+ _screen->fadeFromBlack();
+ } else {
+ _screen->copyRegion(0, 91, 0, 8, 320, 104, 6, 2);
+ _screen->copyRegion(0, 0, 0, 112, 320, 64, 6, 2);
+
+ uint32 start = _system->getMillis();
+ bool doneFlag = false;
+ int oldDistance = 0;
+
+ do {
+ uint32 now = _system->getMillis();
+
+ // The smallest y2 we ever draw the screen for is 65.
+ int distance = (now - start) / _tickLength;
+ if (distance > 112) {
+ distance = 112;
+ doneFlag = true;
+ }
+
+ if (distance > oldDistance) {
+ int y1 = 8 + distance;
+ int h1 = 168 - distance;
+ int y2 = 176 - distance;
+ int h2 = distance;
+
+ _screen->copyRegion(0, y1, 0, 8, 320, h1, 2, 0);
+ if (h2 > 0)
+ _screen->copyRegion(0, 64, 0, y2, 320, h2, 4, 0);
+ _screen->updateScreen();
+ }
+
+ oldDistance = distance;
+ delay(10);
+ } while (!doneFlag && !shouldQuit() && !_abortIntroFlag);
+ }
+
+ if (_abortIntroFlag || shouldQuit())
+ return true;
+
+ return _seq->playSequence(_seq_Forest, true);
+}
+
+bool KyraEngine_LoK::seq_introStory() {
+ _screen->clearPage(3);
+ _screen->clearPage(0);
+
+ // HACK: The Italian fan translation uses an special text screen here
+ // so we show it even when text is disabled
+ if (!textEnabled() && speechEnabled() && _flags.lang != Common::IT_ITA)
+ return false;
+
+ if (((_flags.lang == Common::EN_ANY || _flags.lang == Common::RU_RUS) && !_flags.isTalkie && _flags.platform == Common::kPlatformDOS) || _flags.platform == Common::kPlatformAmiga)
+ _screen->loadBitmap("TEXT.CPS", 3, 3, &_screen->getPalette(0));
+ else if (_flags.lang == Common::EN_ANY || _flags.lang == Common::JA_JPN)
+ _screen->loadBitmap("TEXT_ENG.CPS", 3, 3, &_screen->getPalette(0));
+ else if (_flags.lang == Common::DE_DEU)
+ _screen->loadBitmap("TEXT_GER.CPS", 3, 3, &_screen->getPalette(0));
+ else if (_flags.lang == Common::FR_FRA)
+ _screen->loadBitmap("TEXT_FRE.CPS", 3, 3, &_screen->getPalette(0));
+ else if (_flags.lang == Common::ES_ESP)
+ _screen->loadBitmap("TEXT_SPA.CPS", 3, 3, &_screen->getPalette(0));
+ else if (_flags.lang == Common::IT_ITA && !_flags.isTalkie)
+ _screen->loadBitmap("TEXT_ITA.CPS", 3, 3, &_screen->getPalette(0));
+ else if (_flags.lang == Common::IT_ITA && _flags.isTalkie)
+ _screen->loadBitmap("TEXT_ENG.CPS", 3, 3, &_screen->getPalette(0));
+ else
+ warning("no story graphics file found");
+
+ if (_flags.platform == Common::kPlatformAmiga)
+ _screen->setScreenPalette(_screen->getPalette(4));
+ else
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->copyPage(3, 0);
+
+ if (_flags.lang == Common::JA_JPN) {
+ const int y1 = 175;
+ int x1, x2, y2, col1;
+ const char *s1, *s2;
+
+ if (_flags.platform == Common::kPlatformFMTowns) {
+ s1 = _seq_textsTable[18];
+ s2 = _seq_textsTable[19];
+ x1 = (Screen::SCREEN_W - _screen->getTextWidth(s1)) / 2;
+ x2 = (Screen::SCREEN_W - _screen->getTextWidth(s2)) / 2;
+ uint8 colorMap[] = { 0, 15, 12, 12 };
+ _screen->setTextColor(colorMap, 0, 3);
+ y2 = 184;
+ col1 = 5;
+
+ } else {
+ s1 = _storyStrings[0];
+ s2 = _storyStrings[1];
+ x1 = x2 = 54;
+ y2 = 185;
+ col1 = 15;
+ }
+
+ _screen->printText(s1, x1, y1, col1, 8);
+ _screen->printText(s2, x2, y2, col1, 8);
+ }
+
+ _screen->updateScreen();
+ delay(360 * _tickLength);
+
+ return _abortIntroFlag;
+}
+
+bool KyraEngine_LoK::seq_introMalcolmTree() {
+ _screen->_curPage = 0;
+ _screen->clearPage(3);
+ return _seq->playSequence(_seq_MalcolmTree, true);
+}
+
+bool KyraEngine_LoK::seq_introKallakWriting() {
+ _seq->makeHandShapes();
+ _screen->setAnimBlockPtr(5060);
+ _screen->_charWidth = -2;
+ _screen->clearPage(3);
+ const bool skipped = _seq->playSequence(_seq_KallakWriting, true);
+ _seq->freeHandShapes();
+
+ return skipped;
+}
+
+bool KyraEngine_LoK::seq_introKallakMalcolm() {
+ _screen->clearPage(3);
+ return _seq->playSequence(_seq_KallakMalcolm, true);
+}
+
+void KyraEngine_LoK::seq_createAmuletJewel(int jewel, int page, int noSound, int drawOnly) {
+ static const uint16 specialJewelTable[] = {
+ 0x167, 0x162, 0x15D, 0x158, 0x153, 0xFFFF
+ };
+ static const uint16 specialJewelTable1[] = {
+ 0x14F, 0x154, 0x159, 0x15E, 0x163, 0xFFFF
+ };
+ static const uint16 specialJewelTable2[] = {
+ 0x150, 0x155, 0x15A, 0x15F, 0x164, 0xFFFF
+ };
+ static const uint16 specialJewelTable3[] = {
+ 0x151, 0x156, 0x15B, 0x160, 0x165, 0xFFFF
+ };
+ static const uint16 specialJewelTable4[] = {
+ 0x152, 0x157, 0x15C, 0x161, 0x166, 0xFFFF
+ };
+ if (!noSound)
+ snd_playSoundEffect(0x5F);
+ _screen->hideMouse();
+ if (!drawOnly) {
+ for (int i = 0; specialJewelTable[i] != 0xFFFF; ++i) {
+ _screen->drawShape(page, _shapes[specialJewelTable[i]], _amuletX2[jewel], _amuletY2[jewel], 0, 0);
+ _screen->updateScreen();
+ delayWithTicks(3);
+ }
+
+ const uint16 *opcodes = 0;
+ switch (jewel - 1) {
+ case 0:
+ opcodes = specialJewelTable1;
+ break;
+
+ case 1:
+ opcodes = specialJewelTable2;
+ break;
+
+ case 2:
+ opcodes = specialJewelTable3;
+ break;
+
+ case 3:
+ opcodes = specialJewelTable4;
+ break;
+ }
+
+ if (opcodes) {
+ for (int i = 0; opcodes[i] != 0xFFFF; ++i) {
+ _screen->drawShape(page, _shapes[opcodes[i]], _amuletX2[jewel], _amuletY2[jewel], 0, 0);
+ _screen->updateScreen();
+ delayWithTicks(3);
+ }
+ }
+ }
+ _screen->drawShape(page, _shapes[323 + jewel], _amuletX2[jewel], _amuletY2[jewel], 0, 0);
+ _screen->updateScreen();
+ _screen->showMouse();
+ setGameFlag(0x55 + jewel);
+}
+
+void KyraEngine_LoK::seq_brandonHealing() {
+ if (!(_deathHandler & 8))
+ return;
+ if (_currentCharacter->sceneId == 210) {
+ if (_beadStateVar == 4 || _beadStateVar == 6)
+ return;
+ }
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ assert(_healingShapeTable);
+ setupShapes123(_healingShapeTable, 22, 0);
+ _animator->setBrandonAnimSeqSize(3, 48);
+ snd_playSoundEffect(0x53);
+ for (int i = 123; i <= 144; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+ for (int i = 125; i >= 123; --i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+ _animator->resetBrandonAnimSeqSize();
+ _currentCharacter->currentAnimFrame = 7;
+ _animator->animRefreshNPC(0);
+ freeShapes123();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_brandonHealing2() {
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ assert(_healingShape2Table);
+ setupShapes123(_healingShape2Table, 30, 0);
+ resetBrandonPoisonFlags();
+ _animator->setBrandonAnimSeqSize(3, 48);
+ snd_playSoundEffect(0x50);
+ for (int i = 123; i <= 152; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+ _animator->resetBrandonAnimSeqSize();
+ _currentCharacter->currentAnimFrame = 7;
+ _animator->animRefreshNPC(0);
+ freeShapes123();
+ _screen->showMouse();
+ assert(_poisonGone);
+ characterSays(2010, _poisonGone[0], 0, -2);
+ characterSays(2011, _poisonGone[1], 0, -2);
+}
+
+void KyraEngine_LoK::seq_poisonDeathNow(int now) {
+ if (!(_brandonStatusBit & 1))
+ return;
+ ++_poisonDeathCounter;
+ if (now)
+ _poisonDeathCounter = 2;
+ if (_poisonDeathCounter >= 2) {
+ snd_playWanderScoreViaMap(1, 1);
+ assert(_thePoison);
+ characterSays(7000, _thePoison[0], 0, -2);
+ characterSays(7001, _thePoison[1], 0, -2);
+ seq_poisonDeathNowAnim();
+ _deathHandler = 3;
+ } else {
+ assert(_thePoison);
+ characterSays(7002, _thePoison[2], 0, -2);
+ characterSays(7004, _thePoison[3], 0, -2);
+ }
+}
+
+void KyraEngine_LoK::seq_poisonDeathNowAnim() {
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ assert(_posionDeathShapeTable);
+ setupShapes123(_posionDeathShapeTable, 20, 0);
+ _animator->setBrandonAnimSeqSize(8, 48);
+
+ _currentCharacter->currentAnimFrame = 124;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(30);
+
+ _currentCharacter->currentAnimFrame = 123;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(30);
+
+ for (int i = 125; i <= 139; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ delayWithTicks(60);
+
+ for (int i = 140; i <= 142; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ delayWithTicks(60);
+
+ _animator->resetBrandonAnimSeqSize();
+ freeShapes123();
+ _animator->restoreAllObjectBackgrounds();
+ _currentCharacter->x1 = _currentCharacter->x2 = -1;
+ _currentCharacter->y1 = _currentCharacter->y2 = -1;
+ _animator->preserveAllBackgrounds();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_playFluteAnimation() {
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ setupShapes123(_fluteAnimShapeTable, 36, 0);
+ _animator->setBrandonAnimSeqSize(3, 75);
+ for (int i = 123; i <= 130; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(2);
+ }
+
+ int delayTime = 0, soundType = 0;
+ if (queryGameFlag(0x85)) {
+ snd_playSoundEffect(0x63);
+ delayTime = 9;
+ soundType = 3;
+ } else if (!queryGameFlag(0x86)) {
+ snd_playSoundEffect(0x61);
+ delayTime = 2;
+ soundType = 1;
+ setGameFlag(0x86);
+ } else {
+ snd_playSoundEffect(0x62);
+ delayTime = 2;
+ soundType = 2;
+ }
+
+ for (int i = 131; i <= 158; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(delayTime);
+ }
+
+ for (int i = 126; i >= 123; --i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(delayTime);
+ }
+ _animator->resetBrandonAnimSeqSize();
+ _currentCharacter->currentAnimFrame = 7;
+ _animator->animRefreshNPC(0);
+ freeShapes123();
+ _screen->showMouse();
+
+ if (soundType == 1) {
+ assert(_fluteString);
+ characterSays(1000, _fluteString[0], 0, -2);
+ } else if (soundType == 2) {
+ assert(_fluteString);
+ characterSays(1001, _fluteString[1], 0, -2);
+ }
+}
+
+void KyraEngine_LoK::seq_winterScroll1() {
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ assert(_winterScrollTable);
+ assert(_winterScroll1Table);
+ assert(_winterScroll2Table);
+ setupShapes123(_winterScrollTable, 7, 0);
+ _animator->setBrandonAnimSeqSize(5, 66);
+
+ for (int i = 123; i <= 129; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ freeShapes123();
+ snd_playSoundEffect(0x20);
+
+ uint8 numFrames, midpoint;
+ if (_flags.isTalkie) {
+ numFrames = 18;
+ midpoint = 136;
+ } else {
+ numFrames = 35;
+ midpoint = 147;
+ }
+ setupShapes123(_winterScroll1Table, numFrames, 0);
+ for (int i = 123; i < midpoint; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ if (_currentCharacter->sceneId == 41 && !queryGameFlag(0xA2)) {
+ snd_playSoundEffect(0x20);
+ _sprites->_anims[0].play = false;
+ _animator->sprites()[0].active = 0;
+ _sprites->_anims[1].play = true;
+ _animator->sprites()[1].active = 1;
+
+ if (_flags.platform != Common::kPlatformAmiga)
+ setGameFlag(0xA2);
+ }
+
+ for (int i = midpoint; i < 123 + numFrames; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ if (_currentCharacter->sceneId == 117 && !queryGameFlag(0xB3)) {
+ for (int i = 0; i <= 7; ++i) {
+ _sprites->_anims[i].play = false;
+ _animator->sprites()[i].active = 0;
+ }
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ _screen->copyPalette(0, 11);
+ } else {
+ _screen->getPalette(0).copy(palTable2()[0], 0, 20, 228);
+ _screen->fadePalette(_screen->getPalette(0), 72);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ setGameFlag(0xB3);
+ }
+ } else {
+ delayWithTicks(120);
+ }
+
+ freeShapes123();
+ setupShapes123(_winterScroll2Table, 4, 0);
+
+ for (int i = 123; i <= 126; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ _animator->resetBrandonAnimSeqSize();
+ _currentCharacter->currentAnimFrame = 7;
+ _animator->animRefreshNPC(0);
+ freeShapes123();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_winterScroll2() {
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ assert(_winterScrollTable);
+ setupShapes123(_winterScrollTable, 7, 0);
+ _animator->setBrandonAnimSeqSize(5, 66);
+
+ for (int i = 123; i <= 128; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ delayWithTicks(120);
+
+ for (int i = 127; i >= 123; --i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ _animator->resetBrandonAnimSeqSize();
+ _currentCharacter->currentAnimFrame = 7;
+ _animator->animRefreshNPC(0);
+ freeShapes123();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_makeBrandonInv() {
+ if (_deathHandler == 8)
+ return;
+
+ if (_currentCharacter->sceneId == 210) {
+ if (_beadStateVar == 4 || _beadStateVar == 6)
+ return;
+ }
+
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ _brandonStatusBit |= 0x20;
+ _timer->setCountdown(18, 2700);
+ _brandonStatusBit |= 0x40;
+ snd_playSoundEffect(0x77);
+ _brandonInvFlag = 0;
+ while (_brandonInvFlag <= 0x100) {
+ _animator->animRefreshNPC(0);
+ delayWithTicks(10);
+ _brandonInvFlag += 0x10;
+ }
+ _brandonStatusBit &= 0xFFBF;
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_makeBrandonNormal() {
+ _screen->hideMouse();
+ _brandonStatusBit |= 0x40;
+ snd_playSoundEffect(0x77);
+ _brandonInvFlag = 0x100;
+ while (_brandonInvFlag >= 0) {
+ _animator->animRefreshNPC(0);
+ delayWithTicks(10);
+ _brandonInvFlag -= 0x10;
+ }
+ _brandonInvFlag = 0;
+ _brandonStatusBit &= 0xFF9F;
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_makeBrandonNormal2() {
+ _screen->hideMouse();
+ assert(_brandonToWispTable);
+ setupShapes123(_brandonToWispTable, 26, 0);
+ _animator->setBrandonAnimSeqSize(5, 48);
+ _brandonStatusBit &= 0xFFFD;
+ snd_playSoundEffect(0x6C);
+ for (int i = 138; i >= 123; --i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+ _animator->setBrandonAnimSeqSize(3, 48);
+ _currentCharacter->currentAnimFrame = 7;
+ _animator->animRefreshNPC(0);
+
+ if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245)
+ _screen->fadeSpecialPalette(31, 234, 13, 4);
+ else if (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186)
+ _screen->fadeSpecialPalette(14, 228, 15, 4);
+
+ freeShapes123();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_makeBrandonWisp() {
+ if (_deathHandler == 8)
+ return;
+
+ if (_currentCharacter->sceneId == 210) {
+ if (_beadStateVar == 4 || _beadStateVar == 6)
+ return;
+ }
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ assert(_brandonToWispTable);
+ setupShapes123(_brandonToWispTable, 26, 0);
+ _animator->setBrandonAnimSeqSize(5, 48);
+ snd_playSoundEffect(0x6C);
+ for (int i = 123; i <= 138; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+ _brandonStatusBit |= 2;
+
+ if (_currentCharacter->sceneId >= 109 && _currentCharacter->sceneId <= 198)
+ _timer->setCountdown(14, 18000);
+ else
+ _timer->setCountdown(14, 7200);
+
+ _animator->_brandonDrawFrame = 113;
+ _brandonStatusBit0x02Flag = 1;
+ _currentCharacter->currentAnimFrame = 113;
+ _animator->animRefreshNPC(0);
+ _animator->updateAllObjectShapes();
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ if ((_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245) ||
+ (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186))
+ _screen->fadePalette(_screen->getPalette(10), 0x54);
+ } else {
+ if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245)
+ _screen->fadeSpecialPalette(30, 234, 13, 4);
+ else if (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186)
+ _screen->fadeSpecialPalette(14, 228, 15, 4);
+ }
+
+ freeShapes123();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_dispelMagicAnimation() {
+ if (_deathHandler == 8)
+ return;
+ if (_currentCharacter->sceneId == 210) {
+ if (_beadStateVar == 4 || _beadStateVar == 6)
+ return;
+ }
+ _screen->hideMouse();
+ // TODO
+ // This condition is always false. Is this a typo or a bug in the original?
+ if (_currentCharacter->sceneId == 210 && _currentCharacter->sceneId < 160)
+ _currentCharacter->facing = 3;
+ if (_malcolmFlag == 7 && _beadStateVar == 3) {
+ _beadStateVar = 6;
+ _unkEndSeqVar5 = 2;
+ _malcolmFlag = 10;
+ }
+ checkAmuletAnimFlags();
+ setGameFlag(0xEE);
+ assert(_magicAnimationTable);
+ setupShapes123(_magicAnimationTable, 5, 0);
+ _animator->setBrandonAnimSeqSize(8, 49);
+ snd_playSoundEffect(0x15);
+ for (int i = 123; i <= 127; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ delayWithTicks(120);
+
+ for (int i = 127; i >= 123; --i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(10);
+ }
+ _animator->resetBrandonAnimSeqSize();
+ _currentCharacter->currentAnimFrame = 7;
+ _animator->animRefreshNPC(0);
+ freeShapes123();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_fillFlaskWithWater(int item, int type) {
+ int newItem = -1;
+
+ static const uint8 flaskTable1[] = { 0x46, 0x48, 0x4A, 0x4C };
+ static const uint8 flaskTable2[] = { 0x47, 0x49, 0x4B, 0x4D };
+
+ if (item >= 60 && item <= 77) {
+ assert(_flaskFull);
+ characterSays(8006, _flaskFull[0], 0, -2);
+ } else if (item == 78) {
+ assert(type >= 0 && type < ARRAYSIZE(flaskTable1));
+ newItem = flaskTable1[type];
+ } else if (item == 79) {
+ assert(type >= 0 && type < ARRAYSIZE(flaskTable2));
+ newItem = flaskTable2[type];
+ }
+
+ if (newItem == -1)
+ return;
+
+ setMouseItem(newItem);
+ _itemInHand = newItem;
+
+ assert(_fullFlask);
+ assert(type < _fullFlask_Size && type >= 0);
+
+ static const uint16 voiceEntries[] = {
+ 0x1F40, 0x1F41, 0x1F42, 0x1F45
+ };
+ assert(type < ARRAYSIZE(voiceEntries));
+
+ characterSays(voiceEntries[type], _fullFlask[type], 0, -2);
+}
+
+void KyraEngine_LoK::seq_playDrinkPotionAnim(int item, int unk2, int flags) {
+ if (_flags.platform == Common::kPlatformAmiga) {
+ uint8 r, g, b;
+
+ switch (item) {
+ case 60: case 61:
+ // 0xC22
+ r = 50;
+ g = 8;
+ b = 8;
+ break;
+
+ case 62: case 63: case 76:
+ case 77:
+ // 0x00E
+ r = 0;
+ g = 0;
+ b = 58;
+ break;
+
+ case 64: case 65:
+ // 0xFF5
+ r = 63;
+ g = 63;
+ b = 21;
+ break;
+
+ case 66:
+ // 0x090
+ r = 0;
+ g = 37;
+ b = 0;
+ break;
+
+ case 67:
+ // 0xC61
+ r = 50;
+ g = 25;
+ b = 4;
+ break;
+
+ case 68:
+ // 0xE2E
+ r = 58;
+ g = 8;
+ b = 58;
+ break;
+
+ case 69:
+ // 0xBBB
+ r = 46;
+ g = 46;
+ b = 46;
+ break;
+
+ default:
+ // 0xFFF
+ r = 63;
+ g = 63;
+ b = 63;
+ }
+
+ _screen->setPaletteIndex(16, r, g, b);
+ } else {
+ uint8 red, green, blue;
+
+ switch (item) {
+ case 60: case 61:
+ red = 63;
+ green = blue = 6;
+ break;
+
+ case 62: case 63:
+ red = green = 0;
+ blue = 67;
+ break;
+
+ case 64: case 65:
+ red = 84;
+ green = 78;
+ blue = 14;
+ break;
+
+ case 66:
+ red = blue = 0;
+ green = 48;
+ break;
+
+ case 67:
+ red = 100;
+ green = 48;
+ blue = 23;
+ break;
+
+ case 68:
+ red = 73;
+ green = 0;
+ blue = 89;
+ break;
+
+ case 69:
+ red = green = 73;
+ blue = 86;
+ break;
+
+ default:
+ red = 33;
+ green = 66;
+ blue = 100;
+ }
+
+ red = red * 0x3F / 100;
+ green = green * 0x3F / 100;
+ blue = blue * 0x3F / 100;
+
+ _screen->setPaletteIndex(0xFE, red, green, blue);
+ }
+
+ _screen->hideMouse();
+ checkAmuletAnimFlags();
+ _currentCharacter->facing = 5;
+ _animator->animRefreshNPC(0);
+ assert(_drinkAnimationTable);
+ setupShapes123(_drinkAnimationTable, 9, flags);
+ _animator->setBrandonAnimSeqSize(5, 54);
+
+ for (int i = 123; i <= 131; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(5);
+ }
+
+ snd_playSoundEffect(0x34);
+
+ for (int i = 0; i < 2; ++i) {
+ _currentCharacter->currentAnimFrame = 130;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(7);
+ _currentCharacter->currentAnimFrame = 131;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(7);
+ }
+
+ if (unk2) {
+ // XXX
+ }
+
+ for (int i = 131; i >= 123; --i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(5);
+ }
+
+ _animator->resetBrandonAnimSeqSize();
+ _currentCharacter->currentAnimFrame = 7;
+ _animator->animRefreshNPC(0);
+ freeShapes123();
+
+ if (_flags.platform != Common::kPlatformAmiga)
+ _screen->setPaletteIndex(0xFE, 30, 30, 30);
+
+ _screen->showMouse();
+}
+
+int KyraEngine_LoK::seq_playEnd() {
+ if (_endSequenceSkipFlag)
+ return 0;
+
+ if (_deathHandler == 8)
+ return 0;
+
+ _screen->_curPage = 2;
+ if (_endSequenceNeedLoading) {
+ snd_playWanderScoreViaMap(50, 1);
+ setupPanPages();
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ _sound->loadSoundFile(kMusicFinale);
+
+ // The original started song 0 directly here. Since our player
+ // uses 0, 1 for stop and fade we start song 0 with 2
+ _sound->playTrack(2);
+ }
+
+ _finalA = createWSAMovie();
+ assert(_finalA);
+ _finalA->open("finala.wsa", 1, 0);
+
+ _finalB = createWSAMovie();
+ assert(_finalB);
+ _finalB->open("finalb.wsa", 1, 0);
+
+ _finalC = createWSAMovie();
+ assert(_finalC);
+ _endSequenceNeedLoading = 0;
+ _finalC->open("finalc.wsa", 1, 0);
+
+ _screen->_curPage = 0;
+ _beadStateVar = 0;
+ _malcolmFlag = 0;
+ _unkEndSeqVar2 = _system->getMillis() + 600 * _tickLength;
+
+ _screen->copyRegion(312, 0, 312, 0, 8, 136, 0, 2);
+ }
+
+ // TODO: better handling. This timer shouldn't count when the menu is open or something.
+ if (_unkEndSeqVar2 != -1) {
+ if (_system->getMillis() > (uint32)_unkEndSeqVar2) {
+ _unkEndSeqVar2 = -1;
+ if (!_malcolmFlag)
+ _malcolmFlag = 1;
+ }
+ }
+
+ if (handleMalcolmFlag()) {
+ _beadStateVar = 0;
+ _malcolmFlag = 12;
+ handleMalcolmFlag();
+ handleBeadState();
+ closeFinalWsa();
+ if (_deathHandler == 8) {
+ _screen->_curPage = 0;
+ checkAmuletAnimFlags();
+ seq_brandonToStone();
+ delay(60 * _tickLength);
+ return 1;
+ } else {
+ _endSequenceSkipFlag = 1;
+ if (_text->printed())
+ _text->restoreTalkTextMessageBkgd(2, 0);
+
+ _screen->_curPage = 0;
+ _screen->hideMouse();
+
+ if (_flags.platform != Common::kPlatformAmiga)
+ _screen->fadeSpecialPalette(32, 228, 20, 60);
+
+ delay(60 * _tickLength);
+
+ _screen->loadBitmap("GEMHEAL.CPS", 3, 3, &_screen->getPalette(0));
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->shuffleScreen(8, 8, 304, 128, 2, 0, 1, 0);
+
+ uint32 nextTime = _system->getMillis() + 120 * _tickLength;
+
+ _finalA = createWSAMovie();
+ assert(_finalA);
+ _finalA->open("finald.wsa", 1, 0);
+
+ delayUntil(nextTime);
+ snd_playSoundEffect(0x40);
+ for (int i = 0; i < 22; ++i) {
+ delayUntil(nextTime);
+ if (i == 4)
+ snd_playSoundEffect(0x3E);
+ else if (i == 20)
+ snd_playSoundEffect(_flags.platform == Common::kPlatformPC98 ? 0x13 : 0x0E);
+ nextTime = _system->getMillis() + 8 * _tickLength;
+ _finalA->displayFrame(i, 0, 8, 8, 0, 0, 0);
+ _screen->updateScreen();
+ }
+ delete _finalA;
+
+ _finalA = 0;
+ seq_playEnding();
+ return 1;
+ }
+ } else {
+ handleBeadState();
+ _screen->bitBlitRects();
+ _screen->updateScreen();
+ _screen->_curPage = 0;
+ }
+ return 0;
+}
+
+void KyraEngine_LoK::seq_brandonToStone() {
+ _screen->hideMouse();
+ assert(_brandonStoneTable);
+ setupShapes123(_brandonStoneTable, 14, 0);
+ _animator->setBrandonAnimSeqSize(5, 51);
+
+ for (int i = 123; i <= 136; ++i) {
+ _currentCharacter->currentAnimFrame = i;
+ _animator->animRefreshNPC(0);
+ delayWithTicks(8);
+ }
+
+ _animator->resetBrandonAnimSeqSize();
+ freeShapes123();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_playEnding() {
+ if (shouldQuit())
+ return;
+ _screen->hideMouse();
+ _screen->_curPage = 0;
+ _screen->fadeToBlack();
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ _screen->loadBitmap("GEMCUT.CPS", 3, 3, &_screen->getPalette(0));
+ _screen->copyRegion(232, 136, 176, 56, 56, 56, 2, 2);
+ _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 0, 2, Screen::CR_NO_P_CHECK);
+ } else {
+ _screen->loadBitmap("REUNION.CPS", 3, 3, &_screen->getPalette(0));
+ _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0);
+ }
+
+ _screen->_curPage = 0;
+ // XXX
+ assert(_homeString);
+ drawSentenceCommand(_homeString[0], 179);
+
+ _screen->getPalette(2).clear();
+ _screen->setScreenPalette(_screen->getPalette(2));
+
+ _seqPlayerFlag = true;
+ _seq->playSequence(_seq_Reunion, false);
+ _screen->fadeToBlack();
+ _seqPlayerFlag = false;
+
+ _screen->showMouse();
+
+ // To avoid any remaining input events, we remove the queue
+ // over here.
+ _eventList.clear();
+
+ if (_flags.platform == Common::kPlatformAmiga) {
+ _screen->_charWidth = -2;
+ _screen->setCurPage(2);
+
+ _screen->getPalette(2).clear();
+ _screen->setScreenPalette(_screen->getPalette(2));
+
+ while (!shouldQuit()) {
+ seq_playCreditsAmiga();
+ delayUntil(_system->getMillis() + 300 * _tickLength);
+ }
+ } else {
+ seq_playCredits();
+ }
+}
+
+namespace {
+struct CreditsLine {
+ int16 x, y;
+ Screen::FontId font;
+ uint8 *str;
+};
+} // end of anonymous namespace
+
+void KyraEngine_LoK::seq_playCredits() {
+ static const uint8 colorMap[] = { 0, 0, 0xC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ static const char stringTerms[] = { 0x5, 0xD, 0x0};
+
+ typedef Common::List<CreditsLine> CreditsLineList;
+ CreditsLineList lines;
+
+ _screen->enableInterfacePalette(false);
+
+ _screen->hideMouse();
+ if (!_flags.isTalkie) {
+ _screen->loadFont(Screen::FID_CRED6_FNT, "CREDIT6.FNT");
+ _screen->loadFont(Screen::FID_CRED8_FNT, "CREDIT8.FNT");
+
+ _screen->setFont(Screen::FID_CRED8_FNT);
+ } else
+ _screen->setFont(Screen::FID_8_FNT);
+
+ _screen->loadBitmap("CHALET.CPS", 4, 4, &_screen->getPalette(0));
+
+ _screen->setCurPage(0);
+ _screen->clearCurPage();
+ _screen->setTextColorMap(colorMap);
+ _screen->_charWidth = -1;
+
+ // we only need this for the FM-TOWNS version
+ if (_flags.platform == Common::kPlatformFMTowns && _configMusic == 1)
+ snd_playWanderScoreViaMap(53, 1);
+
+ uint8 *buffer = 0;
+ uint32 size = 0;
+
+ if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) {
+ int sizeTmp = 0;
+ const uint8 *bufferTmp = _staticres->loadRawData(k1CreditsStrings, sizeTmp);
+ buffer = new uint8[sizeTmp];
+ assert(buffer);
+ memcpy(buffer, bufferTmp, sizeTmp);
+ size = sizeTmp;
+ _staticres->unloadId(k1CreditsStrings);
+ } else {
+ buffer = _res->fileData("CREDITS.TXT", &size);
+ assert(buffer);
+ }
+
+ uint8 *nextString = buffer;
+ uint8 *currentString = buffer;
+ int currentY = 200;
+
+ do {
+ currentString = nextString;
+ nextString = (uint8 *)strpbrk((char *)currentString, stringTerms);
+ if (!nextString)
+ nextString = (uint8 *)strchr((char *)currentString, 0);
+
+ CreditsLine line;
+
+ int lineEndCode = nextString[0];
+ *nextString = 0;
+ if (lineEndCode != 0)
+ nextString++;
+
+ int alignment = 0;
+ if (*currentString == 3 || *currentString == 4) {
+ alignment = *currentString;
+ currentString++;
+ }
+
+ if (*currentString == 1) {
+ currentString++;
+
+ if (!_flags.isTalkie)
+ _screen->setFont(Screen::FID_CRED6_FNT);
+ } else if (*currentString == 2) {
+ currentString++;
+
+ if (!_flags.isTalkie)
+ _screen->setFont(Screen::FID_CRED8_FNT);
+ }
+
+ line.font = _screen->_currentFont;
+
+ if (alignment == 3)
+ line.x = 157 - _screen->getTextWidth((const char *)currentString);
+ else if (alignment == 4)
+ line.x = 161;
+ else
+ line.x = (320 - _screen->getTextWidth((const char *)currentString)) / 2 + 1;
+
+ line.y = currentY;
+ if (lineEndCode != 5)
+ currentY += 10;
+
+ line.str = currentString;
+
+ lines.push_back(line);
+ } while (*nextString);
+
+ _screen->setCurPage(2);
+
+ _screen->getPalette(2).clear();
+ _screen->setScreenPalette(_screen->getPalette(2));
+
+ _screen->copyRegion(0, 32, 0, 32, 320, 128, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->fadePalette(_screen->getPalette(0), 0x5A);
+
+ bool finished = false;
+ int bottom = 201;
+ while (!finished && !shouldQuit()) {
+ uint32 startLoop = _system->getMillis();
+
+ if (bottom > 175) {
+ _screen->copyRegion(0, 32, 0, 32, 320, 128, 4, 2, Screen::CR_NO_P_CHECK);
+ bottom = 0;
+
+ for (CreditsLineList::iterator it = lines.begin(); it != lines.end();) {
+ if (it->y < 0) {
+ it = lines.erase(it);
+ continue;
+ }
+
+ if (it->y < 200) {
+ if (it->font != _screen->_currentFont)
+ _screen->setFont(it->font);
+
+ _screen->printText((const char *)it->str, it->x, it->y, 15, 0);
+ }
+
+ it->y--;
+ if (it->y > bottom)
+ bottom = it->y;
+
+ ++it;
+ }
+
+ _screen->copyRegion(0, 32, 0, 32, 320, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ }
+
+ if (checkInput(0, false)) {
+ removeInputTop();
+ finished = true;
+ }
+
+ uint32 now = _system->getMillis();
+ uint32 nextLoop = startLoop + _tickLength * 5;
+
+ if (nextLoop > now)
+ _system->delayMillis(nextLoop - now);
+ }
+
+ delete[] buffer;
+
+ _screen->fadeToBlack();
+ _screen->clearCurPage();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::seq_playCreditsAmiga() {
+ _screen->setFont(Screen::FID_8_FNT);
+
+ _screen->loadBitmap("CHALET.CPS", 4, 2, &_screen->getPalette(0));
+ _screen->copyPage(2, 0);
+
+ _screen->getPalette(0).fill(16, 1, 63);
+ _screen->fadePalette(_screen->getPalette(0), 0x5A);
+ _screen->updateScreen();
+
+ const char *theEnd = "THE END";
+
+ const int width = _screen->getTextWidth(theEnd) + 1;
+ int x = (320 - width) / 2 + 1;
+
+ _screen->copyRegion(x, 8, x, 8, width, 56, 0, 2, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(x, 8, 0, 8, width, 11, 0, 2, Screen::CR_NO_P_CHECK);
+ _screen->printText(theEnd, 0, 10, 31, 0);
+
+ for (int y = 18, h = 1; y >= 10 && !shouldQuit(); --y, ++h) {
+ uint32 endTime = _system->getMillis() + 3 * _tickLength;
+
+ _screen->copyRegion(0, y, x, 8, width, h, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ delayUntil(endTime);
+ }
+
+ for (int y = 8; y <= 62 && !shouldQuit(); ++y) {
+ uint32 endTime = _system->getMillis() + 3 * _tickLength;
+
+ _screen->copyRegion(x, y, 0, 8, width, 11, 2, 2, Screen::CR_NO_P_CHECK);
+ _screen->printText(theEnd, 0, 9, 31, 0);
+ _screen->copyRegion(0, 8, x, y, width, 11, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ delayUntil(endTime);
+ }
+
+ int size = 0;
+ const char *creditsData = (const char *)_staticres->loadRawData(k1CreditsStrings, size);
+
+ char stringBuffer[81];
+ memset(stringBuffer, 0, sizeof(stringBuffer));
+
+ const char *cur = creditsData;
+ char *specialString = stringBuffer;
+ bool fillRectFlag = false, subWidth = false, centerFlag = false;
+ x = 0;
+ int specialX = 0;
+
+ const int fontHeight = _screen->getFontHeight();
+
+ do {
+ char code = *cur;
+
+ if (code == 3) {
+ fillRectFlag = subWidth = true;
+ } else if (code == 5) {
+ centerFlag = true;
+ } else if (code == 4) {
+ if (fillRectFlag) {
+ _screen->fillRect(0, 0, 319, 20, 0);
+
+ if (subWidth)
+ specialX = 157 - _screen->getTextWidth(stringBuffer);
+
+ _screen->printText(stringBuffer, specialX + 8, 0, 31, 0);
+ }
+
+ specialString = stringBuffer;
+ *specialString = 0;
+
+ x = 161;
+ } else if (code == 13) {
+ if (!fillRectFlag)
+ _screen->fillRect(0, 0, 319, 20, 0);
+
+ uint32 nextTime = _system->getMillis() + 8 * _tickLength;
+
+ if (centerFlag)
+ x = (320 - _screen->getTextWidth(stringBuffer)) / 2 - 8;
+
+ _screen->printText(stringBuffer, x + 8, 0, 31, 0);
+
+ for (int i = 0; i < fontHeight && !shouldQuit(); ++i) {
+ _screen->copyRegion(0, 141, 0, 140, 320, 59, 0, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, i, 0, 198, 320, 3, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ delayUntil(nextTime);
+ nextTime = _system->getMillis() + 8 * _tickLength;
+ }
+
+ specialString = stringBuffer;
+ *specialString = 0;
+
+ centerFlag = fillRectFlag = false;
+ } else {
+ *specialString++ = code;
+ *specialString = 0;
+ }
+
+ if (checkInput(0, false)) {
+ removeInputTop();
+ break;
+ }
+ } while (++cur != (creditsData + size) && !shouldQuit());
+}
+
+bool KyraEngine_LoK::seq_skipSequence() const {
+ return shouldQuit() || _abortIntroFlag;
+}
+
+int KyraEngine_LoK::handleMalcolmFlag() {
+ switch (_malcolmFlag) {
+ case 1:
+ _malcolmFrame = 0;
+ _malcolmFlag = 2;
+ _malcolmTimer2 = 0;
+ // fall through
+
+ case 2:
+ if (_system->getMillis() >= _malcolmTimer2) {
+ _finalA->displayFrame(_malcolmFrame, 0, 8, 46, 0, 0, 0);
+ _screen->updateScreen();
+ _malcolmTimer2 = _system->getMillis() + 8 * _tickLength;
+ ++_malcolmFrame;
+ if (_malcolmFrame > 13) {
+ _malcolmFlag = 3;
+ _malcolmTimer1 = _system->getMillis() + 180 * _tickLength;
+ }
+ }
+ break;
+
+ case 3:
+ if (_system->getMillis() < _malcolmTimer1) {
+ if (_system->getMillis() >= _malcolmTimer2) {
+ _malcolmFrame = _rnd.getRandomNumberRng(14, 17);
+ _finalA->displayFrame(_malcolmFrame, 0, 8, 46, 0, 0, 0);
+ _screen->updateScreen();
+ _malcolmTimer2 = _system->getMillis() + 8 * _tickLength;
+ }
+ } else {
+ _malcolmFlag = 4;
+ _malcolmFrame = 18;
+ }
+ break;
+
+ case 4:
+ if (_system->getMillis() >= _malcolmTimer2) {
+ _finalA->displayFrame(_malcolmFrame, 0, 8, 46, 0, 0, 0);
+ _screen->updateScreen();
+ _malcolmTimer2 = _system->getMillis() + 8 * _tickLength;
+ ++_malcolmFrame;
+ if (_malcolmFrame > 25) {
+ _malcolmFrame = 26;
+ _malcolmFlag = 5;
+ _beadStateVar = 1;
+ }
+ }
+ break;
+
+ case 5:
+ if (_system->getMillis() >= _malcolmTimer2) {
+ _finalA->displayFrame(_malcolmFrame, 0, 8, 46, 0, 0, 0);
+ _screen->updateScreen();
+ _malcolmTimer2 = _system->getMillis() + 8 * _tickLength;
+ ++_malcolmFrame;
+ if (_malcolmFrame > 31) {
+ _malcolmFrame = 32;
+ _malcolmFlag = 6;
+ }
+ }
+ break;
+
+ case 6:
+ if (_unkEndSeqVar4) {
+ if (_malcolmFrame <= 33 && _system->getMillis() >= _malcolmTimer2) {
+ _finalA->displayFrame(_malcolmFrame, 0, 8, 46, 0, 0, 0);
+ _screen->updateScreen();
+ _malcolmTimer2 = _system->getMillis() + 8 * _tickLength;
+ ++_malcolmFrame;
+ if (_malcolmFrame > 33) {
+ _malcolmFlag = 7;
+ _malcolmFrame = 32;
+ _unkEndSeqVar5 = 0;
+ }
+ }
+ }
+ break;
+
+ case 7:
+ if (_unkEndSeqVar5 == 1) {
+ _malcolmFlag = 8;
+ _malcolmFrame = 34;
+ } else if (_unkEndSeqVar5 == 2) {
+ _malcolmFlag = 3;
+ _malcolmTimer1 = _system->getMillis() + 180 * _tickLength;
+ }
+ break;
+
+ case 8:
+ if (_system->getMillis() >= _malcolmTimer2) {
+ _finalA->displayFrame(_malcolmFrame, 0, 8, 46, 0, 0, 0);
+ _screen->updateScreen();
+ _malcolmTimer2 = _system->getMillis() + 8 * _tickLength;
+ ++_malcolmFrame;
+ if (_malcolmFrame > 37) {
+ _malcolmFlag = 0;
+ _deathHandler = 8;
+ return 1;
+ }
+ }
+ break;
+
+ case 9:
+ snd_playSoundEffect(12);
+ snd_playSoundEffect(12);
+ for (int i = 0; i < 18; ++i) {
+ _malcolmTimer2 = _system->getMillis() + 4 * _tickLength;
+ _finalC->displayFrame(i, 0, 16, 50, 0, 0, 0);
+ _screen->updateScreen();
+ delayUntil(_malcolmTimer2);
+ }
+ snd_playWanderScoreViaMap(51, 1);
+ delay(60 * _tickLength);
+ _malcolmFlag = 0;
+ return 1;
+
+ case 10:
+ if (!_beadStateVar) {
+ handleBeadState();
+ _screen->bitBlitRects();
+ assert(_veryClever);
+ _text->printTalkTextMessage(_veryClever[0], 60, 31, 5, 0, 2);
+ _malcolmTimer2 = _system->getMillis() + 180 * _tickLength;
+ _malcolmFlag = 11;
+ }
+ break;
+
+ case 11:
+ if (_system->getMillis() >= _malcolmTimer2) {
+ _text->restoreTalkTextMessageBkgd(2, 0);
+ _malcolmFlag = 3;
+ _malcolmTimer1 = _system->getMillis() + 180 * _tickLength;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int KyraEngine_LoK::handleBeadState() {
+ static const int table1[] = {
+ -1, -2, -4, -5, -6, -7, -6, -5,
+ -4, -2, -1, 0, 1, 2, 4, 5,
+ 6, 7, 6, 5, 4, 2, 1, 0, 0
+ };
+
+ static const int table2[] = {
+ 0, 0, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 5, 5, 5, 4, 4,
+ 3, 3, 2, 2, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ switch (_beadStateVar) {
+ case 0:
+ if (_beadState1.x != -1 && _endSequenceBackUpRect) {
+ _screen->copyBlockToPage(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ }
+
+ _beadState1.x = -1;
+ _beadState1.tableIndex = 0;
+ _beadStateTimer1 = 0;
+ _beadStateTimer2 = 0;
+ _lastDisplayedPanPage = 0;
+ return 1;
+
+ case 1:
+ if (_beadState1.x != -1) {
+ if (_endSequenceBackUpRect) {
+ _screen->copyBlockToPage(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ }
+ _beadState1.x = -1;
+ _beadState1.tableIndex = 0;
+ }
+ _beadStateVar = 2;
+ break;
+
+ case 2:
+ if (_system->getMillis() >= _beadStateTimer1) {
+ int x = 0, y = 0;
+ _beadStateTimer1 = _system->getMillis() + 4 * _tickLength;
+ if (_beadState1.x == -1) {
+ assert(_panPagesTable);
+ _beadState1.width2 = _animator->fetchAnimWidth(_panPagesTable[19], 256);
+ _beadState1.width = ((_beadState1.width2 + 7) >> 3) + 1;
+ _beadState1.height = _animator->fetchAnimHeight(_panPagesTable[19], 256);
+ if (!_endSequenceBackUpRect) {
+ _endSequenceBackUpRect = new uint8[(_beadState1.width * _beadState1.height) << 3];
+ assert(_endSequenceBackUpRect);
+ memset(_endSequenceBackUpRect, 0, ((_beadState1.width * _beadState1.height) << 3) * sizeof(uint8));
+ }
+ x = _beadState1.x = 60;
+ y = _beadState1.y = 40;
+ initBeadState(x, y, x, 25, 8, &_beadState2);
+ } else {
+ if (processBead(_beadState1.x, _beadState1.y, x, y, &_beadState2)) {
+ _beadStateVar = 3;
+ _beadStateTimer2 = _system->getMillis() + 240 * _tickLength;
+ _unkEndSeqVar4 = 0;
+ _beadState1.dstX = _beadState1.x;
+ _beadState1.dstY = _beadState1.y;
+ return 0;
+ } else {
+ _screen->copyBlockToPage(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ _beadState1.x = x;
+ _beadState1.y = y;
+ }
+ }
+
+ _screen->copyRegionToBuffer(_screen->_curPage, x, y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->drawShape(2, _panPagesTable[_lastDisplayedPanPage++], x, y, 0, 0);
+
+ if (_lastDisplayedPanPage > 17)
+ _lastDisplayedPanPage = 0;
+
+ _screen->addBitBlitRect(x, y, _beadState1.width2, _beadState1.height);
+ }
+ break;
+
+ case 3:
+ if (_system->getMillis() >= _beadStateTimer1) {
+ _beadStateTimer1 = _system->getMillis() + 4 * _tickLength;
+ _screen->copyBlockToPage(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+
+ _beadState1.x = _beadState1.dstX + table1[_beadState1.tableIndex];
+ _beadState1.y = _beadState1.dstY + table2[_beadState1.tableIndex];
+ _screen->copyRegionToBuffer(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+
+ _screen->drawShape(2, _panPagesTable[_lastDisplayedPanPage++], _beadState1.x, _beadState1.y, 0, 0);
+ if (_lastDisplayedPanPage >= 17)
+ _lastDisplayedPanPage = 0;
+
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+
+ ++_beadState1.tableIndex;
+ if (_beadState1.tableIndex > 24) {
+ _beadState1.tableIndex = 0;
+ _unkEndSeqVar4 = 1;
+ }
+ if (_system->getMillis() > _beadStateTimer2 && _malcolmFlag == 7 && !_unkAmuletVar && !_text->printed()) {
+ snd_playSoundEffect(0x0B);
+ if (_currentCharacter->x1 > 233 && _currentCharacter->x1 < 305 && _currentCharacter->y1 > 85 && _currentCharacter->y1 < 105 &&
+ (_brandonStatusBit & 0x20)) {
+ _beadState1.unk8 = 290;
+ _beadState1.unk9 = 40;
+ _beadStateVar = 5;
+ } else {
+ _beadStateVar = 4;
+ _beadState1.unk8 = _currentCharacter->x1 - 4;
+ _beadState1.unk9 = _currentCharacter->y1 - 30;
+ }
+
+ if (_text->printed())
+ _text->restoreTalkTextMessageBkgd(2, 0);
+
+ initBeadState(_beadState1.x, _beadState1.y, _beadState1.unk8, _beadState1.unk9, 12, &_beadState2);
+ _lastDisplayedPanPage = 18;
+ }
+ }
+ break;
+
+ case 4:
+ if (_system->getMillis() >= _beadStateTimer1) {
+ int x = 0, y = 0;
+ _beadStateTimer1 = _system->getMillis() + _tickLength;
+ if (processBead(_beadState1.x, _beadState1.y, x, y, &_beadState2)) {
+ if (_brandonStatusBit & 20) {
+ _unkEndSeqVar5 = 2;
+ _beadStateVar = 6;
+ } else {
+ snd_playWanderScoreViaMap(52, 1);
+ snd_playSoundEffect(0x0C);
+ _unkEndSeqVar5 = 1;
+ _beadStateVar = 0;
+ }
+ } else {
+ _screen->copyBlockToPage(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ _beadState1.x = x;
+ _beadState1.y = y;
+ _screen->copyRegionToBuffer(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->drawShape(2, _panPagesTable[_lastDisplayedPanPage++], x, y, 0, 0);
+ if (_lastDisplayedPanPage > 17) {
+ _lastDisplayedPanPage = 0;
+ }
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ }
+ }
+ break;
+
+ case 5:
+ if (_system->getMillis() >= _beadStateTimer1) {
+ _beadStateTimer1 = _system->getMillis() + _tickLength;
+ int x = 0, y = 0;
+ if (processBead(_beadState1.x, _beadState1.y, x, y, &_beadState2)) {
+ if (_beadState2.dstX == 290) {
+ _screen->copyBlockToPage(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ uint32 nextRun = 0;
+ for (int i = 0; i < 8; ++i) {
+ nextRun = _system->getMillis() + _tickLength;
+ _finalB->displayFrame(i, 0, 224, 8, 0, 0, 0);
+ _screen->updateScreen();
+ delayUntil(nextRun);
+ }
+ snd_playSoundEffect(0x0D);
+ for (int i = 7; i >= 0; --i) {
+ nextRun = _system->getMillis() + _tickLength;
+ _finalB->displayFrame(i, 0, 224, 8, 0, 0, 0);
+ _screen->updateScreen();
+ delayUntil(nextRun);
+ }
+ initBeadState(_beadState1.x, _beadState1.y, 63, 60, 12, &_beadState2);
+ } else {
+ _screen->copyBlockToPage(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ _beadState1.x = -1;
+ _beadState1.tableIndex = 0;
+ _beadStateVar = 0;
+ _malcolmFlag = 9;
+ }
+ } else {
+ _screen->copyBlockToPage(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ _beadState1.x = x;
+ _beadState1.y = y;
+ _screen->copyRegionToBuffer(_screen->_curPage, _beadState1.x, _beadState1.y, _beadState1.width << 3, _beadState1.height, _endSequenceBackUpRect);
+ _screen->drawShape(2, _panPagesTable[_lastDisplayedPanPage++], x, y, 0, 0);
+ if (_lastDisplayedPanPage > 17)
+ _lastDisplayedPanPage = 0;
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ }
+ }
+ break;
+
+ case 6:
+ _screen->drawShape(2, _panPagesTable[19], _beadState1.x, _beadState1.y, 0, 0);
+ _screen->addBitBlitRect(_beadState1.x, _beadState1.y, _beadState1.width2, _beadState1.height);
+ _beadStateVar = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void KyraEngine_LoK::initBeadState(int x, int y, int x2, int y2, int unk, BeadState *ptr) {
+ ptr->unk9 = unk;
+ int xDiff = x2 - x;
+ int yDiff = y2 - y;
+ int unk1 = 0, unk2 = 0;
+ if (xDiff > 0)
+ unk1 = 1;
+ else if (xDiff == 0)
+ unk1 = 0;
+ else
+ unk1 = -1;
+
+
+ if (yDiff > 0)
+ unk2 = 1;
+ else if (yDiff == 0)
+ unk2 = 0;
+ else
+ unk2 = -1;
+
+ xDiff = ABS(xDiff);
+ yDiff = ABS(yDiff);
+
+ ptr->y = 0;
+ ptr->x = 0;
+ ptr->width = xDiff;
+ ptr->height = yDiff;
+ ptr->dstX = x2;
+ ptr->dstY = y2;
+ ptr->width2 = unk1;
+ ptr->unk8 = unk2;
+}
+
+int KyraEngine_LoK::processBead(int x, int y, int &x2, int &y2, BeadState *ptr) {
+ if (x == ptr->dstX && y == ptr->dstY)
+ return 1;
+
+ int xPos = x, yPos = y;
+ if (ptr->width >= ptr->height) {
+ for (int i = 0; i < ptr->unk9; ++i) {
+ ptr->y += ptr->height;
+ if (ptr->y >= ptr->width) {
+ ptr->y -= ptr->width;
+ yPos += ptr->unk8;
+ }
+ xPos += ptr->width2;
+ }
+ } else {
+ for (int i = 0; i < ptr->unk9; ++i) {
+ ptr->x += ptr->width;
+ if (ptr->x >= ptr->height) {
+ ptr->x -= ptr->height;
+ xPos += ptr->width2;
+ }
+ yPos += ptr->unk8;
+ }
+ }
+
+ int temp = ABS(x - ptr->dstX);
+ if (ptr->unk9 > temp)
+ xPos = ptr->dstX;
+ temp = ABS(y - ptr->dstY);
+ if (ptr->unk9 > temp)
+ yPos = ptr->dstY;
+ x2 = xPos;
+ y2 = yPos;
+ return 0;
+}
+
+void KyraEngine_LoK::setupPanPages() {
+ _screen->savePageToDisk("BKGD.PG", 2);
+ _screen->loadBitmap("BEAD.CPS", 3, 3, 0);
+ if (_flags.platform == Common::kPlatformMacintosh || _flags.platform == Common::kPlatformAmiga) {
+ int pageBackUp = _screen->_curPage;
+ _screen->_curPage = 2;
+
+ delete[] _panPagesTable[19];
+ _panPagesTable[19] = _screen->encodeShape(0, 0, 16, 9, 0);
+ assert(_panPagesTable[19]);
+
+ int curX = 16;
+ for (int i = 0; i < 19; ++i) {
+ delete[] _panPagesTable[i];
+ _panPagesTable[i] = _screen->encodeShape(curX, 0, 8, 5, 0);
+ assert(_panPagesTable[i]);
+ curX += 8;
+ }
+
+ _screen->_curPage = pageBackUp;
+ } else {
+ for (int i = 0; i <= 19; ++i) {
+ delete[] _panPagesTable[i];
+ _panPagesTable[i] = _seq->setPanPages(3, i);
+ assert(_panPagesTable[i]);
+ }
+ }
+ _screen->loadPageFromDisk("BKGD.PG", 2);
+}
+
+void KyraEngine_LoK::freePanPages() {
+ delete[] _endSequenceBackUpRect;
+ _endSequenceBackUpRect = 0;
+ for (int i = 0; i <= 19; ++i) {
+ delete[] _panPagesTable[i];
+ _panPagesTable[i] = 0;
+ }
+}
+
+void KyraEngine_LoK::closeFinalWsa() {
+ delete _finalA;
+ _finalA = 0;
+ delete _finalB;
+ _finalB = 0;
+ delete _finalC;
+ _finalC = 0;
+ freePanPages();
+ _endSequenceNeedLoading = 1;
+}
+
+void KyraEngine_LoK::updateKyragemFading() {
+ if (_flags.platform == Common::kPlatformAmiga) {
+ // The AMIGA version seems to have no fading for the Kyragem. The code does not
+ // alter the screen palette.
+ //
+ // TODO: Check this in the original.
+ return;
+ }
+
+ static const uint8 kyraGemPalette[0x28] = {
+ 0x3F, 0x3B, 0x38, 0x34, 0x32, 0x2F, 0x2C, 0x29, 0x25, 0x22,
+ 0x1F, 0x1C, 0x19, 0x16, 0x12, 0x0F, 0x0C, 0x0A, 0x06, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ if (_system->getMillis() < _kyragemFadingState.timerCount)
+ return;
+
+ _kyragemFadingState.timerCount = _system->getMillis() + 4 * _tickLength;
+
+ int palPos = 684;
+ for (int i = 0; i < 20; ++i) {
+ _screen->getPalette(0)[palPos++] = kyraGemPalette[i + _kyragemFadingState.rOffset];
+ _screen->getPalette(0)[palPos++] = kyraGemPalette[i + _kyragemFadingState.gOffset];
+ _screen->getPalette(0)[palPos++] = kyraGemPalette[i + _kyragemFadingState.bOffset];
+ }
+
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ switch (_kyragemFadingState.nextOperation) {
+ case 0:
+ --_kyragemFadingState.bOffset;
+ if (_kyragemFadingState.bOffset >= 1)
+ return;
+ _kyragemFadingState.nextOperation = 1;
+ break;
+
+ case 1:
+ ++_kyragemFadingState.rOffset;
+ if (_kyragemFadingState.rOffset < 19)
+ return;
+ _kyragemFadingState.nextOperation = 2;
+ break;
+
+ case 2:
+ --_kyragemFadingState.gOffset;
+ if (_kyragemFadingState.gOffset >= 1)
+ return;
+ _kyragemFadingState.nextOperation = 3;
+ break;
+
+ case 3:
+ ++_kyragemFadingState.bOffset;
+ if (_kyragemFadingState.bOffset < 19)
+ return;
+ _kyragemFadingState.nextOperation = 4;
+ break;
+
+ case 4:
+ --_kyragemFadingState.rOffset;
+ if (_kyragemFadingState.rOffset >= 1)
+ return;
+ _kyragemFadingState.nextOperation = 5;
+ break;
+
+ case 5:
+ ++_kyragemFadingState.gOffset;
+ if (_kyragemFadingState.gOffset < 19)
+ return;
+ _kyragemFadingState.nextOperation = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ _kyragemFadingState.timerCount = _system->getMillis() + 120 * _tickLength;
+}
+
+void KyraEngine_LoK::drawJewelPress(int jewel, int drawSpecial) {
+ _screen->hideMouse();
+ int shape = 0;
+
+ if (drawSpecial)
+ shape = 0x14E;
+ else
+ shape = jewel + 0x149;
+
+ snd_playSoundEffect(0x45);
+ _screen->drawShape(0, _shapes[shape], _amuletX2[jewel], _amuletY2[jewel], 0, 0);
+ _screen->updateScreen();
+ delayWithTicks(2);
+
+ if (drawSpecial)
+ shape = 0x148;
+ else
+ shape = jewel + 0x143;
+
+ _screen->drawShape(0, _shapes[shape], _amuletX2[jewel], _amuletY2[jewel], 0, 0);
+ _screen->updateScreen();
+ _screen->showMouse();
+}
+
+void KyraEngine_LoK::drawJewelsFadeOutStart() {
+ static const uint16 jewelTable1[] = { 0x164, 0x15F, 0x15A, 0x155, 0x150, 0xFFFF };
+ static const uint16 jewelTable2[] = { 0x163, 0x15E, 0x159, 0x154, 0x14F, 0xFFFF };
+ static const uint16 jewelTable3[] = { 0x166, 0x160, 0x15C, 0x157, 0x152, 0xFFFF };
+ static const uint16 jewelTable4[] = { 0x165, 0x161, 0x15B, 0x156, 0x151, 0xFFFF };
+ for (int i = 0; jewelTable1[i] != 0xFFFF; ++i) {
+ if (queryGameFlag(0x57))
+ _screen->drawShape(0, _shapes[jewelTable1[i]], _amuletX2[2], _amuletY2[2], 0, 0);
+ if (queryGameFlag(0x59))
+ _screen->drawShape(0, _shapes[jewelTable3[i]], _amuletX2[4], _amuletY2[4], 0, 0);
+ if (queryGameFlag(0x56))
+ _screen->drawShape(0, _shapes[jewelTable2[i]], _amuletX2[1], _amuletY2[1], 0, 0);
+ if (queryGameFlag(0x58))
+ _screen->drawShape(0, _shapes[jewelTable4[i]], _amuletX2[3], _amuletY2[3], 0, 0);
+ _screen->updateScreen();
+ delayWithTicks(3);
+ }
+}
+
+void KyraEngine_LoK::drawJewelsFadeOutEnd(int jewel) {
+ static const uint16 jewelTable[] = { 0x153, 0x158, 0x15D, 0x162, 0x148, 0xFFFF };
+ int newDelay = 0;
+
+ switch (jewel - 1) {
+ case 2:
+ if (_currentCharacter->sceneId >= 109 && _currentCharacter->sceneId <= 198)
+ newDelay = 18900;
+ else
+ newDelay = 8100;
+ break;
+
+ default:
+ newDelay = 3600;
+ }
+
+ setGameFlag(0xF1);
+ _timer->setCountdown(19, newDelay);
+ _screen->hideMouse();
+ for (int i = 0; jewelTable[i] != 0xFFFF; ++i) {
+ uint16 shape = jewelTable[i];
+ if (queryGameFlag(0x57))
+ _screen->drawShape(0, _shapes[shape], _amuletX2[2], _amuletY2[2], 0, 0);
+ if (queryGameFlag(0x59))
+ _screen->drawShape(0, _shapes[shape], _amuletX2[4], _amuletY2[4], 0, 0);
+ if (queryGameFlag(0x56))
+ _screen->drawShape(0, _shapes[shape], _amuletX2[1], _amuletY2[1], 0, 0);
+ if (queryGameFlag(0x58))
+ _screen->drawShape(0, _shapes[shape], _amuletX2[3], _amuletY2[3], 0, 0);
+
+ _screen->updateScreen();
+ delayWithTicks(3);
+ }
+ _screen->showMouse();
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/sequence/sequences_lol.cpp b/engines/kyra/sequence/sequences_lol.cpp
new file mode 100644
index 0000000000..55c0eb1493
--- /dev/null
+++ b/engines/kyra/sequence/sequences_lol.cpp
@@ -0,0 +1,1538 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_LOL
+
+#include "kyra/engine/lol.h"
+#include "kyra/graphics/screen_lol.h"
+#include "kyra/resource/resource.h"
+#include "kyra/sound/sound.h"
+
+#include "base/version.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+#pragma mark - Intro
+
+int LoLEngine::processPrologue() {
+ // There are two non-interactive demos (one which plays the intro and another one) which plays a number of specific scenes.
+ // We try to identify the latter one by looking for a specific file.
+ _res->loadPakFile("GENERAL.PAK");
+ if (_flags.isDemo && _res->exists("scene1.cps")) {
+ return playDemo();
+ } else {
+ setupPrologueData(true);
+ if (!saveFileLoadable(0) || _flags.isDemo)
+ showIntro();
+ }
+
+ if (_flags.isDemo) {
+ _screen->fadePalette(_screen->getPalette(1), 30, 0);
+ _screen->loadBitmap("FINAL.CPS", 2, 2, &_screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+ delayWithTicks(300);
+ _screen->fadePalette(_screen->getPalette(1), 60, 0);
+
+ setupPrologueData(false);
+ return -1;
+ }
+
+ preInit();
+
+ Common::String versionString(Common::String::format("ScummVM %s", gScummVMVersion));
+
+ int processSelection = -1;
+ while (!shouldQuit() && processSelection == -1) {
+ _screen->loadBitmap("TITLE.CPS", 2, 2, &_screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->setFont(Screen::FID_6_FNT);
+ // Original version: (260|193) "V CD1.02 D"
+ const int width = _screen->getTextWidth(versionString.c_str());
+ _screen->fprintString("%s", 320 - width, 193, 0x67, 0x00, 0x04, versionString.c_str());
+ _screen->setFont((_flags.lang == Common::JA_JPN && _flags.use16ColorMode) ? Screen::FID_SJIS_FNT : Screen::FID_9_FNT);
+
+ _screen->fadePalette(_screen->getPalette(0), 0x1E);
+ _screen->updateScreen();
+
+ _eventList.clear();
+ int selection = mainMenu();
+
+ if (selection != 3) {
+ _screen->hideMouse();
+
+ // Unlike the original, we add a nice fade to black
+ _screen->getPalette(0).clear();
+ _screen->fadeToBlack(0x54);
+ }
+
+ switch (selection) {
+ case -1:
+ // This is sent on RTL for example, if we would not have any
+ // special case for this the default path would call quitGame
+ // and thus make the next game launched from the launcher
+ // quit instantly.
+ break;
+
+ case 0: // New game
+ processSelection = 0;
+ break;
+
+ case 1: // Show intro
+ showIntro();
+ break;
+
+ case 2: { // "Lore of the Lands" (only CD version)
+ HistoryPlayer history(this);
+ history.play();
+ } break;
+
+ case 3: // Load game
+ if (_gui->runMenu(_gui->_loadMenu))
+ processSelection = 3;
+ break;
+
+ case 4: // Quit game
+ default:
+ quitGame();
+ updateInput();
+ }
+ }
+
+ if (processSelection == 0) {
+ _sound->loadSoundFile(0);
+ _sound->playTrack(6);
+ chooseCharacter();
+ _sound->playTrack(1);
+ _screen->fadeToBlack();
+ }
+
+ setupPrologueData(false);
+
+ return processSelection;
+}
+
+void LoLEngine::setupPrologueData(bool load) {
+ static const char *const fileListCD[] = {
+ "GENERAL.PAK", "INTROVOC.PAK", "STARTUP.PAK", "INTRO1.PAK",
+ "INTRO2.PAK", "INTRO3.PAK", "INTRO4.PAK", "INTRO5.PAK",
+ "INTRO6.PAK", "INTRO7.PAK", "INTRO8.PAK", "INTRO9.PAK",
+ "HISTORY.PAK", 0
+ };
+
+ static const char *const fileListFloppy[] = {
+ "INTRO.PAK", "INTROVOC.PAK", 0
+ };
+
+ static const char *const fileListTowns[] = {
+ "INTRO.PAK", "TINTROVO.PAK", 0
+ };
+
+ const char *const *fileList = _flags.isTalkie ? fileListCD : (_flags.platform == Common::kPlatformFMTowns ? fileListTowns : fileListFloppy);
+
+ char filename[32];
+ for (uint i = 0; fileList[i]; ++i) {
+ filename[0] = '\0';
+
+ if (_flags.isTalkie) {
+ strcpy(filename, _languageExt[_lang]);
+ strcat(filename, "/");
+ }
+
+ strcat(filename, fileList[i]);
+
+ if (load) {
+ if (!_res->loadPakFile(filename))
+ error("Couldn't load file: '%s'", filename);
+ } else {
+ _res->unloadPakFile(filename);
+ }
+ }
+
+ _screen->clearPage(0);
+ _screen->clearPage(3);
+
+ if (load) {
+ _chargenWSA = new WSAMovie_v2(this);
+ assert(_chargenWSA);
+
+ //_charSelection = -1;
+ _charSelectionInfoResult = -1;
+
+ _selectionAnimFrames[0] = _selectionAnimFrames[2] = 0;
+ _selectionAnimFrames[1] = _selectionAnimFrames[3] = 1;
+
+ memset(_selectionAnimTimers, 0, sizeof(_selectionAnimTimers));
+ _screen->getPalette(1).clear();
+
+ _sound->selectAudioResourceSet(kMusicIntro);
+
+ // We have three sound.dat files, one for the intro, one for the
+ // end sequence and one for ingame, each contained in a different
+ // PAK file. Therefore a new call to loadSoundFile() is required
+ // whenever the PAK file configuration changes.
+ if (_flags.platform == Common::kPlatformPC98)
+ _sound->loadSoundFile("SOUND.DAT");
+
+ if (_flags.isDemo)
+ _sound->loadSoundFile("LOREINTR");
+ } else {
+ delete _chargenWSA; _chargenWSA = 0;
+
+ _screen->getPalette(0).clear();
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ if (shouldQuit())
+ return;
+
+ _eventList.clear();
+ _sound->selectAudioResourceSet(kMusicIntro);
+ }
+}
+
+void LoLEngine::showIntro() {
+ _tim = new TIMInterpreter(this, _screen, _system);
+ assert(_tim);
+
+ if (_flags.platform == Common::kPlatformPC98)
+ showStarcraftLogo();
+
+ _screen->getPalette(0).clear();
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ _screen->clearPage(0);
+ _screen->clearPage(4);
+ _screen->clearPage(8);
+
+ TIM *intro = _tim->load("LOLINTRO.TIM", &_timIntroOpcodes);
+
+ _screen->loadFont(Screen::FID_8_FNT, "NEW8P.FNT");
+ _screen->loadFont(Screen::FID_INTRO_FNT, "INTRO.FNT");
+ _screen->setFont((_flags.lang == Common::JA_JPN && _flags.use16ColorMode) ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+
+ _tim->resetFinishedFlag();
+ _tim->setLangData("LOLINTRO.DIP");
+
+ _screen->hideMouse();
+
+ uint32 palNextFadeStep = 0;
+ while (!_tim->finished() && !shouldQuit() && !skipFlag()) {
+ updateInput();
+ _tim->exec(intro, false);
+ if (!_flags.isDemo && _flags.platform != Common::kPlatformPC98)
+ _screen->checkedPageUpdate(8, 4);
+
+ if (_tim->_palDiff) {
+ if (palNextFadeStep < _system->getMillis()) {
+ _tim->_palDelayAcc += _tim->_palDelayInc;
+ palNextFadeStep = _system->getMillis() + ((_tim->_palDelayAcc >> 8) * _tickLength);
+ _tim->_palDelayAcc &= 0xFF;
+
+ if (!_screen->fadePalStep(_screen->getPalette(0), _tim->_palDiff)) {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _tim->_palDiff = 0;
+ }
+ }
+ }
+
+ _system->delayMillis(10);
+ _screen->updateScreen();
+ }
+ _screen->showMouse();
+ _sound->voiceStop();
+ _sound->beginFadeOut();
+
+ _eventList.clear();
+
+ _tim->unload(intro);
+ _tim->clearLangData();
+
+ for (int i = 0; i < TIM::kWSASlots; i++)
+ _tim->freeAnimStruct(i);
+
+ delete _tim;
+ _tim = 0;
+
+ _screen->fadePalette(_screen->getPalette(1), 30, 0);
+}
+
+int LoLEngine::chooseCharacter() {
+ _tim = new TIMInterpreter(this, _screen, _system);
+ assert(_tim);
+
+ _tim->setLangData("LOLINTRO.DIP");
+
+ _screen->loadFont(Screen::FID_9_FNT, "FONT9P.FNT");
+
+ _screen->loadBitmap("ITEMICN.SHP", 3, 3, 0);
+ _screen->setMouseCursor(0, 0, _screen->getPtrToShape(_screen->getCPagePtr(3), 0));
+
+ while (!_screen->isMouseVisible())
+ _screen->showMouse();
+
+ _screen->loadBitmap("CHAR.CPS", 2, 2, &_screen->getPalette(0));
+ _screen->loadBitmap("BACKGRND.CPS", 4, 4, &_screen->getPalette(0));
+
+ if (!_chargenWSA->open("CHARGEN.WSA", 1, 0))
+ error("Couldn't load CHARGEN.WSA");
+
+ _chargenWSA->displayFrame(0, 2, 113, 0, 0, 0, 0);
+
+ _screen->setFont((_flags.lang == Common::JA_JPN && _flags.use16ColorMode) ? Screen::FID_SJIS_FNT : Screen::FID_9_FNT);
+ _screen->_curPage = 2;
+
+ if (_flags.platform == Common::kPlatformPC98 && _flags.use16ColorMode) {
+ _screen->fillRect(17, 29, 94, 97, 17);
+ _screen->fillRect(68, 167, 310, 199, 17);
+ _screen->drawClippedLine(68, 166, 311, 166, 238);
+ _screen->drawClippedLine(68, 166, 68, 199, 238);
+ _screen->drawClippedLine(311, 166, 311, 199, 238);
+
+ _screen->_curPage = 4;
+ _screen->fillRect(17, 29, 94, 97, 17);
+ _screen->_curPage = 2;
+
+ for (int i = 0; i < 4; ++i) {
+ _screen->printText(_charNamesJapanese[i], _charPosXPC98[i], 168, 0xC1, 0x00);
+
+ Screen::FontId old = _screen->setFont(Screen::FID_SJIS_FNT);
+ for (int j = 0; j < 3; ++j) {
+ Common::String attribString = Common::String::format("%2d", _charPreviews[i].attrib[j]);
+ _screen->printText(attribString.c_str(), _charPosXPC98[i] + 16, 176 + j * 8, 0x81, 0x00);
+ }
+ _screen->setFont(old);
+ }
+
+ _screen->printText(_tim->getCTableEntry(51), 72, 176, 0x81, 0x00);
+ _screen->printText(_tim->getCTableEntry(53), 72, 184, 0x81, 0x00);
+ _screen->printText(_tim->getCTableEntry(55), 72, 192, 0x81, 0x00);
+ } else {
+ const char *const *previewNames = (_flags.lang == Common::RU_RUS && !_flags.isTalkie) ? _charPreviewNamesRussianFloppy : (_flags.lang == Common::JA_JPN ? _charNamesJapanese : _charPreviewNamesDefault);
+ for (int i = 0; i < 4; ++i) {
+ _screen->fprintStringIntro("%s", _charPreviews[i].x + 16, _charPreviews[i].y + 36, 0xC0, 0x00, 0x9C, 0x120, previewNames[i]);
+ _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 48, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[0]);
+ _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 56, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[1]);
+ _screen->fprintStringIntro("%d", _charPreviews[i].x + 21, _charPreviews[i].y + 64, 0x98, 0x00, 0x9C, 0x220, _charPreviews[i].attrib[2]);
+ }
+
+ _screen->fprintStringIntro("%s", 36, 173, 0x98, 0x00, 0x9C, 0x20, _tim->getCTableEntry(51));
+ _screen->fprintStringIntro("%s", 36, 181, 0x98, 0x00, 0x9C, 0x20, _tim->getCTableEntry(53));
+ _screen->fprintStringIntro("%s", 36, 189, 0x98, 0x00, 0x9C, 0x20, _tim->getCTableEntry(55));
+ }
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->_curPage = 0;
+
+ if (_flags.use16ColorMode)
+ _screen->loadPalette("LOL.NOL", _screen->getPalette(0));
+
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+
+ bool kingIntro = true;
+ while (!shouldQuit()) {
+ if (kingIntro)
+ kingSelectionIntro();
+
+ if (_charSelection < 0)
+ processCharacterSelection();
+
+ if (shouldQuit())
+ break;
+
+ if (_charSelection == 100) {
+ kingIntro = true;
+ _charSelection = -1;
+ continue;
+ }
+
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _screen->showMouse();
+
+ if (selectionCharInfo(_charSelection) == -1) {
+ _charSelection = -1;
+ kingIntro = false;
+ } else {
+ break;
+ }
+
+ delay(10);
+ }
+
+ if (shouldQuit())
+ return -1;
+
+ uint32 waitTime = _system->getMillis() + 420 * _tickLength;
+ while (waitTime > _system->getMillis() && !skipFlag() && !shouldQuit()) {
+ updateInput();
+ _system->delayMillis(10);
+ }
+
+ // HACK: Remove all input events
+ _eventList.clear();
+
+ _tim->clearLangData();
+
+ delete _tim;
+ _tim = 0;
+
+ return _charSelection;
+}
+
+void LoLEngine::kingSelectionIntro() {
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ int y = 38;
+
+ if (_flags.platform == Common::kPlatformPC98) {
+ for (int i = 0; i < 5; ++i)
+ _screen->printText(_tim->getCTableEntry(57 + i), 16, 32 + i * 8, 0xC1, 0x00);
+ } else {
+ for (int i = 0; i < 5; ++i)
+ _screen->fprintStringIntro("%s", 8, y + i * 10, 0x32, 0x00, 0x9C, 0x20, _tim->getCTableEntry(57 + i));
+ }
+
+ if (_flags.isTalkie)
+ _sound->voicePlay("KING01", &_speechHandle);
+
+ int index = 4;
+ while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && _charSelection == -1 && !shouldQuit() && !skipFlag()) {
+ index = MAX(index, 4);
+
+ _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 113, 0, 0, 0, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar1IdxTable[index] * 2 + 0], _selectionPosTable[_selectionChar1IdxTable[index] * 2 + 1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar2IdxTable[index] * 2 + 0], _selectionPosTable[_selectionChar2IdxTable[index] * 2 + 1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar3IdxTable[index] * 2 + 0], _selectionPosTable[_selectionChar3IdxTable[index] * 2 + 1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar4IdxTable[index] * 2 + 0], _selectionPosTable[_selectionChar4IdxTable[index] * 2 + 1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0);
+ _screen->updateScreen();
+
+ uint32 waitEnd = _system->getMillis() + 7 * _tickLength;
+ while (waitEnd > _system->getMillis() && _charSelection == -1 && !shouldQuit() && !skipFlag()) {
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ if (speechEnabled())
+ index = (index + 1) % 22;
+ else if (++index >= 27)
+ break;
+ }
+
+ resetSkipFlag();
+
+ _chargenWSA->displayFrame(0x10, 0, 113, 0, 0, 0, 0);
+ _screen->updateScreen();
+ _sound->voiceStop(&_speechHandle);
+}
+
+void LoLEngine::kingSelectionReminder() {
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ int y = 48;
+
+ if (_flags.platform == Common::kPlatformPC98) {
+ _screen->printText(_tim->getCTableEntry(62), 16, 32, 0xC1, 0x00);
+ _screen->printText(_tim->getCTableEntry(63), 16, 40, 0xC1, 0x00);
+ } else {
+ _screen->fprintStringIntro("%s", 8, y, 0x32, 0x00, 0x9C, 0x20, _tim->getCTableEntry(62));
+ _screen->fprintStringIntro("%s", 8, y + 10, 0x32, 0x00, 0x9C, 0x20, _tim->getCTableEntry(63));
+ }
+
+ if (_flags.isTalkie)
+ _sound->voicePlay("KING02", &_speechHandle);
+
+ int index = 0;
+ while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && _charSelection == -1 && !shouldQuit() && index < 15) {
+ _chargenWSA->displayFrame(_chargenFrameTable[index + 9], 0, 113, 0, 0, 0, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar1IdxTable[index] * 2 + 0], _selectionPosTable[_reminderChar1IdxTable[index] * 2 + 1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar2IdxTable[index] * 2 + 0], _selectionPosTable[_reminderChar2IdxTable[index] * 2 + 1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar3IdxTable[index] * 2 + 0], _selectionPosTable[_reminderChar3IdxTable[index] * 2 + 1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar4IdxTable[index] * 2 + 0], _selectionPosTable[_reminderChar4IdxTable[index] * 2 + 1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0);
+ _screen->updateScreen();
+
+ uint32 waitEnd = _system->getMillis() + 8 * _tickLength;
+ while (waitEnd > _system->getMillis() && !shouldQuit()) {
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ if (speechEnabled())
+ index = (index + 1) % 22;
+ else if (++index >= 27)
+ break;
+ }
+
+ _sound->voiceStop(&_speechHandle);
+}
+
+void LoLEngine::kingSelectionOutro() {
+ if (_flags.isTalkie)
+ _sound->voicePlay("KING03", &_speechHandle);
+
+ int index = 0;
+ while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && !shouldQuit() && !skipFlag()) {
+ index = MAX(index, 4);
+
+ _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 113, 0, 0, 0, 0);
+ _screen->updateScreen();
+
+ uint32 waitEnd = _system->getMillis() + 8 * _tickLength;
+ while (waitEnd > _system->getMillis() && !shouldQuit() && !skipFlag()) {
+ updateInput();
+ _system->delayMillis(10);
+ }
+
+ if (speechEnabled())
+ index = (index + 1) % 22;
+ else if (++index >= 27)
+ break;
+ }
+
+ resetSkipFlag();
+
+ _chargenWSA->displayFrame(0x10, 0, 113, 0, 0, 0, 0);
+ _screen->updateScreen();
+ _sound->voiceStop(&_speechHandle);
+}
+
+void LoLEngine::processCharacterSelection() {
+ _charSelection = -1;
+ while (!shouldQuit() && _charSelection == -1) {
+ uint32 nextKingMessage = _system->getMillis() + 900 * _tickLength;
+
+ while (nextKingMessage > _system->getMillis() && _charSelection == -1 && !shouldQuit()) {
+ updateSelectionAnims();
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ if (_charSelection == -1)
+ kingSelectionReminder();
+ }
+}
+
+void LoLEngine::updateSelectionAnims() {
+ for (int i = 0; i < 4; ++i) {
+ if (_system->getMillis() < _selectionAnimTimers[i])
+ continue;
+
+ const int index = _selectionAnimIndexTable[_selectionAnimFrames[i] + i * 2];
+ _screen->copyRegion(_selectionPosTable[index * 2 + 0], _selectionPosTable[index * 2 + 1], _charPreviews[i].x, _charPreviews[i].y, 32, 32, 4, 0);
+
+ int delayTime = 0;
+ if (_selectionAnimFrames[i] == 1)
+ delayTime = _rnd.getRandomNumberRng(0, 31) + 80;
+ else
+ delayTime = _rnd.getRandomNumberRng(0, 3) + 10;
+
+ _selectionAnimTimers[i] = _system->getMillis() + delayTime * _tickLength;
+ _selectionAnimFrames[i] = (_selectionAnimFrames[i] + 1) % 2;
+ }
+
+ _screen->updateScreen();
+}
+
+int LoLEngine::selectionCharInfo(int character) {
+ if (character < 0)
+ return -1;
+
+ char filename[16];
+ char vocFilename[6];
+ strcpy(vocFilename, "000X0");
+
+ switch (character) {
+ case 0:
+ strcpy(filename, "FACE09.SHP");
+ vocFilename[3] = 'A';
+ break;
+
+ case 1:
+ strcpy(filename, "FACE01.SHP");
+ vocFilename[3] = 'M';
+ break;
+
+ case 2:
+ strcpy(filename, "FACE08.SHP");
+ vocFilename[3] = 'K';
+ break;
+
+ case 3:
+ strcpy(filename, "FACE05.SHP");
+ vocFilename[3] = 'C';
+ break;
+
+ default:
+ break;
+ }
+
+ _screen->loadBitmap(filename, 9, 9, 0);
+ _screen->copyRegion(0, 122, 0, 122, 320, 78, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(_charPreviews[character].x - 3, _charPreviews[character].y - 3, 8, 127, 38, 38, 2, 0);
+
+ static const uint8 charSelectInfoIdx[] = { 0x1D, 0x22, 0x27, 0x2C };
+ const int idx = charSelectInfoIdx[character];
+
+ if (_flags.platform == Common::kPlatformPC98) {
+ for (int i = 0; i < 5; ++i)
+ _screen->printText(_tim->getCTableEntry(idx + i), 60, 128 + i * 8, 0x41, 0x00);
+
+ _screen->printText(_tim->getCTableEntry(69), 112, 168, 0x01, 0x00);
+ } else {
+ for (int i = 0; i < 5; ++i)
+ _screen->fprintStringIntro("%s", 50, 127 + i * 10, 0x53, 0x00, 0xCF, 0x20, _tim->getCTableEntry(idx + i));
+
+ _screen->fprintStringIntro("%s", 100, 168, 0x32, 0x00, 0xCF, 0x20, _tim->getCTableEntry(69));
+ }
+
+ selectionCharInfoIntro(vocFilename);
+ if (_charSelectionInfoResult == -1) {
+ while (_charSelectionInfoResult == -1 && !shouldQuit()) {
+ _charSelectionInfoResult = selectionCharAccept();
+ _system->delayMillis(10);
+ }
+ }
+
+ if (_charSelectionInfoResult != 1) {
+ _charSelectionInfoResult = -1;
+ _screen->copyRegion(0, 122, 0, 122, 320, 78, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ return -1;
+ }
+
+ _screen->copyRegion(48, 127, 48, 127, 272, 60, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->hideMouse();
+ _screen->copyRegion(48, 127, 48, 160, 272, 35, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+
+ if (_flags.platform == Common::kPlatformPC98) {
+ for (int i = 0; i < 5; ++i)
+ _screen->printText(_tim->getCTableEntry(64 + i), 16, 32 + i * 8, 0xC1, 0x00);
+ } else {
+ for (int i = 0; i < 5; ++i)
+ _screen->fprintStringIntro("%s", 3, 28 + i * 10, 0x32, 0x00, 0x9C, 0x20, _tim->getCTableEntry(64 + i));
+ }
+
+ resetSkipFlag();
+ kingSelectionOutro();
+ return character;
+}
+
+void LoLEngine::selectionCharInfoIntro(char *file) {
+ int index = 0;
+ file[4] = '0';
+ bool processAnim = true;
+
+ while (_charSelectionInfoResult == -1 && !shouldQuit()) {
+ if (speechEnabled() && !_sound->isVoicePresent(file))
+ break;
+
+ if (_flags.isTalkie)
+ _sound->voicePlay(file, &_speechHandle);
+
+ int i = 0;
+ while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && _charSelectionInfoResult == -1 && !shouldQuit()) {
+ _screen->drawShape(0, _screen->getPtrToShape(_screen->getCPagePtr(9), _charInfoFrameTable[i]), 11, 130, 0, 0);
+ _screen->updateScreen();
+
+ uint32 nextFrame = _system->getMillis() + 8 * _tickLength;
+ while (nextFrame > _system->getMillis() && _charSelectionInfoResult == -1 && !shouldQuit()) {
+ _charSelectionInfoResult = selectionCharAccept();
+ _system->delayMillis(10);
+ }
+
+ if (speechEnabled() || processAnim)
+ i = (i + 1) % 32;
+ if (i == 0)
+ processAnim = false;
+ }
+
+ _sound->voiceStop(&_speechHandle);
+ file[4] = ++index + '0';
+ }
+
+ _screen->drawShape(0, _screen->getPtrToShape(_screen->getCPagePtr(9), 0), 11, 130, 0, 0);
+ _screen->updateScreen();
+}
+
+int LoLEngine::getCharSelection() {
+ int inputFlag = checkInput(0, false) & 0xCF;
+ removeInputTop();
+
+ if (inputFlag == 200) {
+ for (int i = 0; i < 4; ++i) {
+ if (_charPreviews[i].x <= _mouseX && _mouseX <= _charPreviews[i].x + 31 &&
+ _charPreviews[i].y <= _mouseY && _mouseY <= _charPreviews[i].y + 31)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+int LoLEngine::selectionCharAccept() {
+ int inputFlag = checkInput(0, false) & 0xCF;
+ removeInputTop();
+
+ if (inputFlag == 200) {
+ if (88 <= _mouseX && _mouseX <= 128 && 180 <= _mouseY && _mouseY <= 194)
+ return 1;
+ if (196 <= _mouseX && _mouseX <= 236 && 180 <= _mouseY && _mouseY <= 194)
+ return 0;
+ }
+
+ return -1;
+}
+
+void LoLEngine::showStarcraftLogo() {
+ WSAMovie_v2 *ci = new WSAMovie_v2(this);
+ assert(ci);
+
+ _screen->clearPage(0);
+ _screen->clearPage(2);
+
+ int endframe = ci->open("ci01.wsa", 0, &_screen->getPalette(0));
+ if (!ci->opened()) {
+ delete ci;
+ return;
+ }
+ _screen->hideMouse();
+ ci->displayFrame(0, 2, 32, 80, 0, 0, 0);
+ _screen->copyPage(2, 0);
+ _screen->fadeFromBlack();
+ int inputFlag = 0;
+ for (int i = 0; i < endframe; i++) {
+ inputFlag = checkInput(0) & 0xFF;
+ if (shouldQuit() || inputFlag)
+ break;
+ ci->displayFrame(i, 2, 32, 80, 0, 0, 0);
+ _screen->copyPage(2, 0);
+ _screen->updateScreen();
+ delay(4 * _tickLength);
+ }
+
+ if (!(shouldQuit() || inputFlag)) {
+ _sound->voicePlay("star2", &_speechHandle);
+ while (_sound->voiceIsPlaying(&_speechHandle) && !(shouldQuit() || inputFlag)) {
+ inputFlag = checkInput(0) & 0xFF;
+ delay(_tickLength);
+ }
+ }
+
+ _screen->fadeToBlack();
+ _screen->showMouse();
+
+ _eventList.clear();
+ delete ci;
+}
+
+// history player
+
+HistoryPlayer::HistoryPlayer(LoLEngine *vm) : _system(vm->_system), _vm(vm), _screen(vm->screen()) {
+ _x = _y = _width = _height = 0;
+ _frame = _fireFrame = 0;
+ _nextFireTime = 0;
+
+ _wsa = new WSAMovie_v2(vm);
+ assert(_wsa);
+ _fireWsa = new WSAMovie_v2(vm);
+ assert(_fireWsa);
+}
+
+HistoryPlayer::~HistoryPlayer() {
+ delete _wsa;
+ delete _fireWsa;
+}
+
+void HistoryPlayer::play() {
+ int dataSize = 0;
+ const char *data = (const char *)_vm->staticres()->loadRawData(kLoLHistory, dataSize);
+
+ if (!data)
+ error("Could not load history data");
+
+ _screen->loadFont(Screen::FID_9_FNT, "FONT9P.FNT");
+
+ Palette pal(256);
+ pal.fill(0, 256, 0);
+ _screen->fadePalette(pal, 0x1E);
+
+ _screen->loadBitmap("BACKGND.CPS", 8, 8, &pal);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 8, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 8, 2, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ _screen->fadePalette(pal, 0x82);
+
+ _screen->copyRegion(_x, _y, _x, _y, _width, _height, 2, 0);
+ _screen->updateScreen();
+
+ pal.fill(0, 256, 0);
+ _screen->setFont(Screen::FID_9_FNT);
+
+ char tempWsaFilename[16];
+ char voiceFilename[13];
+ // the 'a' *has* to be lowercase
+ strcpy(voiceFilename, "PS_1a");
+
+ int part = 0;
+ Sound *sound = _vm->sound();
+
+ Common::Functor0Mem<void, HistoryPlayer> palFade(this, &HistoryPlayer::updateFire);
+
+ for (; voiceFilename[3] <= '9' && !_vm->shouldQuit() && !_vm->skipFlag(); ++voiceFilename[3], voiceFilename[4] = 'a') {
+ while (!_vm->shouldQuit() && !_vm->skipFlag()) {
+ if (!sound->isVoicePresent(voiceFilename))
+ break;
+
+ if (data[part * 15] == voiceFilename[3] && data[part * 15 + 1] == voiceFilename[4]) {
+ switch (part) {
+ case 0:
+ loadWsa(&data[part * 15 + 2]);
+ playWsa(true);
+ sound->voicePlay(voiceFilename);
+ break;
+
+ case 1: case 2: case 8:
+ case 16: case 25:
+ sound->voicePlay(voiceFilename);
+ playWsa(true);
+ break;
+
+ case 3: case 7: case 10:
+ case 17: case 23: case 26:
+ sound->voicePlay(voiceFilename);
+ playWsa(true);
+ restoreWsaBkgd();
+ loadWsa(&data[part * 15 + 2]);
+ playWsa(true);
+ break;
+
+ case 6:
+ sound->voicePlay(voiceFilename);
+ playWsa(false);
+ restoreWsaBkgd();
+ loadWsa(&data[part * 15 + 2]);
+ playWsa(true);
+ _vm->delayWithTicks(30);
+ playWsa(true);
+ break;
+
+ case 9:
+ sound->voicePlay(voiceFilename);
+ loadWsa(&data[part * 15 + 2]);
+ playWsa(true);
+ break;
+
+ case 22:
+ playWsa(false);
+ restoreWsaBkgd();
+ loadWsa(&data[part * 15 + 2]);
+ _vm->delayWithTicks(30);
+ sound->voicePlay(voiceFilename);
+ playWsa(true);
+
+ strcpy(tempWsaFilename, &data[part * 15]);
+
+ for (int i = 1; i < 4 && !_vm->shouldQuit(); ++i) {
+ uint32 nextTime = _system->getMillis() + 30 * _vm->tickLength();
+ tempWsaFilename[8] = 'a' + i;
+
+ loadWsa(&tempWsaFilename[2]);
+ _vm->delayUntil(nextTime);
+
+ playWsa(true);
+ }
+
+ tempWsaFilename[8] = 'e';
+ loadWsa(&tempWsaFilename[2]);
+ break;
+
+ case 29:
+ sound->voicePlay(voiceFilename);
+ playWsa(false);
+ restoreWsaBkgd();
+ loadWsa(&data[part * 15 + 2]);
+
+ _fireWsa->open("FIRE.WSA", 0, 0);
+ playWsa(true);
+ _fireFrame = 0;
+
+ for (int i = 0; i < 12 && !_vm->shouldQuit(); ++i, ++_fireFrame) {
+ uint32 nextTime = _system->getMillis() + 3 * _vm->tickLength();
+
+ if (_fireFrame > 4)
+ _fireFrame = 0;
+
+ _fireWsa->displayFrame(_fireFrame, 0, 75, 51, 0, 0, 0);
+ _screen->updateScreen();
+ _vm->delayUntil(nextTime);
+ }
+
+ _screen->loadPalette("DRACPAL.PAL", pal);
+ _screen->fadePalette(pal, 0x78, &palFade);
+
+ while (sound->voiceIsPlaying() && !_vm->shouldQuit()) {
+ uint32 nextTime = _system->getMillis() + 3 * _vm->tickLength();
+
+ ++_fireFrame;
+ if (_fireFrame > 4)
+ _fireFrame = 0;
+
+ _fireWsa->displayFrame(_fireFrame, 0, 75, 51, 0, 0, 0);
+ _screen->updateScreen();
+ _vm->delayUntil(nextTime);
+ }
+
+ _fireFrame = 0;
+ for (int i = 0; i < 10; ++i, ++_fireFrame) {
+ uint32 nextTime = _system->getMillis() + 3 * _vm->tickLength();
+
+ if (_fireFrame > 4)
+ _fireFrame = 0;
+
+ _fireWsa->displayFrame(_fireFrame, 0, 75, 51, 0, 0, 0);
+ _screen->updateScreen();
+ _vm->delayUntil(nextTime);
+ }
+
+ break;
+
+ default:
+ sound->voicePlay(voiceFilename);
+ playWsa(false);
+ restoreWsaBkgd();
+ loadWsa(&data[part * 15 + 2]);
+ playWsa(true);
+ break;
+ }
+
+ ++part;
+ } else {
+ sound->voicePlay(voiceFilename);
+ }
+
+ while (sound->voiceIsPlaying() && !_vm->shouldQuit() && !_vm->skipFlag())
+ _vm->delay(10);
+
+ if (_vm->skipFlag())
+ sound->voiceStop();
+
+ ++voiceFilename[4];
+ }
+ }
+
+ if (_vm->skipFlag())
+ _vm->_eventList.clear();
+
+ pal.fill(0, 256, 63);
+ if (_fireWsa->opened())
+ _screen->fadePalette(pal, 0x3C, &palFade);
+ else
+ _screen->fadePalette(pal, 0x3C);
+
+ _screen->clearPage(0);
+ pal.fill(0, 256, 0);
+ _screen->fadePalette(pal, 0x3C);
+
+ if (_vm->skipFlag())
+ _vm->_eventList.clear();
+}
+
+void HistoryPlayer::loadWsa(const char *filename) {
+ if (_wsa->opened())
+ _wsa->close();
+
+ Palette pal(256);
+ if (!_wsa->open(filename, 3, &pal))
+ error("Could not load WSA file: '%s'", filename);
+ _screen->setScreenPalette(pal);
+
+ _x = _wsa->xAdd();
+ _y = _wsa->yAdd();
+ _width = _wsa->width();
+ _height = _wsa->height();
+ _frame = 1;
+}
+
+void HistoryPlayer::playWsa(bool direction) {
+ const int tickLength = _vm->tickLength();
+
+ for (int i = 0; i < 15 && !_vm->shouldQuit(); ++i) {
+ uint32 nextTime = _system->getMillis() + 3 * tickLength;
+
+ _wsa->displayFrame(_frame, 2, 0, 0, 0, 0, 0);
+ _screen->copyRegion(_x, _y, _x, _y, _width, _height, 2, 0);
+ _screen->updateScreen();
+ _vm->delayUntil(nextTime);
+
+ if (direction)
+ ++_frame;
+ else
+ --_frame;
+ }
+}
+
+void HistoryPlayer::restoreWsaBkgd() {
+ _screen->copyRegion(_x, _y, _x, _y, _width, _height, 8, 0);
+ _screen->copyRegion(_x, _y, _x, _y, _width, _height, 8, 2);
+ _screen->updateScreen();
+}
+
+void HistoryPlayer::updateFire() {
+ if (_system->getMillis() > _nextFireTime) {
+ _fireWsa->displayFrame(_fireFrame, 0, 75, 51, 0, 0, 0);
+ _fireFrame = (_fireFrame + 1) % 5;
+ _nextFireTime = _system->getMillis() + 4 * _vm->tickLength();
+ }
+
+ _screen->updateScreen();
+}
+
+// outro
+
+void LoLEngine::setupEpilogueData(bool load) {
+ static const char *const fileListCD[] = {
+ "GENERAL.PAK", "INTROVOC.PAK", "STARTUP.PAK",
+ "FINALE.PAK", "FINALE1.PAK", "FINALE2.PAK", 0
+ };
+
+ static const char *const fileListFloppy[] = {
+ "GENERAL.PAK", "INTRO.PAK", "FINALE1.PAK", "FINALE2.PAK", 0
+ };
+
+ static const char *const fileListTowns[] = {
+ "GENERAL.PAK", "INTRO.PAK", "FINALE1.PAK", "TFINALE2.PAK", 0
+ };
+
+ const char *const *fileList = _flags.isTalkie ? fileListCD : (_flags.platform == Common::kPlatformFMTowns ? fileListTowns : fileListFloppy);
+ assert(fileList);
+
+ char filename[32];
+ for (uint i = 0; fileList[i]; ++i) {
+ filename[0] = '\0';
+
+ if (_flags.isTalkie) {
+ strcpy(filename, _languageExt[_lang]);
+ strcat(filename, "/");
+ }
+
+ strcat(filename, fileList[i]);
+
+ if (load) {
+ if (!_res->loadPakFile(filename))
+ error("Couldn't load file: '%s'", filename);
+ } else {
+ _res->unloadPakFile(filename);
+ }
+ }
+
+ _screen->clearPage(0);
+ _screen->clearPage(3);
+
+ if (load) {
+ _sound->selectAudioResourceSet(kMusicFinale);
+
+ // We have three sound.dat files, one for the intro, one for the
+ // end sequence and one for ingame, each contained in a different
+ // PAK file. Therefore a new call to loadSoundFile() is required
+ // whenever the PAK file configuration changes.
+ if (_flags.platform == Common::kPlatformPC98)
+ _sound->loadSoundFile("SOUND.DAT");
+ } else {
+ _screen->getPalette(0).clear();
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ if (shouldQuit())
+ return;
+
+ _eventList.clear();
+ _sound->selectAudioResourceSet(kMusicIntro);
+ }
+}
+
+void LoLEngine::showOutro(int character, bool maxDifficulty) {
+ setupEpilogueData(true);
+ TIMInterpreter *timBackUp = _tim;
+ _tim = new TIMInterpreter(this, _screen, _system);
+
+ _screen->getPalette(0).clear();
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ _screen->clearPage(0);
+ _screen->clearPage(4);
+ _screen->clearPage(8);
+
+ TIM *outro = _tim->load("LOLFINAL.TIM", &_timOutroOpcodes);
+ assert(outro);
+ outro->lolCharacter = character;
+
+ _screen->loadFont(Screen::FID_6_FNT, "NEW6P.FNT");
+ _screen->loadFont(Screen::FID_INTRO_FNT, "INTRO.FNT");
+
+ _tim->resetFinishedFlag();
+ _tim->setLangData("LOLFINAL.DIP");
+
+ _screen->hideMouse();
+
+ uint32 palNextFadeStep = 0;
+ while (!_tim->finished() && !shouldQuit() && !skipFlag()) {
+ updateInput();
+ _tim->exec(outro, false);
+
+ if (_tim->_palDiff) {
+ if (palNextFadeStep < _system->getMillis()) {
+ _tim->_palDelayAcc += _tim->_palDelayInc;
+ palNextFadeStep = _system->getMillis() + ((_tim->_palDelayAcc >> 8) * _tickLength);
+ _tim->_palDelayAcc &= 0xFF;
+
+ if (!_screen->fadePalStep(_screen->getPalette(0), _tim->_palDiff)) {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _tim->_palDiff = 0;
+ }
+ }
+ }
+
+ _system->delayMillis(10);
+ _screen->updateScreen();
+ }
+ removeInputTop();
+ _screen->showMouse();
+ _sound->voiceStop();
+ _sound->beginFadeOut();
+
+ _eventList.clear();
+
+ _tim->unload(outro);
+
+ for (int i = 0; i < TIM::kWSASlots; i++)
+ _tim->freeAnimStruct(i);
+
+ _screen->fadeToBlack(30);
+
+ if (!shouldQuit())
+ showCredits();
+
+ _eventList.clear();
+
+ if (!shouldQuit()) {
+ switch (character) {
+ case 0:
+ _screen->loadBitmap("KIERAN.CPS", 3, 3, &_screen->getPalette(0));
+ break;
+
+ case 1:
+ _screen->loadBitmap("AK'SHEL.CPS", 3, 3, &_screen->getPalette(0));
+ break;
+
+ case 2:
+ _screen->loadBitmap("MICHAEL.CPS", 3, 3, &_screen->getPalette(0));
+ break;
+
+ case 3:
+ _screen->loadBitmap("CONRAD.CPS", 3, 3, &_screen->getPalette(0));
+ break;
+
+ default:
+ _screen->clearPage(3);
+ _screen->getPalette(0).clear();
+ }
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ if (maxDifficulty && !_flags.use16ColorMode)
+ _tim->displayText(0x8000, 0, 0xDC);
+ _screen->updateScreen();
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+
+ while (!checkInput(0) && !shouldQuit())
+ delay(_tickLength);
+
+ _screen->fadeToBlack(30);
+ }
+
+ _tim->clearLangData();
+ delete _tim;
+ _tim = timBackUp;
+
+ setupEpilogueData(false);
+}
+
+void LoLEngine::showCredits() {
+ for (int i = 0; i < 255; ++i)
+ _outroShapeTable[i] = i;
+
+ if (_flags.use16ColorMode)
+ for (int i = 1; i < 16; ++i)
+ _outroShapeTable[i] = (i << 4) | i;
+ else
+ _outroShapeTable[255] = 0;
+
+ _sound->haltTrack();
+ _sound->loadSoundFile("LOREFINL");
+ _sound->playTrack(4);
+
+ _screen->hideMouse();
+
+ static const uint8 colorMap[] = { 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6F, 0x6F, 0x6D };
+ _screen->_charWidth = 0;
+
+ _screen->loadBitmap("ROOM.CPS", 2, 2, &_screen->getPalette(0));
+
+ if (!_flags.use16ColorMode) {
+ _screen->setTextColorMap(colorMap);
+ _screen->getPalette(0).fill(_screen->getPalette(0).getNumColors() - 1, 1, 0);
+ }
+
+ _screen->fadeToBlack(30);
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->_charOffset = 0;
+
+ char *credits = 0;
+
+ if (_flags.platform == Common::kPlatformPC98) {
+ int size = 0;
+ const uint8 *internCredits = _staticres->loadRawData(kLoLCredits, size);
+ assert(size > 0);
+
+ credits = new char[size];
+ assert(credits);
+
+ memcpy(credits, internCredits, size);
+ _staticres->unloadId(kLoLCredits);
+ } else {
+ credits = (char *)_res->fileData("CREDITS.TXT", 0);
+ }
+
+ processCredits(credits, 21, 4, 5);
+ delete[] credits;
+
+ uint32 endTime = _system->getMillis() + 120 * _tickLength;
+ while (endTime > _system->getMillis() && !shouldQuit()) {
+ if (checkInput(0))
+ break;
+ delay(_tickLength);
+ }
+
+ _sound->beginFadeOut();
+ _screen->fadeToBlack(30);
+
+ _screen->clearCurPage();
+ _screen->updateScreen();
+ _screen->showMouse();
+}
+
+void LoLEngine::processCredits(char *t, int dimState, int page, int delayTime) {
+ if (!t)
+ return;
+
+ _screen->setScreenDim(dimState);
+ _screen->clearPage(page);
+ _screen->clearPage(6);
+
+ _screen->loadBitmap("DOOR.SHP", 5, 5, 0);
+ uint8 *doorShape = _screen->makeShapeCopy(_screen->getCPagePtr(5), 0);
+ assert(doorShape);
+
+ _screen->drawShape(0, doorShape, 0, 0, 22, 0x10);
+ _screen->drawShape(0, doorShape, 0, 0, 23, 0x11);
+
+ int curShapeFile = 0;
+ uint8 *shapes[12];
+ memset(shapes, 0, sizeof(shapes));
+
+ loadOutroShapes(curShapeFile++, shapes);
+ uint8 *monsterPal = 0;
+
+ if (_flags.use16ColorMode) {
+ _screen->loadPalette("LOL.NOL", _screen->getPalette(0));
+ } else {
+ monsterPal = _res->fileData("MONSTERS.PAL", 0);
+ assert(monsterPal);
+ _screen->getPalette(0).copy(monsterPal, 0, 40, 88);
+ }
+
+ _screen->fadePalette(_screen->getPalette(0), 30);
+
+ uint32 waitTimer = _system->getMillis();
+
+ struct CreditsString {
+ int16 x, y;
+ char *str;
+ uint8 code;
+ uint8 height;
+ uint8 alignment;
+ } strings[37];
+ memset(strings, 0, sizeof(strings));
+
+ int countStrings = 0;
+ char *str = t;
+
+ int frameCounter = 0;
+ int monsterAnimFrame = 0;
+ bool needNewShape = false;
+ bool doorRedraw = true;
+
+ uint8 *animBlock = new uint8[40960];
+ assert(animBlock);
+ memset(animBlock, 0, 40960);
+ int inputFlag = 0;
+
+ do {
+ while (_system->getMillis() < waitTimer && !shouldQuit())
+ delay(_tickLength);
+ waitTimer = _system->getMillis() + delayTime * _tickLength;
+
+ while (countStrings < 35 && str[0]) {
+ int y = 0;
+
+ if (!countStrings) {
+ y = _screen->_curDim->h;
+ } else {
+ y = strings[countStrings].y + strings[countStrings].height;
+ y += strings[countStrings].height >> 3;
+ }
+
+ char *curString = str;
+ str = (char *)strpbrk(str, "\x05\x0D");
+ if (!str)
+ str = strchr(curString, 0);
+
+ CreditsString &s = strings[countStrings + 1];
+ s.code = str[0];
+ str[0] = 0;
+
+ if (s.code)
+ ++str;
+
+ s.alignment = 0;
+ if (*curString == 3 || *curString == 4)
+ s.alignment = *curString++;
+
+ _screen->setFont(Screen::FID_6_FNT);
+
+ if (*curString == 1 || *curString == 2)
+ ++curString;
+ s.height = _screen->getFontHeight();
+
+ if (s.alignment == 3)
+ s.x = 0;
+ else if (s.alignment == 4)
+ s.x = 300 - _screen->getTextWidth(curString);
+ else
+ s.x = ((_screen->_curDim->w << 3) - _screen->getTextWidth(curString)) / 2;
+
+ if (strings[countStrings].code == 5)
+ y -= strings[countStrings].height + (strings[countStrings].height >> 3);
+
+ s.y = y;
+ s.str = curString;
+
+ // WORKAROUND: The original did supply some texts, which wouldn't fit on one line.
+ // To display them properly, we will break them into two separate entries. The original
+ // just did not display these lines at all. (At least not in LordHoto's tests with DOSBox).
+ if (s.x + _screen->getTextWidth(s.str) > Screen::SCREEN_W) {
+ char *nextLine = 0;
+ char *lastSeparator = 0;
+
+ int backupX = s.x;
+
+ while (s.x + _screen->getTextWidth(s.str) > Screen::SCREEN_W) {
+ char *sep = strrchr(s.str, ' ');
+
+ if (lastSeparator)
+ *lastSeparator = ' ';
+
+ lastSeparator = sep;
+
+ if (lastSeparator) {
+ *lastSeparator = 0;
+ nextLine = lastSeparator + 1;
+
+ s.x = MAX(((_screen->_curDim->w << 3) - _screen->getTextWidth(s.str)) / 2, 0);
+ } else {
+ // It seems we ca not find any whitespace, thus we are better safe and
+ // do not break up the line into two parts. (This is just paranoia)
+ nextLine = 0;
+ break;
+ }
+ }
+
+ s.x = backupX;
+
+ if (nextLine) {
+ ++countStrings;
+
+ // Center old string
+ s.alignment = 0;
+ s.x = ((_screen->_curDim->w << 3) - _screen->getTextWidth(s.str)) / 2;
+
+ // Add new string, also centered
+ CreditsString &n = strings[countStrings + 1];
+ n.y = s.y + s.height + (s.height >> 3);
+ n.height = s.height;
+ n.alignment = 0;
+ n.code = s.code;
+ n.str = nextLine;
+ n.x = ((_screen->_curDim->w << 3) - _screen->getTextWidth(n.str)) / 2;
+ }
+ }
+
+ ++countStrings;
+ }
+
+ ++frameCounter;
+ if (frameCounter % 3) {
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, page, Screen::CR_NO_P_CHECK);
+ } else {
+ if (!monsterAnimFrame && doorRedraw) {
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, page, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(page, doorShape, 0, 0, 22, 0x10);
+ _screen->drawShape(page, doorShape, 0, 0, 23, 0x11);
+
+ --frameCounter;
+ doorRedraw = false;
+ } else {
+ if (!monsterAnimFrame)
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, page, Screen::CR_NO_P_CHECK);
+
+ uint8 *monsterShape = shapes[_outroFrameTable[monsterAnimFrame]];
+
+ int doorSD = 0;
+ int doorX = 0, doorY = 0;
+ int monsterX = 0, monsterY = 0;
+
+ bool isRightMonster = ((curShapeFile - 1) & 1) != 0;
+
+ if (isRightMonster) {
+ doorSD = 23;
+ doorX = _outroRightDoorPos[monsterAnimFrame * 2 + 0];
+ doorY = _outroRightDoorPos[monsterAnimFrame * 2 + 1];
+
+ monsterX = _outroRightMonsterPos[monsterAnimFrame * 2 + 0];
+ monsterY = _outroRightMonsterPos[monsterAnimFrame * 2 + 1];
+
+ _screen->drawShape(page, doorShape, 0, 0, 22, 0x10);
+ } else {
+ doorSD = 22;
+ doorX = _outroLeftDoorPos[monsterAnimFrame * 2 + 0];
+ doorY = _outroLeftDoorPos[monsterAnimFrame * 2 + 1];
+
+ monsterX = _outroLeftMonsterPos[monsterAnimFrame * 2 + 0];
+ monsterY = _outroLeftMonsterPos[monsterAnimFrame * 2 + 1];
+
+ _screen->drawShape(page, doorShape, 0, 0, 23, 0x11);
+ }
+
+ if (monsterAnimFrame >= 8)
+ _screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 22) ? 0 : 1);
+
+ _screen->drawShape(page, monsterShape, monsterX, monsterY, 0, 0x104 | ((!isRightMonster || monsterAnimFrame < 20) ? 0 : 1), _outroShapeTable, 1, _outroMonsterScaleTableX[monsterAnimFrame], _outroMonsterScaleTableY[monsterAnimFrame]);
+
+ if (monsterAnimFrame < 8)
+ _screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 22) ? 0 : 1);
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, page, 6, Screen::CR_NO_P_CHECK);
+ doorRedraw = true;
+
+ monsterAnimFrame = (monsterAnimFrame + 1) % 24;
+ needNewShape = !monsterAnimFrame;
+ }
+ }
+
+ for (int i = 0; i < countStrings; ++i) {
+ CreditsString &s = strings[i + 1];
+ int x = s.x, y = s.y;
+
+ if (y < _screen->_curDim->h) {
+ _screen->_curPage = page;
+ _screen->setFont(Screen::FID_6_FNT);
+ if (_flags.use16ColorMode) {
+ _screen->printText(s.str, (_screen->_curDim->sx << 3) + x + 1, _screen->_curDim->sy + y + 1, 0x44, 0x00);
+ _screen->printText(s.str, (_screen->_curDim->sx << 3) + x, _screen->_curDim->sy + y, 0x33, 0x00);
+ } else {
+ _screen->printText(s.str, (_screen->_curDim->sx << 3) + x, _screen->_curDim->sy + y, 0xDC, 0x00);
+ }
+ _screen->_curPage = 0;
+ }
+
+ --s.y;
+ }
+
+ _screen->copyToPage0(_screen->_curDim->sy, _screen->_curDim->h, page, animBlock);
+
+ if (strings[1].y < -10) {
+ strings[1].str += strlen(strings[1].str);
+ strings[1].str[0] = strings[1].code;
+ --countStrings;
+ memmove(&strings[1], &strings[2], countStrings * sizeof(CreditsString));
+ }
+
+ if (needNewShape) {
+ ++curShapeFile;
+ if (curShapeFile == 16)
+ curShapeFile += 2;
+ if (curShapeFile == 6)
+ curShapeFile += 2;
+ curShapeFile = curShapeFile % 28;
+
+ loadOutroShapes(curShapeFile, shapes);
+
+ if (!_flags.use16ColorMode) {
+ _screen->getPalette(0).copy(monsterPal, curShapeFile * 40, 40, 88);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+
+ needNewShape = false;
+ }
+
+ _screen->updateScreen();
+ inputFlag = checkInput(0);
+ removeInputTop();
+ } while (countStrings && !(inputFlag && !(inputFlag & 0x800)) && !shouldQuit());
+ removeInputTop();
+
+ delete[] animBlock;
+ delete[] doorShape;
+ delete[] monsterPal;
+ for (int i = 0; i < 12; ++i)
+ delete[] shapes[i];
+}
+
+void LoLEngine::loadOutroShapes(int file, uint8 **storage) {
+ _screen->loadBitmap(_outroShapeFileTable[file], 5, 5, 0);
+
+ for (int i = 0; i < 12; ++i) {
+ delete[] storage[i];
+ if (i < 8)
+ storage[i] = _screen->makeShapeCopy(_screen->getCPagePtr(5), i);
+ else
+ storage[i] = _screen->makeShapeCopy(_screen->getCPagePtr(5), i + 4);
+ }
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_LOL
diff --git a/engines/kyra/sequence/sequences_mr.cpp b/engines/kyra/sequence/sequences_mr.cpp
new file mode 100644
index 0000000000..abfd0d8cbb
--- /dev/null
+++ b/engines/kyra/sequence/sequences_mr.cpp
@@ -0,0 +1,237 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/kyra_mr.h"
+#include "kyra/resource/resource.h"
+
+namespace Kyra {
+
+void KyraEngine_MR::showBadConscience() {
+ if (_badConscienceShown)
+ return;
+
+ _badConscienceShown = true;
+ _badConscienceAnim = _rnd.getRandomNumberRng(0, 2);
+ if (_currentChapter == 2)
+ _badConscienceAnim = 5;
+ else if (_currentChapter == 3)
+ _badConscienceAnim = 3;
+ else if (_currentChapter == 4 && _rnd.getRandomNumberRng(1, 100) <= 25)
+ _badConscienceAnim = 6;
+ else if (_currentChapter == 5 && _rnd.getRandomNumberRng(1, 100) <= 25)
+ _badConscienceAnim = 7;
+
+ if (_characterShapeFile == 9)
+ _badConscienceAnim = 4;
+
+ _badConsciencePosition = (_mainCharacter.x1 <= 160);
+
+ if (_goodConscienceShown)
+ _badConsciencePosition = !_goodConsciencePosition;
+
+ int anim = _badConscienceAnim + (_badConsciencePosition ? 0 : 8);
+ TalkObject &talkObject = _talkObjectList[1];
+
+ if (_badConsciencePosition)
+ talkObject.x = 290;
+ else
+ talkObject.x = 30;
+ talkObject.y = 30;
+
+ static const char *const animFilenames[] = {
+ "GUNFL00.WSA", "GUNFL01.WSA", "GUNFL02.WSA", "GUNFL03.WSA", "GUNFL04.WSA", "GUNFL05.WSA", "GUNFL06.WSA", "GUNFL07.WSA",
+ "GUNFR00.WSA", "GUNFR01.WSA", "GUNFR02.WSA", "GUNFR03.WSA", "GUNFR04.WSA", "GUNFR05.WSA", "GUNFR06.WSA", "GUNFR07.WSA"
+ };
+
+ setupSceneAnimObject(0x0E, 9, 0, 187, -1, -1, -1, -1, 0, 0, 0, -1, animFilenames[anim]);
+ for (uint i = 0; i <= _badConscienceFrameTable[_badConscienceAnim]; ++i) {
+ if (i == 8)
+ snd_playSoundEffect(0x1B, 0xC8);
+ updateSceneAnim(0x0E, i);
+ delay(3*_tickLength, true);
+ }
+
+ if (_mainCharacter.animFrame < 50 || _mainCharacter.animFrame > 87)
+ return;
+
+ if (_mainCharacter.y1 == -1 || (_mainCharacter.x1 != -1 && _mainCharacter.animFrame == 87) || _mainCharacter.animFrame == 87) {
+ _mainCharacter.animFrame = 87;
+ } else {
+ if (_badConsciencePosition)
+ _mainCharacter.facing = 3;
+ else
+ _mainCharacter.facing = 5;
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ }
+
+ updateCharacterAnim(0);
+ refreshAnimObjectsIfNeed();
+}
+
+void KyraEngine_MR::hideBadConscience() {
+ if (!_badConscienceShown)
+ return;
+
+ _badConscienceShown = false;
+ for (int frame = _badConscienceFrameTable[_badConscienceAnim+8]; frame >= 0; --frame) {
+ if (frame == 15)
+ snd_playSoundEffect(0x31, 0xC8);
+ updateSceneAnim(0x0E, frame);
+ delay(1*_tickLength, true);
+ }
+
+ updateSceneAnim(0x0E, -1);
+ update();
+ removeSceneAnimObject(0x0E, 1);
+ setNextIdleAnimTimer();
+}
+
+void KyraEngine_MR::showGoodConscience() {
+ if (_goodConscienceShown)
+ return;
+
+ _goodConscienceShown = true;
+ ++_goodConscienceAnim;
+ _goodConscienceAnim %= 5;
+
+ setNextIdleAnimTimer();
+ _goodConsciencePosition = (_mainCharacter.x1 <= 160);
+
+ if (_badConscienceShown)
+ _goodConsciencePosition = !_badConsciencePosition;
+
+ int anim = _goodConscienceAnim + (_goodConsciencePosition ? 0 : 5);
+ TalkObject &talkObject = _talkObjectList[87];
+
+ if (_goodConsciencePosition)
+ talkObject.x = 290;
+ else
+ talkObject.x = 30;
+ talkObject.y = 30;
+
+ static const char *const animFilenames[] = {
+ "STUFL00.WSA", "STUFL02.WSA", "STUFL04.WSA", "STUFL03.WSA", "STUFL01.WSA",
+ "STUFR00.WSA", "STUFR02.WSA", "STUFR04.WSA", "STUFR03.WSA", "STUFR01.WSA"
+ };
+
+ setupSceneAnimObject(0x0F, 9, 0, 187, -1, -1, -1, -1, 0, 0, 0, -1, animFilenames[anim]);
+ for (uint i = 0; i <= _goodConscienceFrameTable[_goodConscienceAnim]; ++i) {
+ if (i == 10)
+ snd_playSoundEffect(0x7F, 0xC8);
+ updateSceneAnim(0x0F, i);
+ delay(2*_tickLength, true);
+ }
+
+ if (_mainCharacter.animFrame < 50 || _mainCharacter.animFrame > 87)
+ return;
+
+ if (_mainCharacter.y1 == -1 || (_mainCharacter.x1 != -1 && _mainCharacter.animFrame == 87) || _mainCharacter.animFrame == 87) {
+ _mainCharacter.animFrame = 87;
+ } else {
+ if (_goodConsciencePosition)
+ _mainCharacter.facing = 3;
+ else
+ _mainCharacter.facing = 5;
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ }
+
+ updateCharacterAnim(0);
+ refreshAnimObjectsIfNeed();
+}
+
+void KyraEngine_MR::hideGoodConscience() {
+ if (!_goodConscienceShown)
+ return;
+
+ _goodConscienceShown = false;
+ for (int frame = _goodConscienceFrameTable[_goodConscienceAnim+5]; frame >= 0; --frame) {
+ if (frame == 17)
+ snd_playSoundEffect(0x31, 0xC8);
+ updateSceneAnim(0x0F, frame);
+ delay(1*_tickLength, true);
+ }
+
+ updateSceneAnim(0x0F, -1);
+ update();
+ removeSceneAnimObject(0x0F, 1);
+ setNextIdleAnimTimer();
+}
+
+void KyraEngine_MR::eelScript() {
+ if (_chatText)
+ return;
+ _screen->hideMouse();
+
+ if (_inventoryState)
+ hideInventory();
+ removeHandItem();
+
+ objectChat((const char *)getTableEntry(_cCodeFile, 35), 0, 204, 35);
+ objectChat((const char *)getTableEntry(_cCodeFile, 40), 0, 204, 40);
+
+ setGameFlag(0xD1);
+
+ snd_playSoundEffect(0x2A, 0xC8);
+
+ setGameFlag(0x171);
+
+ switch (_characterShapeFile-1) {
+ case 0:
+ runAnimationScript("EELS01.EMC", 0, 0, 1, 1);
+ break;
+
+ case 1:
+ runAnimationScript("EELS02.EMC", 0, 0, 1, 1);
+ break;
+
+ case 2:
+ runAnimationScript("EELS03.EMC", 0, 0, 1, 1);
+ break;
+
+ case 3:
+ runAnimationScript("EELS04.EMC", 0, 0, 1, 1);
+ break;
+
+ default:
+ resetGameFlag(0x171);
+ runAnimationScript("EELS00.EMC", 0, 0, 1, 1);
+ }
+
+ changeChapter(2, 29, 0, 4);
+ _screen->showMouse();
+}
+
+int KyraEngine_MR::initAnimationShapes(uint8 *filedata) {
+ const int lastEntry = MIN(_animShapeLastEntry, 41);
+ for (int i = 0; i < lastEntry; ++i)
+ _gameShapes[9+i] = _screen->getPtrToShape(filedata, i);
+ return lastEntry;
+}
+
+void KyraEngine_MR::uninitAnimationShapes(int count, uint8 *filedata) {
+ for (int i = 0; i < count; ++i)
+ _gameShapes[9+i] = 0;
+ delete[] filedata;
+ setNextIdleAnimTimer();
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/sequence/sequences_v2.cpp b/engines/kyra/sequence/sequences_v2.cpp
new file mode 100644
index 0000000000..4c32357684
--- /dev/null
+++ b/engines/kyra/sequence/sequences_v2.cpp
@@ -0,0 +1,130 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/engine/kyra_v2.h"
+#include "kyra/resource/resource.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void KyraEngine_v2::runAnimationScript(const char *filename, int allowSkip, int resetChar, int newShapes, int shapeUnload) {
+ memset(&_animationScriptData, 0, sizeof(_animationScriptData));
+ memset(&_animationScriptState, 0, sizeof(_animationScriptState));
+
+ if (!_emc->load(filename, &_animationScriptData, &_opcodesAnimation))
+ error("Couldn't load temporary script '%s'", filename);
+
+ _emc->init(&_animationScriptState, &_animationScriptData);
+ _emc->start(&_animationScriptState, 0);
+
+ _animResetFrame = -1;
+
+ if (_animShapeFiledata && newShapes) {
+ uninitAnimationShapes(_animShapeCount, _animShapeFiledata);
+ _animShapeFiledata = 0;
+ _animShapeCount = 0;
+ }
+
+ while (_emc->isValid(&_animationScriptState))
+ _emc->run(&_animationScriptState);
+
+ uint8 *fileData = 0;
+
+ if (newShapes)
+ _animShapeFiledata = _res->fileData(_animShapeFilename, 0);
+
+ fileData = _animShapeFiledata;
+
+ if (!fileData) {
+ _emc->unload(&_animationScriptData);
+ return;
+ }
+
+ if (newShapes)
+ _animShapeCount = initAnimationShapes(fileData);
+
+ processAnimationScript(allowSkip, resetChar);
+
+ if (shapeUnload) {
+ uninitAnimationShapes(_animShapeCount, fileData);
+ _animShapeCount = 0;
+ _animShapeFiledata = 0;
+ }
+
+ _emc->unload(&_animationScriptData);
+}
+
+void KyraEngine_v2::processAnimationScript(int allowSkip, int resetChar) {
+ setCharacterAnimDim(_animShapeWidth, _animShapeHeight);
+
+ _emc->init(&_animationScriptState, &_animationScriptData);
+ _emc->start(&_animationScriptState, 1);
+
+ resetSkipFlag();
+
+ while (_emc->isValid(&_animationScriptState)) {
+ _animNeedUpdate = false;
+ while (_emc->isValid(&_animationScriptState) && !_animNeedUpdate)
+ _emc->run(&_animationScriptState);
+
+ if (_animNewFrame < 0)
+ continue;
+
+ _mainCharacter.animFrame = _animNewFrame + _desc.animScriptFrameAdd;
+ updateCharacterAnim(0);
+ if (_chatText)
+ updateWithText();
+ else
+ update();
+
+ uint32 delayEnd = _system->getMillis() + _animDelayTime * _tickLength;
+
+ while ((!skipFlag() || !allowSkip) && _system->getMillis() < delayEnd)
+ delay(10, true);
+
+ if (skipFlag()) {
+ resetSkipFlag();
+ if (allowSkip)
+ break;
+ }
+ }
+
+ if (resetChar) {
+ if (_animResetFrame >= 0) {
+ _mainCharacter.animFrame = _animResetFrame + _desc.animScriptFrameAdd;
+ updateCharacterAnim(0);
+ if (_chatText)
+ updateWithText();
+ else
+ update();
+ }
+
+ _mainCharacter.animFrame = _desc.characterFrameTable[_mainCharacter.facing];
+ updateCharacterAnim(0);
+ }
+
+ _animResetFrame = -1;
+ resetCharacterAnimDim();
+}
+
+} // End of namespace Kyra