aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/kyra/detection.cpp57
-rw-r--r--engines/kyra/kyra_hof.cpp2
-rw-r--r--engines/kyra/kyra_v1.h3
-rw-r--r--engines/kyra/lol.cpp806
-rw-r--r--engines/kyra/lol.h155
-rw-r--r--engines/kyra/module.mk2
-rw-r--r--engines/kyra/resource.cpp16
-rw-r--r--engines/kyra/screen_lol.cpp69
-rw-r--r--engines/kyra/screen_lol.h53
-rw-r--r--engines/kyra/screen_v2.cpp22
-rw-r--r--engines/kyra/screen_v2.h2
-rw-r--r--engines/kyra/script_tim.cpp401
-rw-r--r--engines/kyra/script_tim.h63
-rw-r--r--engines/kyra/sound_adlib.cpp9
-rw-r--r--engines/kyra/staticres.cpp107
15 files changed, 1736 insertions, 31 deletions
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index fce1e93bc2..2d592069d2 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -26,6 +26,7 @@
#include "kyra/kyra_lok.h"
#include "kyra/kyra_hof.h"
#include "kyra/kyra_mr.h"
+#include "kyra/lol.h"
#include "common/config-manager.h"
#include "common/advancedDetector.h"
@@ -64,6 +65,8 @@ namespace {
#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, false, Kyra::GI_KYRA3)
#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, false, Kyra::GI_KYRA3)
+#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_LOL)
+
const KYRAGameDescription adGameDescs[] = {
{
{
@@ -700,6 +703,56 @@ const KYRAGameDescription adGameDescs[] = {
},
KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA)
},
+
+ // Lands of Lore CD
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
+ {
+ {
+ "lol",
+ "CD",
+ {
+ { "GENERAL.PAK", 0, "05a4f588fb81dc9c0ef1f2ec20d89e24", -1 },
+ { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ Common::ADGF_DROPLANGUAGE | Common::ADGF_CD
+ },
+ LOL_CD_FLAGS
+ },
+
{ AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) }
};
@@ -707,6 +760,7 @@ const PlainGameDescriptor gameList[] = {
{ "kyra1", "The Legend of Kyrandia" },
{ "kyra2", "The Legend of Kyrandia: The Hand of Fate" },
{ "kyra3", "The Legend of Kyrandia: Malcolm's Revenge" },
+ { "lol", "Lands of Lore: The Throne of Chaos" },
{ 0, 0 }
};
@@ -779,6 +833,9 @@ bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common
case Kyra::GI_KYRA3:
*engine = new Kyra::KyraEngine_MR(syst, flags);
break;
+ case Kyra::GI_LOL:
+ *engine = new Kyra::LoLEngine(syst, flags);
+ break;
default:
res = false;
warning("Kyra engine: unknown gameID");
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 879efab86e..d3de621707 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -230,7 +230,7 @@ int KyraEngine_HoF::init() {
_gui = new GUI_HoF(this);
assert(_gui);
_gui->initStaticData();
- _tim = new TIMInterpreter(this, _system);
+ _tim = new TIMInterpreter(this, _screen, _system);
assert(_tim);
if (_flags.isDemo && !_flags.isTalkie) {
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index 09efc8cc97..50cabc421e 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -64,7 +64,8 @@ struct GameFlags {
enum {
GI_KYRA1 = 0,
GI_KYRA2 = 1,
- GI_KYRA3 = 2
+ GI_KYRA3 = 2,
+ GI_LOL = 4
};
struct AudioDataStruct {
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
new file mode 100644
index 0000000000..ef1121baa0
--- /dev/null
+++ b/engines/kyra/lol.cpp
@@ -0,0 +1,806 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "kyra/lol.h"
+#include "kyra/screen_lol.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+#include "common/endian.h"
+
+namespace Kyra {
+
+LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(system, flags) {
+ _screen = 0;
+
+ switch (_flags.lang) {
+ case Common::EN_ANY:
+ case Common::EN_USA:
+ case Common::EN_GRB:
+ _lang = 0;
+ break;
+
+ case Common::FR_FRA:
+ _lang = 1;
+ break;
+
+ case Common::DE_DEU:
+ _lang = 2;
+ break;
+
+ default:
+ warning("unsupported language, switching back to English");
+ _lang = 0;
+ break;
+ }
+
+ _chargenWSA = 0;
+}
+
+LoLEngine::~LoLEngine() {
+ setupPrologueData(false);
+
+ delete _screen;
+ delete _tim;
+
+ for (Common::Array<const TIMOpcode*>::iterator i = _timIntroOpcodes.begin(); i != _timIntroOpcodes.end(); ++i)
+ delete *i;
+ _timIntroOpcodes.clear();
+}
+
+Screen *LoLEngine::screen() {
+ return _screen;
+}
+
+int LoLEngine::init() {
+ _screen = new Screen_LoL(this, _system);
+ assert(_screen);
+ _screen->setResolution();
+
+ KyraEngine_v1::init();
+
+ _tim = new TIMInterpreter(this, _screen, _system);
+ assert(_tim);
+
+ _screen->setAnimBlockPtr(10000);
+ _screen->setScreenDim(0);
+
+ return 0;
+}
+
+int LoLEngine::go() {
+ setupPrologueData(true);
+ showIntro();
+ _sound->playTrack(6);
+ /*int character = */chooseCharacter();
+ _sound->playTrack(1);
+ _screen->fadeToBlack();
+ setupPrologueData(false);
+
+ return 0;
+}
+
+#pragma mark - Input
+
+int LoLEngine::checkInput(Button *buttonList, bool mainLoop) {
+ debugC(9, kDebugLevelMain, "LoLEngine::checkInput(%p, %d)", (const void*)buttonList, mainLoop);
+ updateInput();
+
+ int keys = 0;
+ int8 mouseWheel = 0;
+
+ while (_eventList.size()) {
+ Common::Event event = *_eventList.begin();
+ bool breakLoop = false;
+
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ /*if (event.kbd.keycode >= '1' && event.kbd.keycode <= '9' &&
+ (event.kbd.flags == Common::KBD_CTRL || event.kbd.flags == Common::KBD_ALT) && mainLoop) {
+ const char *saveLoadSlot = getSavegameFilename(9 - (event.kbd.keycode - '0') + 990);
+
+ if (event.kbd.flags == Common::KBD_CTRL) {
+ loadGame(saveLoadSlot);
+ _eventList.clear();
+ breakLoop = true;
+ } else {
+ char savegameName[14];
+ sprintf(savegameName, "Quicksave %d", event.kbd.keycode - '0');
+ saveGame(saveLoadSlot, savegameName);
+ }
+ } else if (event.kbd.flags == Common::KBD_CTRL) {
+ if (event.kbd.keycode == 'd')
+ _debugger->attach();
+ }*/
+ break;
+
+ case Common::EVENT_MOUSEMOVE: {
+ Common::Point pos = getMousePos();
+ _mouseX = pos.x;
+ _mouseY = pos.y;
+ } break;
+
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP: {
+ Common::Point pos = getMousePos();
+ _mouseX = pos.x;
+ _mouseY = pos.y;
+ keys = (event.type == Common::EVENT_LBUTTONDOWN ? 199 : (200 | 0x800));
+ breakLoop = true;
+ } break;
+
+ case Common::EVENT_WHEELUP:
+ mouseWheel = -1;
+ break;
+
+ case Common::EVENT_WHEELDOWN:
+ mouseWheel = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ //if (_debugger->isAttached())
+ // _debugger->onFrame();
+
+ if (breakLoop)
+ break;
+
+ _eventList.erase(_eventList.begin());
+ }
+
+ return /*gui_v2()->processButtonList(buttonList, keys | 0x8000, mouseWheel)*/keys;
+}
+
+void LoLEngine::updateInput() {
+ Common::Event event;
+
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ _quitFlag = true;
+ break;
+
+ case Common::EVENT_KEYDOWN:
+ if (event.kbd.keycode == '.' || event.kbd.keycode == Common::KEYCODE_ESCAPE)
+ _eventList.push_back(Event(event, true));
+ else if (event.kbd.keycode == 'q' && event.kbd.flags == Common::KBD_CTRL)
+ _quitFlag = true;
+ else
+ _eventList.push_back(event);
+ break;
+
+ case Common::EVENT_LBUTTONDOWN:
+ _eventList.push_back(Event(event, true));
+ break;
+
+ case Common::EVENT_MOUSEMOVE:
+ _screen->updateScreen();
+ // fall through
+
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_WHEELUP:
+ case Common::EVENT_WHEELDOWN:
+ _eventList.push_back(event);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void LoLEngine::removeInputTop() {
+ if (!_eventList.empty())
+ _eventList.erase(_eventList.begin());
+}
+
+bool LoLEngine::skipFlag() const {
+ for (Common::List<Event>::const_iterator i = _eventList.begin(); i != _eventList.end(); ++i) {
+ if (i->causedSkip)
+ return true;
+ }
+ return false;
+}
+
+void LoLEngine::resetSkipFlag(bool removeEvent) {
+ for (Common::List<Event>::iterator i = _eventList.begin(); i != _eventList.end(); ++i) {
+ if (i->causedSkip) {
+ if (removeEvent)
+ _eventList.erase(i);
+ else
+ i->causedSkip = false;
+ return;
+ }
+ }
+}
+
+#pragma mark - Intro
+
+void LoLEngine::setupPrologueData(bool load) {
+ static const char * const fileList[] = {
+ "xxx/general.pak",
+ "xxx/introvoc.pak",
+ "xxx/startup.pak",
+ "xxx/intro1.pak",
+ "xxx/intro2.pak",
+ "xxx/intro3.pak",
+ "xxx/intro4.pak",
+ "xxx/intro5.pak",
+ "xxx/intro6.pak",
+ "xxx/intro7.pak",
+ "xxx/intro8.pak",
+ "xxx/intro9.pak"
+ };
+
+ char filename[32];
+ for (uint i = 0; i < ARRAYSIZE(fileList); ++i) {
+ strcpy(filename, fileList[i]);
+ memcpy(filename, _languageExt[_lang], 3);
+
+ if (load) {
+ if (!_res->loadPakFile(filename))
+ error("Couldn't load file: '%s'", filename);
+ } else {
+ _res->unloadPakFile(filename);
+ }
+ }
+
+ if (load) {
+ _chargenWSA = new WSAMovie_v2(this, _screen);
+ assert(_chargenWSA);
+
+ _charSelection = -1;
+ _charSelectionInfoResult = -1;
+
+ _selectionAnimFrames[0] = _selectionAnimFrames[2] = 0;
+ _selectionAnimFrames[1] = _selectionAnimFrames[3] = 1;
+
+ memset(_selectionAnimTimers, 0, sizeof(_selectionAnimTimers));
+ memset(_screen->getPalette(1), 0, 768);
+ } else {
+ delete _chargenWSA; _chargenWSA = 0;
+ }
+}
+
+void LoLEngine::showIntro() {
+ debugC(9, kDebugLevelMain, "LoLEngine::showIntro()");
+
+ 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(Screen::FID_8_FNT);
+
+ _tim->resetFinishedFlag();
+ _tim->setLangData("LOLINTRO.DIP");
+
+ _screen->hideMouse();
+
+ uint32 palNextFadeStep = 0;
+ while (!_tim->finished() && !_quitFlag && !skipFlag()) {
+ updateInput();
+ _tim->exec(intro, false);
+ _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();
+
+ // HACK: Remove all input events
+ _eventList.clear();
+
+ _tim->unload(intro);
+ _tim->clearLangData();
+
+ _screen->fadePalette(_screen->getPalette(1), 30, 0);
+}
+
+int LoLEngine::chooseCharacter() {
+ debugC(9, kDebugLevelMain, "LoLEngine::chooseCharacter()");
+
+ _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->setX(113);
+ _chargenWSA->setY(0);
+ _chargenWSA->setDrawPage(2);
+ _chargenWSA->displayFrame(0, 0, 0, 0);
+
+ _screen->setFont(Screen::FID_9_FNT);
+ _screen->_curPage = 2;
+
+ for (int i = 0; i < 4; ++i)
+ _screen->fprintStringIntro(_charPreviews[i].name, _charPreviews[i].x + 16, _charPreviews[i].y + 36, 0xC0, 0x00, 0x9C, 0x120);
+
+ for (int i = 0; i < 4; ++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(_tim->getCTableEntry(51), 36, 173, 0x98, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(53), 36, 181, 0x98, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(55), 36, 189, 0x98, 0x00, 0x9C, 0x20);
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->_curPage = 0;
+
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+
+ bool kingIntro = true;
+ while (!_quitFlag) {
+ if (kingIntro)
+ kingSelectionIntro();
+
+ if (_charSelection < 0)
+ processCharacterSelection();
+
+ if (_quitFlag)
+ 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;
+ }
+ }
+
+ if (_quitFlag)
+ return -1;
+
+ uint32 waitTime = _system->getMillis() + 420 * _tickLength;
+ while (waitTime > _system->getMillis() && !skipFlag() && !_quitFlag) {
+ updateInput();
+ _system->delayMillis(10);
+ }
+
+ // HACK: Remove all input events
+ _eventList.clear();
+
+ _tim->clearLangData();
+
+ return _charSelection;
+}
+
+void LoLEngine::kingSelectionIntro() {
+ debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionIntro()");
+
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ int y = 38;
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(57), 8, y, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(58), 8, y + 10, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(59), 8, y + 20, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(60), 8, y + 30, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(61), 8, y + 40, 0x32, 0x00, 0x9C, 0x20);
+
+ _sound->voicePlay("KING01");
+
+ _chargenWSA->setX(113);
+ _chargenWSA->setY(0);
+ _chargenWSA->setDrawPage(0);
+
+ int index = 4;
+ while (_sound->voiceIsPlaying("KING01") && _charSelection == -1 && !_quitFlag && !skipFlag()) {
+ index = MAX(index, 4);
+
+ _chargenWSA->displayFrame(_chargenFrameTable[index], 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 && !_quitFlag && !skipFlag()) {
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ index = (index + 1) % 22;
+ }
+
+ resetSkipFlag();
+
+ _chargenWSA->displayFrame(0x10, 0, 0, 0);
+ _screen->updateScreen();
+ _sound->voiceStop("KING01");
+}
+
+void LoLEngine::kingSelectionReminder() {
+ debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionReminder()");
+
+ _screen->copyRegion(0, 0, 0, 0, 112, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ int y = 48;
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(62), 8, y, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(63), 8, y + 10, 0x32, 0x00, 0x9C, 0x20);
+
+ _sound->voicePlay("KING02");
+
+ _chargenWSA->setX(113);
+ _chargenWSA->setY(0);
+ _chargenWSA->setDrawPage(0);
+
+ int index = 0;
+ while (_sound->voiceIsPlaying("KING02") && _charSelection == -1 && !_quitFlag && index < 15) {
+ _chargenWSA->displayFrame(_chargenFrameTable[index+9], 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() && !_quitFlag) {
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ index = (index + 1) % 22;
+ }
+
+ _sound->voiceStop("KING02");
+}
+
+void LoLEngine::kingSelectionOutro() {
+ debugC(9, kDebugLevelMain, "LoLEngine::kingSelectionOutro()");
+
+ _sound->voicePlay("KING03");
+
+ _chargenWSA->setX(113);
+ _chargenWSA->setY(0);
+ _chargenWSA->setDrawPage(0);
+
+ int index = 0;
+ while (_sound->voiceIsPlaying("KING03") && !_quitFlag && !skipFlag()) {
+ index = MAX(index, 4);
+
+ _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 0, 0);
+ _screen->updateScreen();
+
+ uint32 waitEnd = _system->getMillis() + 8 * _tickLength;
+ while (waitEnd > _system->getMillis() && !_quitFlag && !skipFlag()) {
+ updateInput();
+ _system->delayMillis(10);
+ }
+
+ index = (index + 1) % 22;
+ }
+
+ resetSkipFlag();
+
+ _chargenWSA->displayFrame(0x10, 0, 0, 0);
+ _screen->updateScreen();
+ _sound->voiceStop("KING03");
+}
+
+void LoLEngine::processCharacterSelection() {
+ debugC(9, kDebugLevelMain, "LoLEngine::processCharacterSelection()");
+
+ _charSelection = -1;
+ while (!_quitFlag && _charSelection == -1) {
+ uint32 nextKingMessage = _system->getMillis() + 900 * _tickLength;
+
+ while (nextKingMessage > _system->getMillis() && _charSelection == -1 && !_quitFlag) {
+ updateSelectionAnims();
+ _charSelection = getCharSelection();
+ _system->delayMillis(10);
+ }
+
+ if (_charSelection == -1)
+ kingSelectionReminder();
+ }
+}
+
+void LoLEngine::updateSelectionAnims() {
+ debugC(9, kDebugLevelMain, "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) {
+ debugC(9, kDebugLevelMain, "LoLEngine::selectionCharInfo(%d)", 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];
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+0), 50, 127, 0x53, 0x00, 0xCF, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+1), 50, 137, 0x53, 0x00, 0xCF, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+2), 50, 147, 0x53, 0x00, 0xCF, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+3), 50, 157, 0x53, 0x00, 0xCF, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(idx+4), 50, 167, 0x53, 0x00, 0xCF, 0x20);
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(69), 100, 168, 0x32, 0x00, 0xCF, 0x20);
+
+ selectionCharInfoIntro(vocFilename);
+ if (_charSelectionInfoResult == -1) {
+ while (_charSelectionInfoResult == -1) {
+ _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);
+
+ _screen->fprintStringIntro(_tim->getCTableEntry(64), 3, 28, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(65), 3, 38, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(66), 3, 48, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(67), 3, 58, 0x32, 0x00, 0x9C, 0x20);
+ _screen->fprintStringIntro(_tim->getCTableEntry(68), 3, 68, 0x32, 0x00, 0x9C, 0x20);
+
+ resetSkipFlag();
+ kingSelectionOutro();
+ return character;
+}
+
+void LoLEngine::selectionCharInfoIntro(char *file) {
+ debugC(9, kDebugLevelMain, "LoLEngine::selectionCharInfoIntro(%p)", (const void *)file);
+ int index = 0;
+ file[4] = '0';
+
+ while (_charSelectionInfoResult == -1 && !_quitFlag) {
+ if (!_sound->voicePlay(file))
+ break;
+
+ int i = 0;
+ while (_sound->voiceIsPlaying(file) && _charSelectionInfoResult == -1 && !_quitFlag) {
+ _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) {
+ _charSelectionInfoResult = selectionCharAccept();
+ _system->delayMillis(10);
+ }
+
+ i = (i + 1) % 32;
+ }
+
+ _sound->voiceStop(file);
+ 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() & 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() & 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;
+}
+
+#pragma mark - Opcodes
+
+typedef Common::Functor2Mem<const TIM *, const uint16 *, int, LoLEngine> TIMOpcodeLoL;
+#define SetTimOpcodeTable(x) timTable = &x;
+#define OpcodeTim(x) timTable->push_back(new TIMOpcodeLoL(this, &LoLEngine::x))
+#define OpcodeTimUnImpl() timTable->push_back(new TIMOpcodeLoL(this, 0))
+
+void LoLEngine::setupOpcodeTable() {
+ Common::Array<const TIMOpcode*> *timTable = 0;
+
+ SetTimOpcodeTable(_timIntroOpcodes);
+
+ // 0x00
+ OpcodeTim(tlol_setupPaletteFade);
+ OpcodeTimUnImpl();
+ OpcodeTim(tlol_loadPalette);
+ OpcodeTim(tlol_setupPaletteFadeEx);
+
+ // 0x04
+ OpcodeTim(tlol_processWsaFrame);
+ OpcodeTim(tlol_displayText);
+ OpcodeTimUnImpl();
+ OpcodeTimUnImpl();
+}
+
+#pragma mark -
+
+int LoLEngine::tlol_setupPaletteFade(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::t2_playSoundEffect(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]);
+ _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff);
+ _tim->_palDelayAcc = 0;
+ return 1;
+}
+
+int LoLEngine::tlol_loadPalette(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_loadPalette(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]);
+ const char *palFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0]<<1)));
+ _res->loadFileToBuf(palFile, _screen->getPalette(0), 768);
+ return 1;
+}
+
+int LoLEngine::tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_setupPaletteFadeEx(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]);
+ memcpy(_screen->getPalette(0), _screen->getPalette(1), 768);
+
+ _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff);
+ _tim->_palDelayAcc = 0;
+ return 1;
+}
+
+int LoLEngine::tlol_processWsaFrame(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_processWsaFrame(%p, %p) (%d, %d, %d, %d, %d)",
+ (const void*)tim, (const void*)param, param[0], param[1], param[2], param[3], param[4]);
+ TIMInterpreter::Animation *anim = (TIMInterpreter::Animation *)tim->wsa[param[0]].anim;
+ const int frame = param[1];
+ const int x2 = param[2];
+ const int y2 = param[3];
+ const int factor = MAX<int>(0, (int16)param[4]);
+
+ const int x1 = anim->x;
+ const int y1 = anim->y;
+
+ int w1 = anim->wsa->width();
+ int h1 = anim->wsa->height();
+ int w2 = (w1 * factor) / 100;
+ int h2 = (h1 * factor) / 100;
+
+ anim->wsa->setDrawPage(2);
+ anim->wsa->setX(x1);
+ anim->wsa->setY(y1);
+ anim->wsa->displayFrame(frame, anim->wsaCopyParams & 0xF0FF, 0, 0);
+ _screen->wsaFrameAnimationStep(x1, y1, x2, y2, w1, h1, w2, h2, 2, 8, 0);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+
+ return 1;
+}
+
+int LoLEngine::tlol_displayText(const TIM *tim, const uint16 *param) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_displayText(%p, %p) (%d, %d)", (const void*)tim, (const void*)param, param[0], (int16)param[1]);
+ _tim->displayText(param[0], param[1]);
+ return 1;
+}
+
+} // end of namespace Kyra
+
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
new file mode 100644
index 0000000000..ee54f8abbb
--- /dev/null
+++ b/engines/kyra/lol.h
@@ -0,0 +1,155 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef KYRA_LOL_H
+#define KYRA_LOL_H
+
+#include "kyra/kyra_v1.h"
+#include "kyra/script_tim.h"
+
+#include "common/list.h"
+
+namespace Kyra {
+
+class Screen_LoL;
+class WSAMovie_v2;
+struct Button;
+
+class LoLEngine : public KyraEngine_v1 {
+public:
+ LoLEngine(OSystem *system, const GameFlags &flags);
+ ~LoLEngine();
+
+ Screen *screen();
+private:
+ Screen_LoL *_screen;
+ TIMInterpreter *_tim;
+
+ int init();
+ int go();
+
+ // input
+ void updateInput();
+ int checkInput(Button *buttonList = 0, bool mainLoop = false);
+ void removeInputTop();
+
+ int _mouseX, _mouseY;
+
+ struct Event {
+ Common::Event event;
+ bool causedSkip;
+
+ Event() : event(), causedSkip(false) {}
+ Event(Common::Event e) : event(e), causedSkip(false) {}
+ Event(Common::Event e, bool skip) : event(e), causedSkip(skip) {}
+
+ operator Common::Event() const { return event; }
+ };
+ Common::List<Event> _eventList;
+
+ virtual bool skipFlag() const;
+ virtual void resetSkipFlag(bool removeEvent = true);
+
+ // intro
+ void setupPrologueData(bool load);
+
+ void showIntro();
+
+ struct CharacterPrev {
+ const char *name;
+ int x, y;
+ int attrib[3];
+ };
+
+ static const CharacterPrev _charPreviews[];
+
+ WSAMovie_v2 *_chargenWSA;
+ static const uint8 _chargenFrameTable[];
+ int chooseCharacter();
+
+ void kingSelectionIntro();
+ void kingSelectionReminder();
+ void kingSelectionOutro();
+ void processCharacterSelection();
+ void updateSelectionAnims();
+ int selectionCharInfo(int character);
+ void selectionCharInfoIntro(char *file);
+
+ int getCharSelection();
+ int selectionCharAccept();
+
+ int _charSelection;
+ int _charSelectionInfoResult;
+
+ uint32 _selectionAnimTimers[4];
+ uint8 _selectionAnimFrames[4];
+ static const uint8 _selectionAnimIndexTable[];
+
+ static const uint16 _selectionPosTable[];
+
+ static const uint8 _selectionChar1IdxTable[];
+ static const uint8 _selectionChar2IdxTable[];
+ static const uint8 _selectionChar3IdxTable[];
+ static const uint8 _selectionChar4IdxTable[];
+
+ static const uint8 _reminderChar1IdxTable[];
+ static const uint8 _reminderChar2IdxTable[];
+ static const uint8 _reminderChar3IdxTable[];
+ static const uint8 _reminderChar4IdxTable[];
+
+ static const uint8 _charInfoFrameTable[];
+
+ // timer
+ void setupTimers() {}
+
+ // sound
+ void snd_playVoiceFile(int) { /* XXX */ }
+
+ // opcode
+ void setupOpcodeTable();
+
+ Common::Array<const TIMOpcode*> _timIntroOpcodes;
+ int tlol_setupPaletteFade(const TIM *tim, const uint16 *param);
+ int tlol_loadPalette(const TIM *tim, const uint16 *param);
+ int tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param);
+ int tlol_processWsaFrame(const TIM *tim, const uint16 *param);
+ int tlol_displayText(const TIM *tim, const uint16 *param);
+
+ // translation
+ int _lang;
+
+ static const char * const _languageExt[];
+
+ // unneeded
+ void setWalkspeed(uint8) {}
+ void setHandItem(uint16) {}
+ void removeHandItem() {}
+ bool lineIsPassable(int, int) { return false; }
+};
+
+} // end of namespace Kyra
+
+#endif
+
diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk
index ebb63b4b4e..e059a8ce4b 100644
--- a/engines/kyra/module.mk
+++ b/engines/kyra/module.mk
@@ -21,6 +21,7 @@ MODULE_OBJS := \
kyra_v2.o \
kyra_hof.o \
kyra_mr.o \
+ lol.o \
resource.o \
saveload.o \
saveload_lok.o \
@@ -33,6 +34,7 @@ MODULE_OBJS := \
scene_mr.o \
screen.o \
screen_lok.o \
+ screen_lol.o \
screen_v2.o \
screen_hof.o \
screen_mr.o \
diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp
index afd7eacfda..92818aafe1 100644
--- a/engines/kyra/resource.cpp
+++ b/engines/kyra/resource.cpp
@@ -55,10 +55,12 @@ bool Resource::reset() {
if (!dir.exists() || !dir.isDirectory())
error("invalid game path '%s'", dir.getPath().c_str());
- if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat()) {
- Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website";
- _vm->GUIErrorMessage(errorMessage);
- error(errorMessage.c_str());
+ if (_vm->game() != GI_LOL) {
+ if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat()) {
+ Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website";
+ _vm->GUIErrorMessage(errorMessage);
+ error(errorMessage.c_str());
+ }
}
if (_vm->game() == GI_KYRA1) {
@@ -99,6 +101,8 @@ bool Resource::reset() {
loadFileList("FILEDATA.FDT");
return true;
+ } else if (_vm->game() == GI_LOL) {
+ return true;
}
FSList fslist;
@@ -1120,7 +1124,7 @@ bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32
void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt) {
const uint8 *tbl1 = _tables[srcIndex];
- const uint8 *tbl2 = _tables[dstIndex];
+ uint8 *tbl2 = _tables[dstIndex];
const uint8 *tbl3 = dstIndex2 == 0xff ? 0 : _tables[dstIndex2];
if (!cnt)
@@ -1185,7 +1189,7 @@ void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex
}
}
- memset((void*) tbl2, 0, 512);
+ memset(tbl2, 0, 512);
cnt--;
s = tbl1 + cnt;
diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp
new file mode 100644
index 0000000000..c6b47a9ca9
--- /dev/null
+++ b/engines/kyra/screen_lol.cpp
@@ -0,0 +1,69 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "kyra/screen_lol.h"
+#include "kyra/lol.h"
+
+namespace Kyra {
+
+Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system), _vm(vm) {
+}
+
+void Screen_LoL::setScreenDim(int dim) {
+ debugC(9, kDebugLevelScreen, "Screen_LoL::setScreenDim(%d)", dim);
+ assert(dim < _screenDimTableCount);
+ _curDim = &_screenDimTable[dim];
+}
+
+const ScreenDim *Screen_LoL::getScreenDim(int dim) {
+ debugC(9, kDebugLevelScreen, "Screen_LoL::getScreenDim(%d)", dim);
+ assert(dim < _screenDimTableCount);
+ return &_screenDimTable[dim];
+}
+
+void Screen_LoL::fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...) {
+ debugC(9, kDebugLevelScreen, "Screen_LoL::fprintStringIntro('%s', %d, %d, %d, %d, %d, %d, ...)", format, x, y, c1, c2, c3, flags);
+ char buffer[400];
+
+ va_list args;
+ va_start(args, flags);
+ vsprintf(buffer, format, args);
+ va_end(args);
+
+ if ((flags & 0x0F00) == 0x100)
+ x -= getTextWidth(buffer) >> 1;
+ if ((flags & 0x0F00) == 0x200)
+ x -= getTextWidth(buffer);
+
+ if ((flags & 0x00F0) == 0x20) {
+ printText(buffer, x-1, y, c3, c2);
+ printText(buffer, x, y+1, c3, c2);
+ }
+
+ printText(buffer, x, y, c1, c2);
+}
+
+} // end of namespace Kyra
+
diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h
new file mode 100644
index 0000000000..38df3ca897
--- /dev/null
+++ b/engines/kyra/screen_lol.h
@@ -0,0 +1,53 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef KYRA_SCREEN_LOL_H
+#define KYRA_SCREEN_LOL_H
+
+#include "kyra/screen_v2.h"
+
+namespace Kyra {
+
+class LoLEngine;
+
+class Screen_LoL : public Screen_v2 {
+public:
+ Screen_LoL(LoLEngine *vm, OSystem *system);
+
+ void setScreenDim(int dim);
+ const ScreenDim *getScreenDim(int dim);
+
+ void fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...);
+private:
+ LoLEngine *_vm;
+
+ static const ScreenDim _screenDimTable[];
+ static const int _screenDimTableCount;
+};
+
+} // end of namespace Kyra
+
+#endif
+
diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp
index e5d851aeab..c6ea6a93e8 100644
--- a/engines/kyra/screen_v2.cpp
+++ b/engines/kyra/screen_v2.cpp
@@ -485,5 +485,27 @@ bool Screen_v2::calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, i
return (w1 == -1) ? false : true;
}
+void Screen_v2::checkedPageUpdate(int srcPage, int dstPage) {
+ debugC(9, kDebugLevelScreen, "Screen_v2::checkedPageUpdate(%d, %d)", srcPage, dstPage);
+
+ const uint32 *src = (const uint32 *)getPagePtr(srcPage);
+ uint32 *dst = (uint32 *)getPagePtr(dstPage);
+ uint32 *page0 = (uint32 *)getPagePtr(0);
+
+ bool updated = false;
+
+ for (int y = 0; y < 200; ++y) {
+ for (int x = 0; x < 80; ++x, ++src, ++dst, ++page0) {
+ if (*src != *dst) {
+ updated = true;
+ *dst = *page0 = *src;
+ }
+ }
+ }
+
+ if (updated)
+ addDirtyRect(0, 0, 320, 200);
+}
+
} // end of namespace Kyra
diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h
index 3283526ee3..7bbdc4b6c3 100644
--- a/engines/kyra/screen_v2.h
+++ b/engines/kyra/screen_v2.h
@@ -40,6 +40,8 @@ public:
void copyWsaRect(int x, int y, int w, int h, int dimState, int plotFunc, const uint8 *src,
int unk1, const uint8 *unkPtr1, const uint8 *unkPtr2);
+ void checkedPageUpdate(int srcPage, int dstPage);
+
// palette handling
uint8 *generateOverlay(const uint8 *palette, uint8 *buffer, int color, uint16 factor);
void applyOverlay(int x, int y, int w, int h, int pageNum, const uint8 *overlay);
diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp
index 4b82232049..b8fc6713a6 100644
--- a/engines/kyra/script_tim.cpp
+++ b/engines/kyra/script_tim.cpp
@@ -26,12 +26,14 @@
#include "kyra/script_tim.h"
#include "kyra/script.h"
#include "kyra/resource.h"
+#include "kyra/sound.h"
+#include "kyra/wsamovie.h"
#include "common/endian.h"
namespace Kyra {
-TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _system(system), _currentTim(0) {
+TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system) : _vm(vm), _screen(screen), _system(system), _currentTim(0) {
#define COMMAND(x) { &TIMInterpreter::x, #x }
#define COMMAND_UNIMPL() { 0, 0 }
#define cmd_return(n) cmd_return_##n
@@ -39,32 +41,32 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s
// 0x00
COMMAND(cmd_initFunc0),
COMMAND(cmd_stopCurFunc),
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_initWSA),
+ COMMAND(cmd_uninitWSA),
// 0x04
COMMAND(cmd_initFunc),
COMMAND(cmd_stopFunc),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_wsaDisplayFrame),
COMMAND_UNIMPL(),
// 0x08
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_loadVocFile),
+ COMMAND(cmd_unloadVocFile),
+ COMMAND(cmd_playVocFile),
COMMAND_UNIMPL(),
// 0x0C
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_loadSoundFile),
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_playMusicTrack),
COMMAND_UNIMPL(),
// 0x10
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_return(1)),
+ COMMAND(cmd_return(1)),
COMMAND_UNIMPL(),
COMMAND_UNIMPL(),
// 0x14
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
- COMMAND_UNIMPL(),
+ COMMAND(cmd_setLoopIp),
+ COMMAND(cmd_continueLoop),
+ COMMAND(cmd_resetLoopIp),
COMMAND(cmd_resetAllRuntimes),
// 0x18
COMMAND(cmd_return(1)),
@@ -80,6 +82,19 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, OSystem *system) : _vm(vm), _s
_commands = commandProcs;
_commandsSize = ARRAYSIZE(commandProcs);
+
+ memset(&_animations, 0, sizeof(_animations));
+ _langData = 0;
+ _textDisplayed = false;
+ _textAreaBuffer = new uint8[320*40];
+ assert(_textAreaBuffer);
+
+ _palDelayInc = _palDiff = _palDelayAcc = 0;
+}
+
+TIMInterpreter::~TIMInterpreter() {
+ delete[] _langData;
+ delete[] _textAreaBuffer;
}
TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes) {
@@ -139,6 +154,11 @@ void TIMInterpreter::unload(TIM *&tim) const {
tim = 0;
}
+void TIMInterpreter::setLangData(const char *filename) {
+ delete[] _langData;
+ _langData = _vm->resource()->fileData(filename, 0);
+}
+
void TIMInterpreter::exec(TIM *tim, bool loop) {
if (!tim)
return;
@@ -175,6 +195,10 @@ void TIMInterpreter::exec(TIM *tim, bool loop) {
_currentTim->procFunc = _currentFunc;
break;
+ case 22:
+ cur.loopIp = 0;
+ break;
+
default:
break;
}
@@ -201,6 +225,205 @@ void TIMInterpreter::refreshTimersAfterPause(uint32 elapsedTime) {
}
}
+void TIMInterpreter::displayText(uint16 textId, int16 flags) {
+ char *text = getTableEntry(textId);
+
+ if (_textDisplayed) {
+ _screen->copyBlockToPage(0, 0, 160, 320, 40, _textAreaBuffer);
+ _textDisplayed = false;
+ }
+
+ if (!text)
+ return;
+ if (!text[0])
+ return;
+
+ char filename[16];
+ memset(filename, 0, sizeof(filename));
+
+ if (text[0] == '$') {
+ const char *end = strchr(text+1, '$');
+ if (end)
+ memcpy(filename, text+1, end-1-text);
+ }
+
+ if (filename[0])
+ _vm->sound()->voicePlay(filename);
+
+ if (text[0] == '$')
+ text = strchr(text + 1, '$') + 1;
+
+ setupTextPalette((flags < 0) ? 1 : flags, 0);
+
+ if (flags < 0) {
+ static const uint8 colorMap[] = { 0x00, 0xF0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ _screen->setFont(Screen::FID_8_FNT);
+ _screen->setTextColorMap(colorMap);
+ _screen->_charWidth = -2;
+ }
+
+ _screen->_charOffset = -4;
+ _screen->copyRegionToBuffer(0, 0, 160, 320, 40, _textAreaBuffer);
+ _textDisplayed = true;
+
+ char backupChar = 0;
+ char *str = text;
+ int heightAdd = 0;
+
+ while (str[0]) {
+ char *nextLine = strchr(str, '\r');
+
+ backupChar = 0;
+ if (nextLine) {
+ backupChar = nextLine[0];
+ nextLine[0] = '\0';
+ }
+
+ int width = _screen->getTextWidth(str);
+
+ if (flags >= 0)
+ _screen->printText(str, (320 - width) >> 1, 160 + heightAdd, 0xF0, 0x00);
+ else
+ _screen->printText(str, (320 - width) >> 1, 188, 0xF0, 0x00);
+
+ heightAdd += _screen->getFontHeight();
+ str += strlen(str);
+
+ if (backupChar) {
+ nextLine[0] = backupChar;
+ ++str;
+ }
+ }
+
+ _screen->_charOffset = 0;
+
+ if (flags < 0) {
+ static const uint8 colorMap[] = { 0x00, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x00, 0x00, 0x00, 0x00 };
+
+ _screen->setFont(Screen::FID_INTRO_FNT);
+ _screen->setTextColorMap(colorMap);
+ _screen->_charWidth = 0;
+ }
+}
+
+void TIMInterpreter::setupTextPalette(uint index, int fadePalette) {
+ static const uint16 palTable[] = {
+ 0x00, 0x00, 0x00,
+ 0x64, 0x64, 0x64,
+ 0x61, 0x51, 0x30,
+ 0x29, 0x48, 0x64,
+ 0x00, 0x4B, 0x3B,
+ 0x64, 0x1E, 0x1E,
+ };
+
+ for (int i = 0; i < 15; ++i) {
+ uint8 *palette = _screen->getPalette(0) + (240 + i) * 3;
+
+ uint8 c1 = (((15 - i) << 2) * palTable[index*3+0]) / 100;
+ uint8 c2 = (((15 - i) << 2) * palTable[index*3+1]) / 100;
+ uint8 c3 = (((15 - i) << 2) * palTable[index*3+2]) / 100;
+
+ palette[0] = c1;
+ palette[1] = c2;
+ palette[2] = c3;
+ }
+
+ if (!fadePalette && !_palDiff) {
+ _screen->setScreenPalette(_screen->getPalette(0));
+ } else {
+ _screen->getFadeParams(_screen->getPalette(0), fadePalette, _palDelayInc, _palDiff);
+ _palDelayAcc = 0;
+ }
+}
+
+TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags) {
+ Animation *anim = &_animations[index];
+ anim->x = x;
+ anim->y = y;
+ anim->wsaCopyParams = wsaFlags;
+
+ uint16 wsaOpenFlags = ((wsaFlags & 0x10) != 0) ? 2 : 0;
+
+ char file[32];
+ snprintf(file, 32, "%s.WSA", filename);
+
+ if (_vm->resource()->exists(file)) {
+ anim->wsa = new WSAMovie_v2(_vm, _screen);
+ assert(anim->wsa);
+
+ anim->wsa->open(file, wsaOpenFlags, (index == 1) ? _screen->getPalette(0) : 0);
+ }
+
+ if (anim->wsa && anim->wsa->opened()) {
+ if (x == -1)
+ anim->x = x = 0;
+ if (y == -1)
+ anim->y = y = 0;
+
+ if (wsaFlags & 2) {
+ _screen->fadePalette(_screen->getPalette(1), 15, 0);
+ _screen->clearPage(8);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ if (wsaFlags & 4) {
+ snprintf(file, 32, "%s.CPS", filename);
+
+ if (_vm->resource()->exists(file)) {
+ _screen->loadBitmap(file, 3, 3, _screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 8, Screen::CR_NO_P_CHECK);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ anim->wsa->setX(x);
+ anim->wsa->setY(y);
+ anim->wsa->setDrawPage(0);
+ anim->wsa->displayFrame(0, 0, 0, 0);
+ }
+
+ if (wsaFlags & 2)
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+ } else {
+ if (wsaFlags & 2) {
+ _screen->fadePalette(_screen->getPalette(1), 15, 0);
+ _screen->clearPage(8);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ snprintf(file, 32, "%s.CPS", filename);
+
+ if (_vm->resource()->exists(file)) {
+ _screen->loadBitmap(file, 3, 3, _screen->getPalette(0));
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 8, Screen::CR_NO_P_CHECK);
+ _screen->checkedPageUpdate(8, 4);
+ _screen->updateScreen();
+ }
+
+ if (wsaFlags & 2)
+ _screen->fadePalette(_screen->getPalette(0), 30, 0);
+ }
+
+ return anim;
+}
+
+char *TIMInterpreter::getTableEntry(uint idx) {
+ if (!_langData)
+ return 0;
+ else
+ return (char *)(_langData + READ_LE_UINT16(_langData + (idx<<1)));
+}
+
+const char *TIMInterpreter::getCTableEntry(uint idx) const {
+ if (!_langData)
+ return 0;
+ else
+ return (const char *)(_langData + READ_LE_UINT16(_langData + (idx<<1)));
+}
+
int TIMInterpreter::execCommand(int cmd, const uint16 *param) {
if (cmd < 0 || cmd >= _commandsSize) {
warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename);
@@ -212,11 +435,14 @@ int TIMInterpreter::execCommand(int cmd, const uint16 *param) {
return 0;
}
- debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void*)param);
+ debugC(5, kDebugLevelScript, "TIMInterpreter::%s(%p)", _commands[cmd].desc, (const void* )param);
return (this->*_commands[cmd].proc)(param);
}
int TIMInterpreter::cmd_initFunc0(const uint16 *param) {
+ for (int i = 0; i < TIM::kWSASlots; ++i)
+ memset(&_currentTim->wsa[i], 0, sizeof(TIM::WSASlot));
+
_currentTim->func[0].ip = _currentTim->func[0].avtl;
_currentTim->func[0].lastTime = _system->getMillis();
return 1;
@@ -230,6 +456,46 @@ int TIMInterpreter::cmd_stopCurFunc(const uint16 *param) {
return -2;
}
+int TIMInterpreter::cmd_initWSA(const uint16 *param) {
+ const int index = param[0];
+
+ TIM::WSASlot &slot = _currentTim->wsa[index];
+
+ slot.x = int16(param[2]);
+ slot.y = int16(param[3]);
+ slot.offscreen = param[4];
+ slot.wsaFlags = param[5];
+ const char *filename = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (param[1]<<1)));
+
+ slot.anim = initAnimStruct(index, filename, slot.x, slot.y, 10, slot.offscreen, slot.wsaFlags);
+ return 1;
+}
+
+int TIMInterpreter::cmd_uninitWSA(const uint16 *param) {
+ const int index = param[0];
+
+ TIM::WSASlot &slot = _currentTim->wsa[index];
+
+ if (!slot.anim)
+ return 0;
+
+ Animation &anim = _animations[index];
+
+ if (slot.offscreen) {
+ delete anim.wsa;
+ anim.wsa = 0;
+ slot.anim = 0;
+ } else {
+ //XXX
+
+ delete anim.wsa;
+ memset(&anim, 0, sizeof(Animation));
+ memset(&slot, 0, sizeof(TIM::WSASlot));
+ }
+
+ return 1;
+}
+
int TIMInterpreter::cmd_initFunc(const uint16 *param) {
uint16 func = *param;
assert(func < TIM::kCountFuncs);
@@ -247,6 +513,97 @@ int TIMInterpreter::cmd_stopFunc(const uint16 *param) {
return 1;
}
+int TIMInterpreter::cmd_wsaDisplayFrame(const uint16 *param) {
+ Animation &anim = _animations[param[0]];
+ const int frame = param[1];
+
+ anim.wsa->setX(anim.x);
+ anim.wsa->setY(anim.y);
+ anim.wsa->setDrawPage((anim.wsaCopyParams & 0x4000) != 0 ? 2 : 8);
+ anim.wsa->displayFrame(frame, anim.wsaCopyParams & 0xF0FF, 0, 0);
+ return 1;
+}
+
+int TIMInterpreter::cmd_displayText(const uint16 *param) {
+ displayText(param[0], param[1]);
+ return 1;
+}
+
+int TIMInterpreter::cmd_loadVocFile(const uint16 *param) {
+ const int stringId = param[0];
+ const int index = param[1];
+
+ _vocFiles[index] = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (stringId << 1)));
+ for (int i = 0; i < 4; ++i)
+ _vocFiles[index].deleteLastChar();
+ return 1;
+}
+
+int TIMInterpreter::cmd_unloadVocFile(const uint16 *param) {
+ const int index = param[0];
+ _vocFiles[index].clear();
+ return 1;
+}
+
+int TIMInterpreter::cmd_playVocFile(const uint16 *param) {
+ const int index = param[0];
+ const int volume = (param[1] * 255) / 100;
+
+ if (index < ARRAYSIZE(_vocFiles) && !_vocFiles[index].empty())
+ _vm->sound()->voicePlay(_vocFiles[index].c_str()/*, volume*/, true);
+ else
+ _vm->snd_playSoundEffect(index, volume);
+
+ return 1;
+}
+
+int TIMInterpreter::cmd_loadSoundFile(const uint16 *param) {
+ const char *file = (const char *)(_currentTim->text + READ_LE_UINT16(_currentTim->text + (param[0]<<1)));
+
+ static char * fileList[] = { 0 };
+ fileList[0] = _audioFilename;
+ static AudioDataStruct audioList = { fileList, 1, 0, 0 };
+
+ strncpy(_audioFilename, file, sizeof(_audioFilename));
+
+ _vm->sound()->setSoundList(&audioList);
+ _vm->sound()->loadSoundFile(0);
+ return 1;
+}
+
+int TIMInterpreter::cmd_playMusicTrack(const uint16 *param) {
+ _vm->sound()->playTrack(param[0]);
+ return 1;
+}
+
+int TIMInterpreter::cmd_setLoopIp(const uint16 *param) {
+ _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip;
+ return 1;
+}
+
+int TIMInterpreter::cmd_continueLoop(const uint16 *param) {
+ TIM::Function &func = _currentTim->func[_currentFunc];
+
+ if (!func.loopIp)
+ return -2;
+
+ func.ip = func.loopIp;
+
+ uint16 factor = param[0];
+ if (factor) {
+ const uint32 random = _vm->_rnd.getRandomNumberRng(0, 0x8000);
+ uint32 waitTime = (random * factor) / 0x8000;
+ func.nextTime += waitTime * _vm->tickLength();
+ }
+
+ return 1;
+}
+
+int TIMInterpreter::cmd_resetLoopIp(const uint16 *param) {
+ _currentTim->func[_currentFunc].loopIp = 0;
+ return 1;
+}
+
int TIMInterpreter::cmd_resetAllRuntimes(const uint16 *param) {
for (int i = 0; i < TIM::kCountFuncs; ++i) {
if (_currentTim->func[i].ip)
@@ -256,17 +613,25 @@ int TIMInterpreter::cmd_resetAllRuntimes(const uint16 *param) {
}
int TIMInterpreter::cmd_execOpcode(const uint16 *param) {
+ const uint16 opcode = *param++;
+
if (!_currentTim->opcodes) {
- warning("Trying to execute TIM opcode without opcode list");
+ warning("Trying to execute TIM opcode %d without opcode list (file '%s')", opcode, _currentTim->filename);
+ fflush(stderr); fflush(stdout);
return 0;
}
- uint16 opcode = *param++;
if (opcode > _currentTim->opcodes->size()) {
warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename);
return 0;
}
+ if (!(*_currentTim->opcodes)[opcode]->isValid()) {
+ warning("Calling unimplemented TIM opcode(0x%.02X/%d) from file '%s'", opcode, opcode, _currentTim->filename);
+ fflush(stderr);
+ return 0;
+ }
+
return (*(*_currentTim->opcodes)[opcode])(_currentTim, param);
}
diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h
index 39a1d90a44..68ef23fd6c 100644
--- a/engines/kyra/script_tim.h
+++ b/engines/kyra/script_tim.h
@@ -30,9 +30,12 @@
#include "common/array.h"
#include "common/func.h"
+#include "common/str.h"
namespace Kyra {
+class WSAMovie_v2;
+class Screen_v2;
struct TIM;
typedef Common::Functor2<const TIM*, const uint16*, int> TIMOpcode;
@@ -52,9 +55,23 @@ struct TIM {
uint32 lastTime;
uint32 nextTime;
+ const uint16 *loopIp;
+
const uint16 *avtl;
} func[kCountFuncs];
+ enum {
+ kWSASlots = 10
+ };
+
+ struct WSASlot {
+ void *anim;
+
+ int16 x, y;
+ uint16 wsaFlags;
+ uint16 offscreen;
+ } wsa[kWSASlots];
+
uint16 *avtl;
uint8 *text;
@@ -63,10 +80,22 @@ struct TIM {
class TIMInterpreter {
public:
- TIMInterpreter(KyraEngine_v1 *vm, OSystem *system);
+ struct Animation {
+ WSAMovie_v2 *wsa;
+ int16 x, y;
+ uint16 wsaCopyParams;
+ };
+
+ TIMInterpreter(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system);
+ ~TIMInterpreter();
TIM *load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes);
void unload(TIM *&tim) const;
+
+ void setLangData(const char *filename);
+ void clearLangData() { delete[] _langData; _langData = 0; }
+
+ const char *getCTableEntry(uint idx) const;
void resetFinishedFlag() { _finished = false; }
bool finished() const { return _finished; }
@@ -74,10 +103,15 @@ public:
void exec(TIM *tim, bool loop);
void stopCurFunc() { if (_currentTim) cmd_stopCurFunc(0); }
- void play(const char *filename);
void refreshTimersAfterPause(uint32 elapsedTime);
+
+ void displayText(uint16 textId, int16 flags);
+ void setupTextPalette(uint index, int fadePalette);
+
+ int _palDelayInc, _palDiff, _palDelayAcc;
private:
KyraEngine_v1 *_vm;
+ Screen_v2 *_screen;
OSystem *_system;
TIM *_currentTim;
@@ -85,6 +119,19 @@ private:
bool _finished;
+ Common::String _vocFiles[120];
+
+ Animation _animations[TIM::kWSASlots];
+
+ Animation *initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags);
+
+ char _audioFilename[32];
+
+ uint8 *_langData;
+ char *getTableEntry(uint idx);
+ bool _textDisplayed;
+ uint8 *_textAreaBuffer;
+
int execCommand(int cmd, const uint16 *param);
typedef int (TIMInterpreter::*CommandProc)(const uint16 *);
@@ -98,8 +145,20 @@ private:
int cmd_initFunc0(const uint16 *param);
int cmd_stopCurFunc(const uint16 *param);
+ int cmd_initWSA(const uint16 *param);
+ int cmd_uninitWSA(const uint16 *param);
int cmd_initFunc(const uint16 *param);
int cmd_stopFunc(const uint16 *param);
+ int cmd_wsaDisplayFrame(const uint16 *param);
+ int cmd_displayText(const uint16 *param);
+ int cmd_loadVocFile(const uint16 *param);
+ int cmd_unloadVocFile(const uint16 *param);
+ int cmd_playVocFile(const uint16 *param);
+ int cmd_loadSoundFile(const uint16 *param);
+ int cmd_playMusicTrack(const uint16 *param);
+ int cmd_setLoopIp(const uint16 *param);
+ int cmd_continueLoop(const uint16 *param);
+ int cmd_resetLoopIp(const uint16 *param);
int cmd_resetAllRuntimes(const uint16 *param);
int cmd_execOpcode(const uint16 *param);
int cmd_initFuncNow(const uint16 *param);
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index 68a2f0be9c..0ceb288b8a 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -235,6 +235,10 @@ private:
// * One for instruments, starting at offset 500.
uint8 *getProgram(int progId) {
+ uint16 offset = READ_LE_UINT16(_soundData + 2 * progId);
+ //TODO: Check in LoL CD Adlib driver
+ if (offset == 0xFFFF)
+ return 0;
return _soundData + READ_LE_UINT16(_soundData + 2 * progId);
}
@@ -1282,6 +1286,9 @@ int AdlibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 va
return 0;
uint8 *ptr = getProgram(value);
+ //TODO: Check in LoL CD Adlib driver
+ if (!ptr)
+ return 0;
uint8 chan = *ptr++;
uint8 priority = *ptr++;
@@ -2213,7 +2220,7 @@ const int SoundAdlibPC::_kyra1NumSoundTriggers = ARRAYSIZE(SoundAdlibPC::_kyra1S
SoundAdlibPC::SoundAdlibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer)
: Sound(vm, mixer), _driver(0), _trackEntries(), _soundDataPtr(0) {
memset(_trackEntries, 0, sizeof(_trackEntries));
- _v2 = (_vm->gameFlags().gameID == GI_KYRA2);
+ _v2 = (_vm->gameFlags().gameID == GI_KYRA2) || (_vm->gameFlags().gameID == GI_LOL);
_driver = new AdlibDriver(mixer, _v2);
assert(_driver);
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index c05795dacd..9a4b40902e 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -23,16 +23,17 @@
*
*/
-
#include "common/endian.h"
#include "common/md5.h"
#include "kyra/kyra_v1.h"
#include "kyra/kyra_lok.h"
+#include "kyra/lol.h"
#include "kyra/kyra_v2.h"
#include "kyra/kyra_hof.h"
#include "kyra/kyra_mr.h"
#include "kyra/screen.h"
#include "kyra/screen_lok.h"
+#include "kyra/screen_lol.h"
#include "kyra/screen_hof.h"
#include "kyra/screen_mr.h"
#include "kyra/resource.h"
@@ -287,8 +288,10 @@ bool StaticResource::init() {
} else if (_vm->game() == GI_KYRA3) {
_builtIn = 0;
_filenameTable = kyra3StaticRes;
+ } else if (_vm->game() == GI_LOL) {
+ return true;
} else {
- error("unknown game ID");
+ error("StaticResource: Unknown game ID");
}
char errorBuffer[100];
@@ -2236,5 +2239,105 @@ const int8 KyraEngine_MR::_albumWSAY[] = {
-1, -2, 2, 2, -6, -6, -6, 0
};
+// lands of lore static res
+
+const ScreenDim Screen_LoL::_screenDimTable[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0xC7, 0xCF, 0x00, 0x00 }
+};
+
+const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable);
+
+const char * const LoLEngine::_languageExt[] = {
+ "ENG",
+ "FRE",
+ "GER"
+};
+
+const LoLEngine::CharacterPrev LoLEngine::_charPreviews[] = {
+ { "Ak\'shel", 0x060, 0x7F, { 0x0F, 0x08, 0x05 } },
+ { "Michael", 0x09A, 0x7F, { 0x06, 0x0A, 0x0F } },
+ { "Kieran", 0x0D4, 0x7F, { 0x08, 0x06, 0x08 } },
+ { "Conrad", 0x10F, 0x7F, { 0x0A, 0x0C, 0x0A } }
+};
+
+const uint8 LoLEngine::_chargenFrameTable[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x04, 0x03, 0x02, 0x01,
+ 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x0E, 0x0F, 0x10, 0x11, 0x12
+};
+
+const uint16 LoLEngine::_selectionPosTable[] = {
+ 0x6F, 0x00, 0x8F, 0x00, 0xAF, 0x00, 0xCF, 0x00,
+ 0xEF, 0x00, 0x6F, 0x20, 0x8F, 0x20, 0xAF, 0x20,
+ 0xCF, 0x20, 0xEF, 0x20, 0x6F, 0x40, 0x8F, 0x40,
+ 0xAF, 0x40, 0xCF, 0x40, 0xEF, 0x40, 0x10F, 0x00
+};
+
+const uint8 LoLEngine::_selectionChar1IdxTable[] = {
+ 0, 0, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 0, 0, 5, 5, 5,
+ 5, 5, 5, 5, 0, 0, 5, 5,
+ 5, 5, 5
+};
+
+const uint8 LoLEngine::_selectionChar2IdxTable[] = {
+ 1, 1, 6, 6, 1, 1, 6, 6,
+ 6, 6, 6, 6, 6, 1, 1, 6,
+ 6, 6, 1, 1, 6, 6, 6, 6,
+ 6, 6, 6
+};
+
+const uint8 LoLEngine::_selectionChar3IdxTable[] = {
+ 2, 2, 7, 7, 7, 7, 2, 2,
+ 7, 7, 7, 7, 7, 7, 7, 2,
+ 2, 7, 7, 7, 7, 2, 2, 7,
+ 7, 7, 7
+};
+
+const uint8 LoLEngine::_selectionChar4IdxTable[] = {
+ 3, 3, 8, 8, 8, 8, 3, 3,
+ 8, 8, 3, 3, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 3, 3, 8,
+ 8, 8, 8
+};
+
+const uint8 LoLEngine::_reminderChar1IdxTable[] = {
+ 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5
+};
+
+const uint8 LoLEngine::_reminderChar2IdxTable[] = {
+ 9, 9, 9, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6
+};
+
+const uint8 LoLEngine::_reminderChar3IdxTable[] = {
+ 0xE, 0xE, 0xE, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7
+};
+
+const uint8 LoLEngine::_reminderChar4IdxTable[] = {
+ 0xF, 0xF, 0xF, 0x8, 0x8, 0x8, 0x8, 0x8,
+ 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8,
+ 0x8
+};
+
+const uint8 LoLEngine::_selectionAnimIndexTable[] = {
+ 0, 5, 1, 6, 2, 7, 3, 8
+};
+
+const uint8 LoLEngine::_charInfoFrameTable[] = {
+ 0x0, 0x7, 0x8, 0x9, 0xA, 0xB, 0xA, 0x9,
+ 0x8, 0x7, 0x0, 0x0, 0x7, 0x8, 0x9, 0xA,
+ 0xB, 0xA, 0x9, 0x8, 0x7, 0x0, 0x0, 0x7,
+ 0x8, 0x9, 0xA, 0xB, 0xA, 0x9, 0x8, 0x7
+};
+
} // End of namespace Kyra