aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
authorJohannes Schickel2009-05-31 19:31:04 +0000
committerJohannes Schickel2009-05-31 19:31:04 +0000
commitede3dec88a291d7435708deec88f4108e383224b (patch)
treea04d8271925bb4f222fc90cb27d89742dd25a712 /engines/kyra
parentdad6073548ee02cd81dbfbc8457f6d8c0252d227 (diff)
downloadscummvm-rg350-ede3dec88a291d7435708deec88f4108e383224b.tar.gz
scummvm-rg350-ede3dec88a291d7435708deec88f4108e383224b.tar.bz2
scummvm-rg350-ede3dec88a291d7435708deec88f4108e383224b.zip
Add support for the Lands of Lore scrolling credits.
svn-id: r41081
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/lol.h18
-rw-r--r--engines/kyra/sequences_lok.cpp2
-rw-r--r--engines/kyra/sequences_lol.cpp271
-rw-r--r--engines/kyra/sprites_lol.cpp2
-rw-r--r--engines/kyra/staticres.cpp76
5 files changed, 361 insertions, 8 deletions
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
index 84b6386ccd..ae80f4384d 100644
--- a/engines/kyra/lol.h
+++ b/engines/kyra/lol.h
@@ -393,6 +393,24 @@ private:
void showOutro(int character, bool maxDifficulty);
void setupEpilogueData(bool load);
+ void showCredits();
+ void processCredits(char *text, int dimState, int page, int delay);
+ void loadOutroShapes(int file, uint8 **storage);
+
+ uint8 _outroShapeTable[256];
+
+ // TODO: Consider moving these tables to kyra.dat
+ static const char * const _outroShapeFileTable[];
+ static const uint8 _outroFrameTable[];
+
+ static const int16 _outroRightMonsterPos[];
+ static const int16 _outroLeftMonsterPos[];
+ static const int16 _outroRightDoorPos[];
+ static const int16 _outroLeftDoorPos[];
+
+ static const int _outroMonsterScaleTableX[];
+ static const int _outroMonsterScaleTableY[];
+
// timers
void setupTimers();
void enableTimer(int id);
diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp
index 7e5f4fc517..12ede98ad4 100644
--- a/engines/kyra/sequences_lok.cpp
+++ b/engines/kyra/sequences_lok.cpp
@@ -1024,7 +1024,7 @@ void KyraEngine_LoK::seq_playEnding() {
}
void KyraEngine_LoK::seq_playCredits() {
- static const uint8 colorMap[] = { 0, 0, 0xC, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ 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};
static const int numStrings = 250;
diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp
index fed09e3c3c..3cb203998a 100644
--- a/engines/kyra/sequences_lol.cpp
+++ b/engines/kyra/sequences_lol.cpp
@@ -750,9 +750,8 @@ void LoLEngine::showOutro(int character, bool maxDifficulty) {
assert(outro);
outro->lolCharacter = character;
- _screen->loadFont(Screen::FID_8_FNT, "NEW8P.FNT");
+ _screen->loadFont(Screen::FID_6_FNT, "NEW6P.FNT");
_screen->loadFont(Screen::FID_INTRO_FNT, "INTRO.FNT");
- _screen->setFont(Screen::FID_8_FNT);
_tim->resetFinishedFlag();
_tim->setLangData("LOLFINAL.DIP");
@@ -780,6 +779,7 @@ void LoLEngine::showOutro(int character, bool maxDifficulty) {
_system->delayMillis(10);
_screen->updateScreen();
}
+ removeInputTop();
_screen->showMouse();
_sound->voiceStop();
_sound->beginFadeOut();
@@ -793,7 +793,7 @@ void LoLEngine::showOutro(int character, bool maxDifficulty) {
_screen->fadeToBlack(30);
- //XXX
+ showCredits();
switch (character) {
case 0:
@@ -825,7 +825,7 @@ void LoLEngine::showOutro(int character, bool maxDifficulty) {
_screen->fadePalette(_screen->getPalette(0), 30, 0);
while (!checkInput(0) && !shouldQuit())
- delay(1);
+ delay(_tickLength);
_screen->fadeToBlack(30);
@@ -835,6 +835,269 @@ void LoLEngine::showOutro(int character, bool maxDifficulty) {
setupEpilogueData(false);
}
+void LoLEngine::showCredits() {
+ for (int i = 0; i < 255; ++i)
+ _outroShapeTable[i] = i;
+ _outroShapeTable[256] = 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->setTextColorMap(colorMap);
+ _screen->_charWidth = 0;
+
+ _screen->loadBitmap("ROOM.CPS", 2, 2, _screen->getPalette(0));
+ memset(_screen->getPalette(0) + 764, 0, 3);
+ _screen->fadeToBlack(30);
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+
+ char *credits = (char *)_res->fileData("CREDITS.TXT", 0);
+ processCredits(credits, 19, 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, 20, 0x10);
+ _screen->drawShape(0, doorShape, 0, 0, 21, 0x11);
+
+ int curShapeFile = 0;
+ uint8 *shapes[12];
+ memset(shapes, 0, sizeof(shapes));
+
+ loadOutroShapes(curShapeFile++, shapes);
+ uint8 *monsterPal = _res->fileData("MONSTERS.PAL", 0);
+ assert(monsterPal);
+
+ memcpy(_screen->getPalette(0) + 88 * 3, monsterPal + 0 * 3, 40 * 3);
+ _screen->fadePalette(_screen->getPalette(0), 30);
+
+ uint32 waitTimer = _system->getMillis();
+
+ struct CreditsString {
+ int16 x, y;
+ char *str;
+ uint8 code;
+ uint8 height;
+ uint8 alignment;
+ } strings[36];
+ 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);
+
+ 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;
+ ++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, 20, 0x10);
+ _screen->drawShape(page, doorShape, 0, 0, 21, 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 = 21;
+ 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, 20, 0x10);
+ } else {
+ doorSD = 20;
+ 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, 21, 0x11);
+ }
+
+ if (monsterAnimFrame >= 8)
+ _screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 20) ? 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 == 20) ? 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);
+ _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);
+ memcpy(_screen->getPalette(0) + 88 * 3, monsterPal + curShapeFile * 40 * 3, 40 * 3);
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ needNewShape = false;
+ }
+
+ _screen->updateScreen();
+ } while (countStrings && !checkInput(0) && !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/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp
index df1e062ae2..ccc4725827 100644
--- a/engines/kyra/sprites_lol.cpp
+++ b/engines/kyra/sprites_lol.cpp
@@ -117,7 +117,7 @@ void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int animTy
delete[] tmpPal1;
delete[] tmpPal2;
delete[] tmpPal3;
- delete[] tsh;
+ delete[] tsh;
}
void LoLEngine::releaseMonsterShapes(int monsterIndex) {
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 6c4985d608..8cc9ba17c2 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -3019,7 +3019,12 @@ const ScreenDim Screen_LoL::_screenDimTable256C[] = {
{ 0x0F, 0x06, 0x14, 0x6E, 0x01, 0x00, 0x00, 0x00 },
{ 0x1A, 0xBE, 0x0A, 0x07, 0xFE, 0x01, 0x00, 0x00 },
{ 0x0B, 0x8C, 0x10, 0x33, 0x3D, 0x01, 0x00, 0x00 }, // Main menu box (5 entries, CD version only)
- { 0x0B, 0x8C, 0x10, 0x23, 0x3D, 0x01, 0x00, 0x00 } // Main menu box (3 entries, floppy version only)
+ { 0x0B, 0x8C, 0x10, 0x23, 0x3D, 0x01, 0x00, 0x00 }, // Main menu box (3 entries, floppy version only)
+
+ { 0x01, 0x20, 0x26, 0x80, 0xDC, 0xFD, 0x00, 0x00 }, // Credits
+ { 0x09, 0x29, 0x08, 0x2C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x19, 0x29, 0x08, 0x2C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x01, 0x02, 0x26, 0x14, 0x00, 0x0F, 0x0E, 0x00 }
};
const ScreenDim Screen_LoL::_screenDimTable16C[] = {
@@ -3041,7 +3046,12 @@ const ScreenDim Screen_LoL::_screenDimTable16C[] = {
{ 0x0F, 0x06, 0x14, 0x6E, 0x44, 0x00, 0x00, 0x00 },
{ 0x1A, 0xBE, 0x0A, 0x07, 0x33, 0x44, 0x00, 0x00 },
{ 0x0B, 0x8C, 0x10, 0x33, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (5 entries, not used here)
- { 0x0B, 0x8C, 0x10, 0x23, 0x33, 0x44, 0x00, 0x00 } // Main menu box (3 entries)
+ { 0x0B, 0x8C, 0x10, 0x23, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (3 entries)
+
+ { 0x01, 0x20, 0x26, 0x80, 0xDC, 0xFD, 0x00, 0x00 }, // Credits (TODO: Check this!)
+ { 0x09, 0x29, 0x08, 0x2C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x19, 0x29, 0x08, 0x2C, 0x00, 0x00, 0x00, 0x00 },
+ { 0x01, 0x02, 0x26, 0x14, 0x00, 0x0F, 0x0E, 0x00 }
};
const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable256C);
@@ -3158,6 +3168,68 @@ const int8 LoLEngine::_mapCoords[12][4] = {
const uint8 LoLEngine::_numClock2Timers = ARRAYSIZE(LoLEngine::_clock2Timers);
+const char * const LoLEngine::_outroShapeFileTable[] = {
+ "AMAZON.SHP", "ARCHRSLG.SHP", "AVIANWRM.SHP", "BANDIT.SHP", "BOAR.SHP", "CABAL.SHP",
+ "GUARD.SHP", "HAG.SHP", "HORNET.SHP", "HURZELL.SHP", "IRONGRZR.SHP", "KNOWLES.SHP",
+ "LIZARD.SHP", "MANTHA.SHP", "MINOTAUR.SHP", "MORIBUND.SHP", "ORC.SHP", "ORCLDR.SHP",
+ "PENTROG.SHP", "RATMAN.SHP", "ROCKLING.SHP", "SCAVNGR.SHP", "STARK.SHP",
+ "SWAMPCIT.SHP", "SWAMPMON.SHP", "THUG.SHP", "VIPER.SHP", "XEOB.SHP"
+};
+
+const uint8 LoLEngine::_outroFrameTable[] = {
+ 0, 0, 0, 0, 0, 1, 2, 3,
+ 0, 1, 2, 3, 8, 9, 10, 11,
+ 8, 9, 10, 11, 4, 5, 6, 7
+};
+
+const int16 LoLEngine::_outroRightMonsterPos[] = {
+ 205, 55, 205, 55, 205, 55, 205, 55,
+ 205, 56, 207, 57, 208, 58, 210, 59,
+ 213, 60, 216, 61, 220, 61, 225, 61,
+ 230, 61, 235, 61, 240, 61, 240, 61,
+ 240, 61, 240, 61, 240, 61, 240, 61,
+ 240, 61, 265, 61, 290, 61, 315, 61
+};
+
+const int16 LoLEngine::_outroLeftMonsterPos[] = {
+ 92, 55, 92, 55, 92, 55, 92, 55,
+ 92, 56, 90, 57, 85, 58, 77, 59,
+ 67, 60, 57, 61, 47, 61, 35, 61,
+ 35, 61, 35, 61, 35, 61, 35, 61,
+ 35, 61, 35, 61, 35, 61, 35, 61,
+ 35, 61, 10, 61, -20, 61, -45, 61
+};
+
+const int16 LoLEngine::_outroRightDoorPos[] = {
+ 200, 41, 200, 29, 200, 17, 200, 5,
+ 200, -7, 200, -7, 200, -7, 200, -7,
+ 200, 5, 200, 17, 200, 29, 200, 41,
+ 200, 41, 200, 41, 200, 41, 200, 41,
+ 200, 41, 200, 41, 200, 41, 200, 41,
+ 200, 41, 200, 41, 200, 41, 200, 41
+};
+
+const int16 LoLEngine::_outroLeftDoorPos[] = {
+ 72, 41, 72, 29, 72, 17, 72, 5,
+ 72, -7, 72, -7, 72, -7, 72, -7,
+ 72, 5, 72, 17, 72, 29, 72, 41,
+ 72, 41, 72, 41, 72, 41, 72, 41,
+ 72, 41, 72, 41, 72, 41, 72, 41,
+ 72, 41, 72, 41, 72, 41, 72, 41
+};
+
+const int LoLEngine::_outroMonsterScaleTableX[] = {
+ 0x050, 0x050, 0x050, 0x050, 0x050, 0x05D, 0x070, 0x085,
+ 0x0A0, 0x0C0, 0x0E2, 0x100, 0x100, 0x100, 0x100, 0x100,
+ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100
+};
+
+const int LoLEngine::_outroMonsterScaleTableY[] = {
+ 0x04C, 0x04C, 0x04C, 0x04C, 0x04C, 0x059, 0x06B, 0x080,
+ 0x099, 0x0B8, 0x0D9, 0x100, 0x100, 0x100, 0x100, 0x100,
+ 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100
+};
+
#endif // ENABLE_LOL
} // End of namespace Kyra