diff options
author | Christopher Page | 2008-08-04 22:34:07 +0000 |
---|---|---|
committer | Christopher Page | 2008-08-04 22:34:07 +0000 |
commit | 4198ee962399305a4a158b1f43224c00e2e04a1b (patch) | |
tree | eea375b5cb471509df2e2c5d9123d963a62403c6 /engines/kyra | |
parent | a51f45407659bba43254b466d20b6af2e8f17ffd (diff) | |
parent | 4f5479ee744ac6b419cdf7ec1e96fbf7c83d36ef (diff) | |
download | scummvm-rg350-4198ee962399305a4a158b1f43224c00e2e04a1b.tar.gz scummvm-rg350-4198ee962399305a4a158b1f43224c00e2e04a1b.tar.bz2 scummvm-rg350-4198ee962399305a4a158b1f43224c00e2e04a1b.zip |
Merged revisions 33188-33189,33191-33193,33196,33198,33202-33203,33206,33210,33212,33218-33220,33222,33224-33226,33229-33243,33246,33248-33250,33252,33258-33261,33263,33266,33270,33272-33283,33285,33287-33290,33295-33298,33321,33325-33330,33332-33335,33337-33340,33342,33345,33347,33349-33350,33352-33357,33359-33367,33369-33371,33373,33375-33377,33379-33380,33383-33385,33387-33389,33392-33394,33400-33402,33404-33405,33407-33410,33412-33416,33418-33419,33425-33427,33432,33436-33438,33444,33446,33452-33453,33455-33459,33463-33464,33466-33471,33473-33474,33478,33490,33492,33495-33496,33509-33512,33518-33519,33522-33527,33529-33530,33537,33541,33544,33546,33550,33552-33554,33556,33558,33561-33562,33565,33568,33570,33574,33576,33578-33581,33584-33587,33590,33596,33604-33611,33614-33615,33617-33618,33620-33621 via svnmerge from
https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk
svn-id: r33624
Diffstat (limited to 'engines/kyra')
31 files changed, 2310 insertions, 159 deletions
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index fce1e93bc2..f8aa44be63 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" @@ -55,6 +56,7 @@ namespace { #define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2) #define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA2) #define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, Kyra::GI_KYRA2) #define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, Kyra::GI_KYRA2) #define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA2) #define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2) @@ -64,6 +66,11 @@ 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) +#define LOL_PC98_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_PC98_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_LOL) +#define LOL_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA2) + const KYRAGameDescription adGameDescs[] = { { { @@ -207,7 +214,7 @@ const KYRAGameDescription adGameDescs[] = { { // FM-Towns version { "kyra1", - 0, + "CD", { { "EMC.PAK", 0, "a046bb0b422061aab8e4c4689400343a", -1 }, { "TWMUSIC.PAK", 0, "e53bca3a3e3fb49107d59463ec387a59", -1 }, @@ -215,14 +222,14 @@ const KYRAGameDescription adGameDescs[] = { }, Common::EN_ANY, Common::kPlatformFMTowns, - Common::ADGF_NO_FLAGS + Common::ADGF_CD }, KYRA1_TOWNS_FLAGS }, { { "kyra1", - 0, + "CD", { { "JMC.PAK", 0, "9c5707a2a478e8167e44283246612d2c", -1 }, { "TWMUSIC.PAK", 0, "e53bca3a3e3fb49107d59463ec387a59", -1 }, @@ -230,7 +237,7 @@ const KYRAGameDescription adGameDescs[] = { }, Common::JA_JPN, Common::kPlatformFMTowns, - Common::ADGF_NO_FLAGS + Common::ADGF_CD }, KYRA1_TOWNS_SJIS_FLAGS }, @@ -418,6 +425,41 @@ const KYRAGameDescription adGameDescs[] = { KYRA2_CD_FLAGS }, + // Italian fan translation, see fr#2003504 "KYRA: add support for Italian version of Kyrandia 2&3" + { // CD version + { + "kyra2", + "CD", + AD_ENTRY1("FATE.PAK", "30487f3b8d7790c7857f4769ff2dd125"), + Common::IT_ITA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE | Common::ADGF_CD + }, + KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY) + }, + { + { + "kyra2", + "CD", + AD_ENTRY1("FATE.PAK", "30487f3b8d7790c7857f4769ff2dd125"), + Common::DE_DEU, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE | Common::ADGF_CD + }, + KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY) + }, + { + { + "kyra2", + "CD", + AD_ENTRY1("FATE.PAK", "30487f3b8d7790c7857f4769ff2dd125"), + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE | Common::ADGF_CD + }, + KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY) + }, + { // Interactive Demo { "kyra2", @@ -454,11 +496,11 @@ const KYRAGameDescription adGameDescs[] = { KYRA2_CD_DEMO_FLAGS }, - { // Non-Interactive Demo + { // Non-Interactive Demos { "kyra2", "Demo", - AD_ENTRY1("GENERAL.PAK", "35825783e5b60755fd520360079f9c15"), + AD_ENTRY1("VOC.PAK", "ecb3561b63749158172bf21528cf5f45"), Common::EN_ANY, Common::kPlatformPC, Common::ADGF_DEMO @@ -469,44 +511,44 @@ const KYRAGameDescription adGameDescs[] = { { // FM-Towns { "kyra2", - 0, + "CD", AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"), Common::EN_ANY, Common::kPlatformFMTowns, - Common::ADGF_NO_FLAGS + Common::ADGF_CD }, KYRA2_TOWNS_FLAGS }, { { "kyra2", - 0, + "CD", AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"), Common::JA_JPN, Common::kPlatformFMTowns, - Common::ADGF_NO_FLAGS + Common::ADGF_CD }, KYRA2_TOWNS_SJIS_FLAGS }, { // PC-9821 { "kyra2", - 0, + "CD", AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"), Common::EN_ANY, Common::kPlatformPC98, - Common::ADGF_NO_FLAGS + Common::ADGF_CD }, KYRA2_TOWNS_FLAGS }, { { "kyra2", - 0, + "CD", AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"), Common::JA_JPN, Common::kPlatformPC98, - Common::ADGF_NO_FLAGS + Common::ADGF_CD }, KYRA2_TOWNS_SJIS_FLAGS }, @@ -700,6 +742,151 @@ 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 + }, + + { + { + "lol", + "CD", + { + { "GENERAL.PAK", 0, "9e4bab499b7ea9337b91ac29fcba6d13", -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, "9e4bab499b7ea9337b91ac29fcba6d13", -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, "9e4bab499b7ea9337b91ac29fcba6d13", -1 }, + { "L01.PAK", 0, "759a0ac26808d77ea968bd392355ba1d", -1 }, + { 0, 0, 0, 0 } + }, + Common::FR_FRA, + Common::kPlatformPC, + Common::ADGF_DROPLANGUAGE | Common::ADGF_CD + }, + LOL_CD_FLAGS + }, + + /*{ + { + "lol", + 0, + { + { "GENERAL.PAK", 0, "3fe6539b9b09084c0984eaf7170464e9", -1 }, + { "MUS.PAK", 0, "008dc69d8cbcdb6bae30e270fab26e76", -1 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, + Common::kPlatformPC98, + Common::ADGF_NO_FLAGS + }, + LOL_PC98_FLAGS + }, + + { + { + "lol", + 0, + { + { "GENERAL.PAK", 0, "3fe6539b9b09084c0984eaf7170464e9", -1 }, + { "MUS.PAK", 0, "008dc69d8cbcdb6bae30e270fab26e76", -1 }, + { 0, 0, 0, 0 } + }, + Common::JA_JPN, + Common::kPlatformPC98, + Common::ADGF_NO_FLAGS + }, + LOL_PC98_SJIS_FLAGS + },*/ + + { + { + "lol", + "Demo", + { + { "GENERAL.PAK", 0, "e94863d86c4597a2d581d05481c152ba", -1 }, + { 0, 0, 0, 0 } + }, + Common::EN_ANY, + Common::kPlatformPC, + Common::ADGF_NO_FLAGS + }, + LOL_DEMO_FLAGS + }, + { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) } }; @@ -707,6 +894,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 +967,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/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 092aaedb23..818d2f9b4e 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -526,7 +526,7 @@ int GUI_LoK::resumeGame(Button *button) { void GUI_LoK::setupSavegames(Menu &menu, int num) { Common::InSaveFile *in; - static char savenames[5][31]; + static char savenames[5][35]; uint8 startSlot; assert(num <= 5); @@ -545,7 +545,8 @@ void GUI_LoK::setupSavegames(Menu &menu, int num) { KyraEngine_v1::SaveHeader header; for (int i = startSlot; i < num && uint(_savegameOffset + i) < _saveSlots.size(); i++) { if ((in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i + _savegameOffset]), header))) { - strncpy(savenames[i], header.description.c_str(), 31); + strncpy(savenames[i], header.description.c_str(), ARRAYSIZE(savenames[0])); + savenames[i][34] = 0; menu.item[i].itemString = savenames[i]; menu.item[i].enabled = 1; menu.item[i].saveSlot = _saveSlots[i + _savegameOffset]; @@ -669,7 +670,7 @@ void GUI_LoK::updateSavegameString() { length = strlen(_savegameName); if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127) { - if (length < 31) { + if (length < ARRAYSIZE(_savegameName)-1) { _savegameName[length] = _keyPressed.ascii; _savegameName[length+1] = 0; redrawTextfield(); diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h index 49081c7ae2..16b7ef9183 100644 --- a/engines/kyra/gui_lok.h +++ b/engines/kyra/gui_lok.h @@ -162,7 +162,7 @@ private: bool _menuRestoreScreen; uint8 _toplevelMenu; int _savegameOffset; - char _savegameName[31]; + char _savegameName[35]; const char *_specialSavegameString; Common::KeyState _keyPressed; int8 _mouseWheel; diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index 11f430040c..a7ae2a6c44 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -456,6 +456,7 @@ void GUI_v2::setupSavegameNames(Menu &menu, int num) { for (int i = startSlot; i < num && uint(_savegameOffset + i) < _saveSlots.size(); ++i) { if ((in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i + _savegameOffset]), header)) != 0) { strncpy(getTableString(menu.item[i].itemId), header.description.c_str(), 80); + getTableString(menu.item[i].itemId)[79] = 0; menu.item[i].saveSlot = _saveSlots[i + _savegameOffset]; menu.item[i].enabled = true; delete in; diff --git a/engines/kyra/gui_v2.h b/engines/kyra/gui_v2.h index 161752627b..60b7f0ab86 100644 --- a/engines/kyra/gui_v2.h +++ b/engines/kyra/gui_v2.h @@ -188,7 +188,7 @@ protected: // save menu bool _noSaveProcess; int _saveSlot; - char _saveDescription[0x50]; + char _saveDescription[0x51]; int saveMenu(Button *caller); int clickSaveSlot(Button *caller); diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index ac69272ef4..fd14e8c909 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) { @@ -251,7 +251,7 @@ int KyraEngine_HoF::init() { _abortIntroFlag = false; if (_sequenceStrings) { - for (int i = 0; i < 33; i++) + for (int i = 0; i < MIN(33, _sequenceStringsSize); i++) _sequenceStringsDuration[i] = (int) strlen(_sequenceStrings[i]) * 8; } @@ -278,7 +278,10 @@ int KyraEngine_HoF::go() { seq_showStarcraftLogo(); if (_flags.isDemo && !_flags.isTalkie) { - seq_playSequences(kSequenceDemoVirgin, kSequenceDemoFisher); + if (_flags.gameID == GI_LOL) + seq_playSequences(kSequenceLolDemoScene1, kSequenceLolDemoScene6); + else + seq_playSequences(kSequenceDemoVirgin, kSequenceDemoFisher); _menuChoice = 4; } else { seq_playSequences(kSequenceVirgin, kSequenceZanfaun); diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h index 866dd55d16..279e9e35a6 100644 --- a/engines/kyra/kyra_hof.h +++ b/engines/kyra/kyra_hof.h @@ -97,6 +97,20 @@ enum kNestedSequencesDemo { kSequenceDemoDig }; +enum kSequencesLolDemo { + kSequenceLolDemoScene1 = 0, + kSequenceLolDemoText1, + kSequenceLolDemoScene2, + kSequenceLolDemoText2, + kSequenceLolDemoScene3, + kSequenceLolDemoText3, + kSequenceLolDemoScene4, + kSequenceLolDemoText4, + kSequenceLolDemoScene5, + kSequenceLolDemoText5, + kSequenceLolDemoScene6 +}; + class WSAMovie_v2; class KyraEngine_HoF; class TextDisplayer_HoF; @@ -242,6 +256,14 @@ protected: int seq_demoBail(WSAMovie_v2 *wsaObj, int x, int y, int frm); int seq_demoDig(WSAMovie_v2 *wsaObj, int x, int y, int frm); + int seq_lolDemoScene1(WSAMovie_v2 *wsaObj, int x, int y, int frm); + int seq_lolDemoScene2(WSAMovie_v2 *wsaObj, int x, int y, int frm); + int seq_lolDemoScene3(WSAMovie_v2 *wsaObj, int x, int y, int frm); + int seq_lolDemoScene4(WSAMovie_v2 *wsaObj, int x, int y, int frm); + int seq_lolDemoScene5(WSAMovie_v2 *wsaObj, int x, int y, int frm); + int seq_lolDemoText5(WSAMovie_v2 *wsaObj, int x, int y, int frm); + int seq_lolDemoScene6(WSAMovie_v2 *wsaObj, int x, int y, int frm); + void seq_sequenceCommand(int command); void seq_loadNestedSequence(int wsaNum, int seqNum); void seq_nestedSequenceFrame(int command, int wsaNum); @@ -264,7 +286,7 @@ protected: WSAMovie_v2 * wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos); void seq_finaleActorScreen(); void seq_displayScrollText(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); - void seq_scrollPage(); + void seq_scrollPage(int bottom, int top); void seq_showStarcraftLogo(); void seq_init(); diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index afd164958c..f668ae8401 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -173,7 +173,8 @@ int KyraEngine_LoK::init() { initStaticResource(); - _sound->setSoundList(&_soundData[kMusicIntro]); + if (_soundData) + _sound->setSoundList(&_soundData[kMusicIntro]); _trackMap = _dosTrackMap; _trackMapSize = _dosTrackMapSize; @@ -316,7 +317,8 @@ void KyraEngine_LoK::startup() { debugC(9, kDebugLevelMain, "KyraEngine_LoK::startup()"); static const uint8 colorMap[] = { 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0 }; _screen->setTextColorMap(colorMap); - _sound->setSoundList(&_soundData[kMusicIngame]); + if (_soundData) + _sound->setSoundList(&_soundData[kMusicIngame]); _sound->loadSoundFile(0); // _screen->setFont(Screen::FID_6_FNT); _screen->setAnimBlockPtr(3750); diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 6121f6979c..f3014911fc 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -112,7 +112,7 @@ int KyraEngine_v1::init() { _sound = new SoundTownsPC98_v2(this, _mixer); } else if (_flags.platform == Common::kPlatformPC98) { if (_flags.gameID == GI_KYRA1) - _sound = new SoundTowns/*SoundPC98*/(this, _mixer); + _sound = new SoundPC98(this, _mixer); else _sound = new SoundTownsPC98_v2(this, _mixer); } else if (midiDriver == MD_ADLIB) { @@ -150,6 +150,16 @@ int KyraEngine_v1::init() { _res = new Resource(this); assert(_res); _res->reset(); + + if (_flags.isDemo) { + // HACK: check whether this is the HOF demo or the LOL demo. + // The LOL demo needs to be detected and run as KyraEngine_HoF, + // but the static resource loader and the sequence player will + // need correct IDs. + if (_res->exists("scene1.cps")) + _flags.gameID = GI_LOL; + } + _staticres = new StaticResource(this); assert(_staticres); if (!_staticres->init()) diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 8dd95c79b9..6d61bd997f 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -34,8 +34,8 @@ #include "kyra/script.h" namespace Common { -class InSaveFile; -class OutSaveFile; +class SeekableReadStream; +class WriteStream; } // end of namespace Common class KyraMetaEngine; @@ -64,7 +64,8 @@ struct GameFlags { enum { GI_KYRA1 = 0, GI_KYRA2 = 1, - GI_KYRA3 = 2 + GI_KYRA3 = 2, + GI_LOL = 4 }; struct AudioDataStruct { @@ -293,10 +294,10 @@ protected: kRSHEIoError = 3 }; - static kReadSaveHeaderError readSaveHeader(Common::InSaveFile *file, SaveHeader &header); + static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *file, SaveHeader &header); - Common::InSaveFile *openSaveForReading(const char *filename, SaveHeader &header); - Common::OutSaveFile *openSaveForWriting(const char *filename, const char *saveName) const; + Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header); + Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName) const; }; } // End of namespace Kyra 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..5d3c5ff715 100644 --- a/engines/kyra/resource.cpp +++ b/engines/kyra/resource.cpp @@ -99,6 +99,8 @@ bool Resource::reset() { loadFileList("FILEDATA.FDT"); return true; + } else if (_vm->game() == GI_LOL) { + return true; } FSList fslist; @@ -1120,7 +1122,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 +1187,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/saveload.cpp b/engines/kyra/saveload.cpp index 147c774a52..0dc7cf2c02 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -95,6 +95,9 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::InSave if (header.version <= 8) { char buffer[31]; in->read(buffer, 31); + // WORKAROUND: Old savegames could contain a missing termination 0 at the + // end so we manually add it. + buffer[30] = 0; header.description = buffer; } else { header.description = ""; diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 6e7a88b1a3..0cde066cc0 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -380,61 +380,23 @@ void Screen::fadePalette(const uint8 *palData, int delay, const UpdateFunctor *u debugC(9, kDebugLevelScreen, "Screen::fadePalette(%p, %d, %p)", (const void *)palData, delay, (const void*)upFunc); updateScreen(); - uint8 fadePal[768]; - memcpy(fadePal, _screenPalette, 768); - uint8 diff, maxDiff = 0; - for (int i = 0; i < 768; ++i) { - diff = ABS(palData[i] - fadePal[i]); - if (diff > maxDiff) { - maxDiff = diff; - } - } - - int16 delayInc = delay << 8; - if (maxDiff != 0) - delayInc /= maxDiff; - - delay = delayInc; - for (diff = 1; diff <= maxDiff; ++diff) { - if (delayInc >= 512) - break; - delayInc += delay; - } + int diff = 0, delayInc = 0; + getFadeParams(palData, delay, delayInc, diff); int delayAcc = 0; while (!_vm->quit()) { delayAcc += delayInc; - bool needRefresh = false; - for (int i = 0; i < 768; ++i) { - int c1 = palData[i]; - int c2 = fadePal[i]; - if (c1 != c2) { - needRefresh = true; - if (c1 > c2) { - c2 += diff; - if (c1 < c2) - c2 = c1; - } - - if (c1 < c2) { - c2 -= diff; - if (c1 > c2) - c2 = c1; - } - fadePal[i] = (uint8)c2; - } - } - - if (!needRefresh) - break; + int refreshed = fadePalStep(palData, diff); - setScreenPalette(fadePal); if (upFunc && upFunc->isValid()) (*upFunc)(); else _system->updateScreen(); - //_system->delayMillis((delayAcc >> 8) * 1000 / 60); + + if (!refreshed) + break; + _vm->delay((delayAcc >> 8) * 1000 / 60); delayAcc &= 0xFF; } @@ -448,6 +410,64 @@ void Screen::fadePalette(const uint8 *palData, int delay, const UpdateFunctor *u } } +void Screen::getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff) { + debugC(9, kDebugLevelScreen, "Screen::getFadeParams(%p, %d, %p, %p)", (const void *)palette, delay, (const void *)&delayInc, (const void *)&diff); + uint8 maxDiff = 0; + + const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256) * 3; + for (int i = 0; i < colors; ++i) { + diff = ABS(palette[i] - _screenPalette[i]); + maxDiff = MAX<uint8>(maxDiff, diff); + } + + delayInc = delay << 8; + if (maxDiff != 0) + delayInc /= maxDiff; + delayInc &= 0x7FFF; + + delay = delayInc; + for (diff = 1; diff <= maxDiff; ++diff) { + if (delayInc >= 512) + break; + delayInc += delay; + } +} + +int Screen::fadePalStep(const uint8 *palette, int diff) { + debugC(9, kDebugLevelScreen, "Screen::fadePalStep(%p, %d)", (const void *)palette, diff); + + uint8 fadePal[768]; + memcpy(fadePal, _screenPalette, 768); + + bool needRefresh = false; + const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256) * 3; + for (int i = 0; i < colors; ++i) { + int c1 = palette[i]; + int c2 = fadePal[i]; + if (c1 != c2) { + needRefresh = true; + if (c1 > c2) { + c2 += diff; + if (c1 < c2) + c2 = c1; + } + + if (c1 < c2) { + c2 -= diff; + if (c1 > c2) + c2 = c1; + } + + fadePal[i] = (uint8)c2; + } + } + + if (needRefresh) + setScreenPalette(fadePal); + + return needRefresh ? 1 : 0; +} + void Screen::setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue) { debugC(9, kDebugLevelScreen, "Screen::setPaletteIndex(%u, %u, %u, %u)", index, red, green, blue); _currentPalette[index * 3 + 0] = red; @@ -459,7 +479,7 @@ void Screen::setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue) { void Screen::setScreenPalette(const uint8 *palData) { debugC(9, kDebugLevelScreen, "Screen::setScreenPalette(%p)", (const void *)palData); - int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256); + const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256); if (palData != _screenPalette) memcpy(_screenPalette, palData, colors*3); @@ -2442,7 +2462,7 @@ void Screen::setShapePages(int page1, int page2, int minY, int maxY) { _maskMaxY = maxY; } -void Screen::setMouseCursor(int x, int y, byte *shape) { +void Screen::setMouseCursor(int x, int y, const byte *shape) { debugC(9, kDebugLevelScreen, "Screen::setMouseCursor(%d, %d, %p)", x, y, (const void *)shape); if (!shape) return; diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index f8c85a2bac..99ba2d7c5f 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -89,10 +89,12 @@ public: enum FontId { FID_6_FNT = 0, FID_8_FNT, + FID_9_FNT, FID_CRED6_FNT, FID_CRED8_FNT, FID_BOOKFONT_FNT, FID_GOLDFONT_FNT, + FID_INTRO_FNT, FID_NUM }; @@ -145,6 +147,8 @@ public: void fadeToBlack(int delay=0x54, const UpdateFunctor *upFunc = 0); void fadePalette(const uint8 *palData, int delay, const UpdateFunctor *upFunc = 0); + virtual void getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff); + int fadePalStep(const uint8 *palette, int diff); void setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue); void setScreenPalette(const uint8 *palData); @@ -189,7 +193,7 @@ public: void hideMouse(); void showMouse(); bool isMouseVisible() const; - void setMouseCursor(int x, int y, byte *shape); + void setMouseCursor(int x, int y, const byte *shape); // rect handling virtual int getRectSize(int w, int h) = 0; 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 e26ef87bad..c6ea6a93e8 100644 --- a/engines/kyra/screen_v2.cpp +++ b/engines/kyra/screen_v2.cpp @@ -111,6 +111,30 @@ int Screen_v2::findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *p return r; } +void Screen_v2::getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff) { + debugC(9, kDebugLevelScreen, "Screen_v2::getFadeParams(%p, %d, %p, %p)", (const void *)palette, delay, (const void *)&delayInc, (const void *)&diff); + + int maxDiff = 0; + diff = 0; + for (int i = 0; i < 768; ++i) { + diff = ABS(palette[i] - _screenPalette[i]); + maxDiff = MAX(maxDiff, diff); + } + + delayInc = delay << 8; + if (maxDiff != 0) { + delayInc /= maxDiff; + delayInc = MIN(delayInc, 0x7FFF); + } + + delay = delayInc; + for (diff = 1; diff <= maxDiff; ++diff) { + if (delayInc >= 256) + break; + delayInc += delay; + } +} + void Screen_v2::copyWsaRect(int x, int y, int w, int h, int dimState, int plotFunc, const uint8 *src, int unk1, const uint8 *unkPtr1, const uint8 *unkPtr2) { uint8 *dstPtr = getPagePtr(_curPage); @@ -369,7 +393,7 @@ void Screen_v2::wsaFrameAnimationStep(int x1, int y1, int x2, int y2, int t = (nb * h1) / h2; if (t != u) { u = t; - const uint8 *s = src + (x1 + t) * 320; + const uint8 *s = src + x1 + t * 320; uint8 *dt = (uint8 *)_wsaFrameAnimBuffer; t = w2 - w1; @@ -461,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 f624228445..7bbdc4b6c3 100644 --- a/engines/kyra/screen_v2.h +++ b/engines/kyra/screen_v2.h @@ -40,10 +40,14 @@ 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); int findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *palette, uint16 numColors); + + virtual void getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff); // shape handling uint8 *getPtrToShape(uint8 *shpFile, int shape); diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index 94f160d11f..e3a8bf95bc 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -1492,7 +1492,7 @@ typedef Common::Functor1Mem<EMCState*, int, KyraEngine_HoF> OpcodeV2; typedef Common::Functor2Mem<const TIM*, const uint16*, int, KyraEngine_HoF> TIMOpcodeV2; #define OpcodeTim(x) _timOpcodes.push_back(new TIMOpcodeV2(this, &KyraEngine_HoF::x)) -#define OpcodeTimUnImpl() _timOpcodes.push_back(TIMOpcodeV2(this, 0)) +#define OpcodeTimUnImpl() _timOpcodes.push_back(new TIMOpcodeV2(this, 0)) void KyraEngine_HoF::setupOpcodeTable() { Common::Array<const Opcode*> *table = 0; diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 4b82232049..9b215b2c03 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,89 @@ 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))); + _vm->sound()->loadSoundFile(file); + 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 +605,23 @@ 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); 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); + 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/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp index 7e0220af8a..b42374f44f 100644 --- a/engines/kyra/sequences_hof.cpp +++ b/engines/kyra/sequences_hof.cpp @@ -50,7 +50,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { _sound->setSoundList(&_soundData[(startSeq > kSequenceZanfaun) ? kMusicFinale : kMusicIntro]); _sound->loadSoundFile(0); - _screen->_charWidth = -2; + _screen->_charWidth = (_flags.gameID == GI_LOL) ? 0 : -2; memset(_activeWSA, 0, sizeof(ActiveWSA) * 8); for (int i = 0; i < 8; ++i) @@ -300,8 +300,8 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { _eventList.clear(); seqNum = kSequenceFirates; } - } else if (seqNum == kSequenceDemoFisher && !(_abortIntroFlag || skipFlag())) { - seqNum = kSequenceDemoVirgin; + } else if (seqNum == endSeq && !(_abortIntroFlag || skipFlag())) { + seqNum = 0; } if (_menuChoice) { @@ -1722,7 +1722,7 @@ int KyraEngine_HoF::seq_demoFisher(WSAMovie_v2 *wsaObj, int x, int y, int frm) { _seqScrollTextCounter = 0; } - seq_scrollPage(); + seq_scrollPage(24, 144); _seqFrameCounter++; if (_seqFrameCounter < 0x256 || _seqFrameCounter > 0x31c) { if (_seqFrameCounter < 0x174 || _seqFrameCounter > 0x1d7) { @@ -1740,7 +1740,7 @@ int KyraEngine_HoF::seq_demoFisher(WSAMovie_v2 *wsaObj, int x, int y, int frm) { } } else { - seq_scrollPage(); + seq_scrollPage(24, 144); } return 0; } @@ -1796,6 +1796,182 @@ int KyraEngine_HoF::seq_demoDig(WSAMovie_v2 *wsaObj, int x, int y, int frm) { return frm; } +int KyraEngine_HoF::seq_lolDemoScene1(WSAMovie_v2 *wsaObj, int x, int y, int frm) { + uint8 *tmpPal = _screen->getPalette(2); + + if (!(_seqFrameCounter % 100)) { + if (_seqFrameCounter == 0) { + _sound->haltTrack(); + _sound->playTrack(6); + } + memcpy(tmpPal, _screen->getPalette(0), 0x300); + for (int i = 3; i < 0x300; i++) { + tmpPal[i] = ((int)tmpPal[i] * 120) / 64; + if (tmpPal[i] > 0x3f) + tmpPal[i] = 0x3f; + } + seq_playTalkText(_rnd.getRandomBit()); + _screen->setScreenPalette(tmpPal); + _screen->updateScreen(); + delay(8); + } else { + _screen->setScreenPalette(_screen->getPalette(0)); + _screen->updateScreen(); + if (_seqFrameCounter == 40) + seq_playTalkText(3); + } + + _seqFrameCounter++; + return frm; +} + +int KyraEngine_HoF::seq_lolDemoScene2(WSAMovie_v2 *wsaObj, int x, int y, int frm) { + switch (_seqFrameCounter - 17) { + case 0: + _seqFrameDelay = 8; + break; + case 3: + case 6: + case 9: + seq_playTalkText(8); + break; + case 15: + seq_playTalkText(9); + break; + case 18: + seq_playTalkText(2); + break; + default: + break; + } + _seqFrameCounter++; + return frm; +} + +int KyraEngine_HoF::seq_lolDemoScene3(WSAMovie_v2 *wsaObj, int x, int y, int frm) { + if (_seqFrameCounter == 1) + seq_playTalkText(6); + else if (frm == 26) + seq_playTalkText(7); + + _seqFrameCounter++; + return frm; +} + +int KyraEngine_HoF::seq_lolDemoScene4(WSAMovie_v2 *wsaObj, int x, int y, int frm) { + switch (_seqFrameCounter) { + case 11: + case 14: + case 17: + case 20: + seq_playTalkText(8); + break; + case 22: + seq_playTalkText(11); + break; + case 24: + seq_playTalkText(8); + break; + case 30: + seq_playTalkText(15); + break; + case 34: + seq_playTalkText(14); + break; + case 38: + seq_playTalkText(13); + break; + case 42: + seq_playTalkText(12); + break; + default: + break; + } + + _seqFrameCounter++; + return frm; +} + +int KyraEngine_HoF::seq_lolDemoScene5(WSAMovie_v2 *wsaObj, int x, int y, int frm) { + switch (_seqFrameCounter++) { + 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: + seq_playTalkText(15); + break; + case 32: + seq_playTalkText(16); + break; + case 42: + seq_playTalkText(6); + break; + default: + break; + } + return frm; +} + +int KyraEngine_HoF::seq_lolDemoText5(WSAMovie_v2 *wsaObj, int x, int y, int frm) { + if (_seqFrameCounter++ == 100) + seq_playTalkText(5); + return frm; +} + +int KyraEngine_HoF::seq_lolDemoScene6(WSAMovie_v2 *wsaObj, int x, int y, int frm) { + while (_seqScrollTextCounter < 0x122) { + _seqEndTime = _system->getMillis() + 6 * _tickLength; + if (!_seqFrameCounter) { + _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); + _seqScrollTextCounter = 0; + } + + if (_seqFrameCounter % 175) { + _screen->setScreenPalette(_screen->getPalette(0)); + } else { + uint8 *tmpPal = _screen->getPalette(2); + memcpy(tmpPal, _screen->getPalette(0), 0x300); + for (int i = 3; i < 0x300; i++) { + tmpPal[i] = ((int)tmpPal[i] * 120) / 64; + if (tmpPal[i] > 0x3f) + tmpPal[i] = 0x3f; + } + seq_playTalkText(_rnd.getRandomBit()); + _screen->setScreenPalette(tmpPal); + _screen->updateScreen(); + delay(8); + } + + if (_seqFrameCounter == 40 || _seqFrameCounter == 80 || _seqFrameCounter == 150 || _seqFrameCounter == 300) + seq_playTalkText(3); + + _screen->copyPage(12, 2); + seq_scrollPage(70, 130); + _screen->copyPage(2, 0); + _screen->updateScreen(); + _seqFrameCounter++; + if (_seqFrameCounter < 128 || _seqFrameCounter > 207) + _seqScrollTextCounter++; + delayUntil(_seqEndTime); + } + _screen->copyPage(2, 12); + + return 0; +} + uint32 KyraEngine_HoF::seq_activeTextsTimeLeft() { uint32 res = 0; @@ -1892,16 +2068,14 @@ void KyraEngine_HoF::seq_sequenceCommand(int command) { switch (command) { case 0: memset(pal, 0, 0x300); - _screen->fadePalette(pal, 16); + _screen->fadePalette(pal, 36); memcpy (_screen->getPalette(0), pal, 0x300); memcpy (_screen->getPalette(1), pal, 0x300); break; case 1: memset(pal, 0x3F, 0x300); - //////////XXX - //////////Unused anyway (at least by fm-towns intro/outro) - + seq_playTalkText(_rnd.getRandomBit()); _screen->fadePalette(pal, 16); memcpy (_screen->getPalette(0), pal, 0x300); memcpy (_screen->getPalette(1), pal, 0x300); @@ -2575,32 +2749,34 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int delete[] textData; } -void KyraEngine_HoF::seq_scrollPage() { +void KyraEngine_HoF::seq_scrollPage(int bottom, int top) { int dstY, dstH, srcH; static const ScreenDim d = { 0x00, 0x00, 0x28, 0x320, 0xFF, 0xFE, 0x00, 0x00 }; - if (_seqScrollTextCounter - 143 < 0) { - dstY = 144 - _seqScrollTextCounter; + if (_seqScrollTextCounter - (top - 1) < 0) { + dstY = top - _seqScrollTextCounter; dstH = _seqScrollTextCounter; srcH = 0; } else { dstY = 0; - srcH = _seqScrollTextCounter - 144; - dstH = (400 - srcH <= 144) ? 400 - srcH : 144; + srcH = _seqScrollTextCounter - top; + dstH = (400 - srcH <= top) ? 400 - srcH : top; } if (dstH > 0) { - for (int i = 0; i < 4; i++) { - const ItemAnimData_v1 *def = &_demoAnimData[i]; - ActiveItemAnim *a = &_activeItemAnim[i]; - - _screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4); - _screen->drawShape(4, getShapePtr(def->itemIndex + def->frames[a->currentFrame]), 12, def->y - 8, 0, 0); - if(_seqFrameCounter % 2 == 0) - a->currentFrame = ++a->currentFrame % 20; + if (_demoAnimData) { + for (int i = 0; i < 4; i++) { + const ItemAnimData_v1 *def = &_demoAnimData[i]; + ActiveItemAnim *a = &_activeItemAnim[i]; + + _screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4); + _screen->drawShape(4, getShapePtr(def->itemIndex + def->frames[a->currentFrame]), 12, def->y - 8, 0, 0); + if(_seqFrameCounter % 2 == 0) + a->currentFrame = ++a->currentFrame % 20; + } } - _screen->copyRegionEx(4, 0, srcH, 2, 2, dstY + 24, 320, dstH, &d); + _screen->copyRegionEx(4, 0, srcH, 2, 2, dstY + bottom, 320, dstH, &d); } } @@ -2656,6 +2832,10 @@ void KyraEngine_HoF::seq_init() { _res->loadFileList(_sequencePakList, _sequencePakListSize); int numShp = -1; + + if (_flags.gameID == GI_LOL) + return; + if (_flags.isDemo && !_flags.isTalkie) { _demoAnimData = _staticres->loadShapeAnimData_v1(k2SeqplayShapeAnimData, _itemAnimDataSize); uint8 *shp = _res->fileData("icons.shp", 0); diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index 5068268d99..073639e4ca 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -104,6 +104,11 @@ int32 Sound::voicePlay(const char *file, bool isSfx) { fileSize = 0; } + if (!audioStream) { + warning("Couldn't load sound file '%s'", file); + return 0; + } + _soundChannels[h].file = file; _mixer->playInputStream(isSfx ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType, &_soundChannels[h].channelHandle, audioStream); @@ -202,8 +207,8 @@ bool SoundMidiPC::init() { } void SoundMidiPC::updateVolumeSettings() { - _musicVolume = ConfMan.getInt("music_volume"); - _sfxVolume = ConfMan.getInt("sfx_volume"); + _musicVolume = CLIP(ConfMan.getInt("music_volume"), 0, 255); + _sfxVolume = CLIP(ConfMan.getInt("sfx_volume"), 0, 255); updateChannelVolume(_musicVolume); } @@ -323,7 +328,17 @@ struct DeleterArray { void SoundMidiPC::loadSoundFile(uint file) { Common::StackLock lock(_mutex); - Common::String filename = fileListEntry(file); + internalLoadFile(fileListEntry(file)); +} + +void SoundMidiPC::loadSoundFile(Common::String file) { + Common::StackLock lock(_mutex); + + internalLoadFile(file); +} + +void SoundMidiPC::internalLoadFile(Common::String file) { + Common::String filename = file; filename += "."; filename += _useC55 ? "C55" : "XMI"; diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index cebfdf491f..e5294eb15d 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -120,6 +120,12 @@ public: virtual void loadSoundFile(uint file) = 0; /** + * Load a sound file for playing music + * and sound effects from. + */ + virtual void loadSoundFile(Common::String file) = 0; + + /** * Plays the specified track. * * @param track track number @@ -215,8 +221,6 @@ protected: int _musicEnabled; bool _sfxEnabled; - int _currentTheme; - KyraEngine_v1 *_vm; Audio::Mixer *_mixer; @@ -260,6 +264,7 @@ public: void process(); void loadSoundFile(uint file); + void loadSoundFile(Common::String file); void playTrack(uint8 track); void haltTrack(); @@ -269,6 +274,8 @@ public: void beginFadeOut(); private: + void internalLoadFile(Common::String file); + void play(uint8 track); void unk1(); @@ -280,7 +287,8 @@ private: uint8 _trackEntries[500]; uint8 *_soundDataPtr; int _sfxPlayingSound; - uint _soundFileLoaded; + + Common::String _soundFileLoaded; uint8 _sfxPriority; uint8 _sfxFourthByteOfSong; @@ -316,6 +324,7 @@ public: void updateVolumeSettings(); void loadSoundFile(uint file); + void loadSoundFile(Common::String file); void playTrack(uint8 track); void haltTrack(); @@ -343,6 +352,7 @@ public: bool isMT32() const { return _nativeMT32; } private: + void internalLoadFile(Common::String file); void updateChannelVolume(uint8 vol); static void onTimer(void *data); @@ -397,6 +407,7 @@ public: void process(); void loadSoundFile(uint file); + void loadSoundFile(Common::String) {} void playTrack(uint8 track); void haltTrack(); @@ -454,6 +465,7 @@ public: void process() {} void loadSoundFile(uint file) {} + void loadSoundFile(Common::String) {} void playTrack(uint8 track); void haltTrack(); @@ -480,6 +492,7 @@ public: void process(); void loadSoundFile(uint file) {} + void loadSoundFile(Common::String) {} void playTrack(uint8 track); void haltTrack(); @@ -513,6 +526,7 @@ public: void setSoundList(const AudioDataStruct * list) { _music->setSoundList(list); _sfx->setSoundList(list); } bool hasSoundFile(uint file) const { return _music->hasSoundFile(file) && _sfx->hasSoundFile(file); } void loadSoundFile(uint file) { _music->loadSoundFile(file); _sfx->loadSoundFile(file); } + void loadSoundFile(Common::String file) { _music->loadSoundFile(file); _sfx->loadSoundFile(file); } void playTrack(uint8 track) { _music->playTrack(track); } void haltTrack() { _music->haltTrack(); } diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp index 68a2f0be9c..62551d2b09 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,12 +2220,12 @@ 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); _sfxPlayingSound = -1; - _soundFileLoaded = (uint)-1; + _soundFileLoaded.clear(); if (_v2) { // TODO: Figure out if Kyra 2 uses sound triggers at all. @@ -2262,7 +2269,7 @@ void SoundAdlibPC::playTrack(uint8 track) { // sync for each loop. To avoid that, we declare that all four // of the song channels have to jump "in sync". - if (track == 4 && scumm_stricmp(fileListEntry(_soundFileLoaded), "KYRA1B") == 0) + if (track == 4 && _soundFileLoaded.equalsIgnoreCase("KYRA1B.ADL")) _driver->setSyncJumpMask(0x000F); else _driver->setSyncJumpMask(0); @@ -2341,6 +2348,15 @@ void SoundAdlibPC::beginFadeOut() { } void SoundAdlibPC::loadSoundFile(uint file) { + internalLoadFile(fileListEntry(file)); +} + +void SoundAdlibPC::loadSoundFile(Common::String file) { + internalLoadFile(file); +} + +void SoundAdlibPC::internalLoadFile(Common::String file) { + file += ".ADL"; if (_soundFileLoaded == file) return; @@ -2349,12 +2365,9 @@ void SoundAdlibPC::loadSoundFile(uint file) { uint8 *file_data = 0; uint32 file_size = 0; - char filename[25]; - sprintf(filename, "%s.ADL", fileListEntry(file)); - - file_data = _vm->resource()->fileData(filename, &file_size); + file_data = _vm->resource()->fileData(file.c_str(), &file_size); if (!file_data) { - warning("Couldn't find music file: '%s'", filename); + warning("Couldn't find music file: '%s'", file.c_str()); return; } diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 0f2b916c9d..ec1962a58f 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -2363,7 +2363,7 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : _numSSG(type == OD_TOWNS ? 0 : 3), _hasADPCM(type == OD_TYPE86 ? true : false), _numChan(type == OD_TYPE26 ? 3 : 6), _hasStereo(type == OD_TYPE26 ? false : true) { setTempo(84); - _baserate = (double)getRate() / 10368.0; + _baserate = (486202500.0 / (double)getRate()) / 10368.0; } TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index c05795dacd..7d7f0cd4b8 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" @@ -42,7 +43,7 @@ namespace Kyra { -#define RESFILE_VERSION 28 +#define RESFILE_VERSION 31 bool StaticResource::checkKyraDat() { Common::File kyraDat; @@ -278,6 +279,16 @@ bool StaticResource::init() { { 0, 0, 0 } }; + static const FilenameTable lolStaticRes[] = { + // Demo Sequence Player + { k2SeqplayPakFiles, kStringList, "S_PAKFILES.TXT" }, + { k2SeqplayStrings, kLanguageList, "S_STRINGS." }, + { k2SeqplaySfxFiles, kStringList, "S_SFXFILES.TXT" }, + { k2SeqplaySeqData, k2SeqData, "S_DATA.SEQ" }, + { k2SeqplayIntroTracks, kStringList, "S_INTRO.TRA" }, + { 0, 0, 0 } + }; + if (_vm->game() == GI_KYRA1) { _builtIn = 0; _filenameTable = kyra1StaticRes; @@ -287,8 +298,13 @@ bool StaticResource::init() { } else if (_vm->game() == GI_KYRA3) { _builtIn = 0; _filenameTable = kyra3StaticRes; + } else if (_vm->game() == GI_LOL) { + if (!_vm->gameFlags().isDemo) + return true; + _builtIn = 0; + _filenameTable = lolStaticRes; } else { - error("unknown game ID"); + error("StaticResource: Unknown game ID"); } char errorBuffer[100]; @@ -917,6 +933,8 @@ const char *StaticResource::getFilename(const char *name) { filename += ".K2"; else if (_vm->gameFlags().gameID == GI_KYRA3) filename += ".K3"; + else if (_vm->gameFlags().gameID == GI_LOL) + filename += ".LOL"; if (_vm->gameFlags().isTalkie && _vm->gameFlags().gameID != GI_KYRA3) filename += ".CD"; @@ -1034,10 +1052,8 @@ void KyraEngine_LoK::initStaticResource() { } // audio data tables -#if 0 static const char *tIntro98[] = { "intro%d.dat" }; static const char *tIngame98[] = { "kyram%d.dat" }; -#endif static const AudioDataStruct soundData_PC[] = { { _soundFilesIntro, _soundFilesIntroSize, 0, 0 }, @@ -1051,21 +1067,20 @@ void KyraEngine_LoK::initStaticResource() { { 0, 0, 0, 0} }; -#if 0 static const AudioDataStruct soundData_PC98[] = { { tIntro98, 1, 0, 0 }, { tIngame98, 1, 0, 0 }, { 0, 0, 0, 0} }; -#endif if (_flags.platform == Common::kPlatformPC) _soundData = soundData_PC; else if (_flags.platform == Common::kPlatformFMTowns) _soundData = soundData_TOWNS; else if (_flags.platform == Common::kPlatformPC98) - _soundData = soundData_TOWNS/*soundData_PC98*/; - + _soundData = soundData_PC98; + else + _soundData = 0; } void KyraEngine_LoK::loadMouseShapes() { @@ -1263,11 +1278,9 @@ void KyraEngine_HoF::initStaticResource() { static const char *fmtMusicFileListFinale[] = { "finale%d.twn" }; static const char *fmtMusicFileListIngame[] = { "km%02d.twn" }; -#if 0 static const char *pc98MusicFileListIntro[] = { "intro%d.86" }; static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; -#endif static const AudioDataStruct soundData_PC[] = { { _musicFileListIntro, _musicFileListIntroSize, 0, 0 }, @@ -1281,20 +1294,18 @@ void KyraEngine_HoF::initStaticResource() { { fmtMusicFileListFinale, 1, _cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1 } }; -#if 0 static const AudioDataStruct soundData_PC98[] = { { pc98MusicFileListIntro, 1, 0, 0 }, { pc98MusicFileListIngame, 1, 0, 0 }, { pc98MusicFileListFinale, 1, 0, 0 } }; -#endif if (_flags.platform == Common::kPlatformPC) _soundData = soundData_PC; else if (_flags.platform == Common::kPlatformFMTowns) _soundData = soundData_TOWNS; else if (_flags.platform == Common::kPlatformPC98) - _soundData = soundData_TOWNS/*soundData_PC98*/; + _soundData = soundData_PC98; // setup sequence data _sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize); @@ -1333,8 +1344,17 @@ void KyraEngine_HoF::initStaticResource() { &KyraEngine_HoF::seq_demoDig, 0 }; - _callbackS = (_flags.isDemo && !_flags.isTalkie) ? hofDemoSequenceCallbacks : hofSequenceCallbacks; - _callbackN = (_flags.isDemo && !_flags.isTalkie) ? hofDemoNestedSequenceCallbacks : hofNestedSequenceCallbacks; + static const SeqProc lolDemoSequenceCallbacks[] = { + &KyraEngine_HoF::seq_lolDemoScene1, 0, &KyraEngine_HoF::seq_lolDemoScene2, 0, + &KyraEngine_HoF::seq_lolDemoScene3, 0, &KyraEngine_HoF::seq_lolDemoScene4, 0, + &KyraEngine_HoF::seq_lolDemoScene5, &KyraEngine_HoF::seq_lolDemoText5, + &KyraEngine_HoF::seq_lolDemoScene6, 0 + }; + + static const SeqProc lolDemoNestedSequenceCallbacks[] = { 0 }; + + _callbackS = _flags.gameID == GI_LOL ? lolDemoSequenceCallbacks : ((_flags.isDemo && !_flags.isTalkie) ? hofDemoSequenceCallbacks : hofSequenceCallbacks); + _callbackN = _flags.gameID == GI_LOL ? lolDemoNestedSequenceCallbacks : ((_flags.isDemo && !_flags.isTalkie) ? hofDemoNestedSequenceCallbacks : hofNestedSequenceCallbacks); } void KyraEngine_MR::initStaticResource() { @@ -2236,5 +2256,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 diff --git a/engines/kyra/wsamovie.h b/engines/kyra/wsamovie.h index 36cd75b1ab..1db8ee8474 100644 --- a/engines/kyra/wsamovie.h +++ b/engines/kyra/wsamovie.h @@ -109,7 +109,7 @@ private: class WSAMovie_v2 : public WSAMovie_v1 { public: - WSAMovie_v2(KyraEngine_v1 *vm, Screen_v2 *scren); + WSAMovie_v2(KyraEngine_v1 *vm, Screen_v2 *screen); int open(const char *filename, int unk1, uint8 *palette); |