aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/sequence
diff options
context:
space:
mode:
authorathrxx2019-01-26 01:31:34 +0100
committerathrxx2019-03-06 20:48:15 +0100
commit1dfdcc7252ac83643cae7a7447c025da2af63843 (patch)
treeb6736d006bf67d5264dd171c336f0915695d1f88 /engines/kyra/sequence
parent8b53d20b51771680c3d31aa02c0285b7a8be4e85 (diff)
downloadscummvm-rg350-1dfdcc7252ac83643cae7a7447c025da2af63843.tar.gz
scummvm-rg350-1dfdcc7252ac83643cae7a7447c025da2af63843.tar.bz2
scummvm-rg350-1dfdcc7252ac83643cae7a7447c025da2af63843.zip
KYRA: cleanup dir
Reorganize all files in sub directories. The file placement isn't as intuitive as it might be for other engines, which is probably the reason why this hasn't been done before.
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