diff options
author | Norbert Lange | 2009-07-01 14:45:24 +0000 |
---|---|---|
committer | Norbert Lange | 2009-07-01 14:45:24 +0000 |
commit | abef70f4e14f495b20097cb46411d1fafbafdd53 (patch) | |
tree | 27462f82f352b303ac059dd275466930c88b2de6 /engines | |
parent | 3b94e2488df9a699a899727515ac69af6a0a1a6e (diff) | |
parent | f9298ff40310149779b37ccdecc873afba7adf2f (diff) | |
download | scummvm-rg350-abef70f4e14f495b20097cb46411d1fafbafdd53.tar.gz scummvm-rg350-abef70f4e14f495b20097cb46411d1fafbafdd53.tar.bz2 scummvm-rg350-abef70f4e14f495b20097cb46411d1fafbafdd53.zip |
Merging in changes from trunk
svn-id: r41989
Diffstat (limited to 'engines')
240 files changed, 15516 insertions, 15914 deletions
diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp index 0676c0f8e4..e373dd3e6d 100644 --- a/engines/agi/agi.cpp +++ b/engines/agi/agi.cpp @@ -729,6 +729,8 @@ void AgiEngine::initialize() { // because Apple IIGS AGI games use only Apple IIGS specific sound resources. if (getPlatform() == Common::kPlatformApple2GS) { _soundemu = SOUND_EMU_APPLE2GS; + } else if (getPlatform() == Common::kPlatformCoCo3) { + _soundemu = SOUND_EMU_COCO3; } else { switch (MidiDriver::detectMusicDriver(MDT_PCSPK)) { case MD_PCSPK: diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp index aef236ce64..bf4622bc08 100644 --- a/engines/agi/cycle.cpp +++ b/engines/agi/cycle.cpp @@ -198,7 +198,9 @@ int AgiEngine::mainCycle() { // In AGI Mouse emulation mode we must update the mouse-related // vars in every interpreter cycle. - if (getFeatures() & GF_AGIMOUSE) { + // + // We run AGIMOUSE always as a side effect + if (getFeatures() & GF_AGIMOUSE || 1) { _game.vars[28] = g_mouse.x / 2; _game.vars[29] = g_mouse.y; } diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 302951b69b..910f6e0e55 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -168,6 +168,9 @@ using Common::GUIO_NONE; #define FANMADE_ILVF(id,name,md5,lang,ver,features) GAME_LVFPN(id,name,"logdir",md5,-1,lang,ver,(GF_FANMADE|features),GID_FANMADE,Common::kPlatformPC,GType_V2) +#define FANMADE_ISVP(id,name,md5,size,ver,platform) GAME_LVFPN(id,name,"logdir",md5,size,Common::EN_ANY,ver,GF_FANMADE,GID_FANMADE,platform,GType_V2) +#define FANMADE_SVP(name,md5,size,ver,platform) FANMADE_ISVP("agi-fanmade",name,md5,size,ver,platform) + #define FANMADE_LVF(name,md5,lang,ver,features) FANMADE_ILVF("agi-fanmade",name,md5,lang,ver,features) #define FANMADE_LF(name,md5,lang,features) FANMADE_LVF(name,md5,lang,0x2917,features) @@ -222,6 +225,12 @@ static const AGIGameDescription gameDescriptions[] = { // Black Cauldron (PC) 2.10 [AGI 3.002.097] GAME3("bc", "2.10", "bcdir", "0de3953c9225009dc91e5b0d1692967b", 0x3149, GID_BC), + // Black Cauldron (CoCo3 360k) [AGI 2.023] + GAME_PS("bc", "", "51212c54808ade96176f201ae0ac7a6f", 357, 0x2440, GID_BC, Common::kPlatformCoCo3), + + // Black Cauldron (CoCo3 360k) [AGI 2.072] + GAME_PS("bc", "updated", "c4e1937f74e8100cd0152b904434d8b4", 357, 0x2440, GID_BC, Common::kPlatformCoCo3), + // TODO // These aren't supposed to work now as they require unsupported agi engine 2.01 #if 0 @@ -279,6 +288,12 @@ static const AGIGameDescription gameDescriptions[] = { }, + // Gold Rush! (CoCo3 720k) [AGI 2.023] + GAME_PS("goldrush", "", "0a41b65efc0cd6c4271e957e6ffbbd8e", 744, 0x2440, GID_GOLDRUSH, Common::kPlatformCoCo3), + + // Gold Rush! (CoCo3 360k/720k) [AGI 2.072] + GAME_PS("goldrush", "updated", "c49bf56bf91e31a4601a604e51ef8bfb", 744, 0x2440, GID_GOLDRUSH, Common::kPlatformCoCo3), + // King's Quest 1 (Amiga) 1.0U # 2.082 // The original game did not have menus, they are enabled under ScummVM GAME_FP("kq1", "1.0U 1986", "246c695324f1c514aee2b904fa352fad", 0x2440, GF_MENUS, GID_KQ1, Common::kPlatformAmiga), @@ -297,6 +312,15 @@ static const AGIGameDescription gameDescriptions[] = { // King's Quest 1 (PC 5.25"/3.5") 2.0F [AGI 2.917] GAME("kq1", "2.0F 1987-05-05 5.25\"/3.5\"", "10ad66e2ecbd66951534a50aedcd0128", 0x2917, GID_KQ1), + // King's Quest 1 (CoCo3 360k) [AGI 2.023] + GAME_PS("kq1", "", "10ad66e2ecbd66951534a50aedcd0128", 315, 0x2440, GID_KQ1, Common::kPlatformCoCo3), + + // King's Quest 1 (CoCo3 360k) [AGI 2.023] + GAME_PS("kq1", "fixed", "4c8ef8b5d2f1b6c1a93e456d1f1ffc74", 768, 0x2440, GID_KQ1, Common::kPlatformCoCo3), + + // King's Quest 1 (CoCo3 360k) [AGI 2.072] + GAME_PS("kq1", "updated", "94087178c78933a4af3cd24d1c8dd7b2", 315, 0x2440, GID_KQ1, Common::kPlatformCoCo3), + // King's Quest 2 (IIgs) 2.0A 6/16/88 (CE) GAME_P("kq2", "2.0A 1988-06-16 (CE)", "5203c8b95250a2ecfee93ddb99414753", 0x2917, GID_KQ2, Common::kPlatformApple2GS), @@ -316,6 +340,15 @@ static const AGIGameDescription gameDescriptions[] = { // King's Quest 2 (Russian) GAME_LPS("kq2", "", "35211c574ececebdc723b23e35f99275", 543, Common::RU_RUS, 0x2917, GID_KQ2, Common::kPlatformPC), + // King's Quest 2 (CoCo3 360k) [AGI 2.023] + GAME_PS("kq2", "", "b944c4ff18fb8867362dc21cc688a283", 543, 0x2440, GID_KQ2, Common::kPlatformCoCo3), + + // King's Quest 2 (CoCo3 360k) [AGI 2.072] + GAME_PS("kq2", "updated", "f64a606de740a5348f3d125c03e989fe", 543, 0x2440, GID_KQ2, Common::kPlatformCoCo3), + + // King's Quest 2 (CoCo3 360k) [AGI 2.023] + GAME_PS("kq2", "fixed", "fb33ac2768a94a89117a270771db465c", 768, 0x2440, GID_KQ2, Common::kPlatformCoCo3), + // King's Quest 3 (Amiga) 1.01 11/8/86 // The original game did not have menus, they are enabled under ScummVM GAME_FP("kq3", "1.01 1986-11-08", "8ab343306df0e2d98f136be4e8cfd0ef", 0x2440, GF_MENUS, GID_KQ3, Common::kPlatformAmiga), @@ -350,6 +383,9 @@ static const AGIGameDescription gameDescriptions[] = { // King's Quest 3 (PC 3.5") 2.14 3/15/88 [AGI 2.936] GAME("kq3", "2.14 1988-03-15 3.5\"", "d3d17b77b3b3cd13246749231d9473cd", 0x2936, GID_KQ3), + // King's Quest 3 (CoCo3 158k/360k) [AGI 2.023] + GAME_PS("kq3", "", "5a6be7d16b1c742c369ef5cc64fefdd2", 429, 0x2440, GID_KQ3, Common::kPlatformCoCo3), + // King's Quest 4 (PC 5.25") 2.3 9/27/88 [AGI 3.002.086] GAME3("kq4", "2.3 1988-09-27", "kq4dir", "6d7714b8b61466a5f5981242b993498f", 0x3086, GID_KQ4), @@ -371,6 +407,12 @@ static const AGIGameDescription gameDescriptions[] = { // Menus not tested GAME3("kq4", "Demo 1988-12-20", "dmdir", "a3332d70170a878469d870b14863d0bf", 0x3149, GID_KQ4), + // King's Quest 4 (CoCo3 720k) [AGI 2.023] + GAME_PS("kq4", "", "9e7729a28e749ca241d2bf71b9b2dbde", 741, 0x2440, GID_KQ4, Common::kPlatformCoCo3), + + // King's Quest 4 (CoCo3 360k/720k) [AGI 2.072] + GAME_PS("kq4", "updated", "1959ca10739edb34069bb504dbd74805", 741, 0x2440, GID_KQ4, Common::kPlatformCoCo3), + // Leisure Suit Larry 1 (PC 5.25"/3.5") 1.00 6/1/87 [AGI 2.440] GAME("lsl1", "1.00 1987-06-01 5.25\"/3.5\"", "1fe764e66857e7f305a5f03ca3f4971d", 0x2440, GID_LSL1), @@ -392,6 +434,9 @@ static const AGIGameDescription gameDescriptions[] = { // Leisure Suit Larry 1 (Mac) 1.05 6/26/87 GAME_P("lsl1", "1.05 1987-06-26", "8a0076429890531832f0dc113285e31e", 0x2440, GID_LSL1, Common::kPlatformMacintosh), + // Leisure Suit Larry 1 (CoCo3 158k/360k) [AGI 2.072] + GAME_PS("lsl1", "", "a2de1fe76565c3e8b40c9d036b5e5612", 198, 0x2440, GID_LSL1, Common::kPlatformCoCo3), + // Manhunter NY (ST) 1.03 10/20/88 GAME3_P("mh1", "1.03 1988-10-20", "mhdir", "f2d58056ad802452d60776ee920a52a6", 0x3149, 0, GID_MH1, Common::kPlatformAtariST), @@ -408,6 +453,12 @@ static const AGIGameDescription gameDescriptions[] = { // Manhunter NY (PC 3.5") 1.22 8/31/88 [AGI 3.002.102] GAME3_PS("mh1", "1.22 1988-08-31", "mhdir", "5b625329021ad49fd0c1d6f2d6f54bba", 2141, 0x3149, 0, GID_MH1, Common::kPlatformPC), + // Manhunter NY (CoCo3 720k) [AGI 2.023] + GAME_PS("mh1", "", "b968285caf2f591c78dd9c9e26ab8974", 495, 0x2440, GID_MH1, Common::kPlatformCoCo3), + + // Manhunter NY (CoCo3 360k/720k) [AGI 2.072] + GAME_PS("mh1", "updated", "d47da950c62289f8d4ccf36af73365f2", 495, 0x2440, GID_MH1, Common::kPlatformCoCo3), + // Manhunter SF (ST) 1.0 7/29/89 GAME3_P("mh2", "1.0 1989-07-29", "mh2dir", "5e3581495708b952fea24438a6c7e040", 0x3149, 0, GID_MH1, Common::kPlatformAtariST), @@ -420,6 +471,12 @@ static const AGIGameDescription gameDescriptions[] = { // Manhunter SF (PC 3.5") 3.02 7/26/89 [AGI 3.002.149] GAME3("mh2", "3.02 1989-07-26 3.5\"", "mh2dir", "6fb6f0ee2437704c409cf17e081ba152", 0x3149, GID_MH2), + // Manhunter SF (CoCo3 720k) [AGI 2.023] + GAME_PS("mh2", "", "acaaa577e10d1753c5a74f6ae1d858d4", 591, 0x2440, GID_MH2, Common::kPlatformCoCo3), + + // Manhunter SF (CoCo3 720k) [AGI 2.072] + GAME_PS("mh2", "updated", "c64875766700196e72a92359f70f45a9", 591, 0x2440, GID_MH2, Common::kPlatformCoCo3), + // Mickey's Space Adventure // Preagi game GAMEpre_P("mickey", "", "1.pic", "b6ec04c91a05df374792872c4d4ce66d", 0x0000, GID_MICKEY, Common::kPlatformPC), @@ -437,11 +494,8 @@ static const AGIGameDescription gameDescriptions[] = { // Mixed-Up Mother Goose (PC) [AGI 2.915] GAME("mixedup", "1987-11-10", "e524655abf9b96a3b179ffcd1d0f79af", 0x2917, GID_MIXEDUP), -#if 0 - // Mixed Up Mother Goose (PC) [AGI 2.915] (Broken) - // Menus not tested - GAME("mixedup", "[corrupt/OBJECT from disk 1]", "e524655abf9b96a3b179ffcd1d0f79af", 0x2917, GID_MIXEDUP), -#endif + // Mixed-Up Mother Goose (CoCo3 360k) [AGI 2.072] + GAME_PS("mixedup", "", "44e63e9b4d4822a31edea0e8a7e7eac4", 606, 0x2440, GID_MIXEDUP, Common::kPlatformCoCo3), // Police Quest 1 (PC) 2.0E 11/17/87 [AGI 2.915] GAME("pq1", "2.0E 1987-11-17", "2fd992a92df6ab0461d5a2cd83c72139", 0x2917, GID_PQ1), @@ -471,6 +525,12 @@ static const AGIGameDescription gameDescriptions[] = { // not sure about disk format -- dsymonds GAME("pq1", "2.0G 1987-12-03", "d194e5d88363095f55d5096b8e32fbbb", 0x2917, GID_PQ1), + // Police Quest 1 (CoCo3 360k) [AGI 2.023] + GAME_PS("pq1", "", "28a077041f75aab78f66804800940085", 375, 0x2440, GID_PQ1, Common::kPlatformCoCo3), + + // Police Quest 1 (CoCo3 360k) [AGI 2.072] + GAME_PS("pq1", "updated", "63b9a9c6eec154751dd446cd3693e0e2", 768, 0x2440, GID_PQ1, Common::kPlatformCoCo3), + // Space Quest 1 (ST) 1.1A // The original game did not have menus, they are enabled under ScummVM GAME_FP("sq1", "1.1A 1986-02-06", "6421fb64b0e6604c9dd065975d9279e9", 0x2440, GF_MENUS, GID_SQ1, Common::kPlatformAtariST), @@ -499,8 +559,14 @@ static const AGIGameDescription gameDescriptions[] = { // Space Quest 1 (PC 5.25"/3.5") 2.2 [AGI 2.426/2.917] GAME("sq1", "2.2 1987-05-07 5.25\"/3.5\"", "5d67630aba008ec5f7f9a6d0a00582f4", 0x2440, GID_SQ1), - // Space Quest 1 (CoCo3) - GAME_P("sq1", "", "5d67630aba008ec5f7f9a6d0a00582f4", 0x2440, GID_SQ1, Common::kPlatformCoCo3), + // Space Quest 1 (CoCo3 360k) [AGI 2.072] + GAME_PS("sq1", "", "5d67630aba008ec5f7f9a6d0a00582f4", 372, 0x2440, GID_SQ1, Common::kPlatformCoCo3), + + // Space Quest 1 (CoCo3 360k) [AGI 2.023] + GAME_PS("sq1", "fixed", "ca822b768b6462e410423ea7f498daee", 768, 0x2440, GID_SQ1, Common::kPlatformCoCo3), + + // Space Quest 1 (CoCo3 360k) [AGI 2.072] + GAME_PS("sq1", "updated", "7fa54e6bb7ffeb4cf20eca39d86f5fb2", 387, 0x2440, GID_SQ1, Common::kPlatformCoCo3), // Space Quest 2 (PC 3.5") 2.0D [AGI 2.936] GAME("sq2", "2.0D 1988-03-14 3.5\"", "85390bde8958c39830e1adbe9fff87f3", 0x2936, GID_SQ2), @@ -550,6 +616,12 @@ static const AGIGameDescription gameDescriptions[] = { // Space Quest 2 (PC 3.5") 2.0F [AGI 2.936] GAME("sq2", "2.0F 1989-01-05 3.5\"", "28add5125484302d213911df60d2aded", 0x2936, GID_SQ2), + // Space Quest 2 (CoCo3 360k) [AGI 2.023] + GAME_PS("sq2", "", "12973d39b892dc9d280257fd271e9597", 768, 0x2440, GID_SQ2, Common::kPlatformCoCo3), + + // Space Quest 2 (CoCo3 360k) [AGI 2.072] + GAME_PS("sq2", "updated", "d24f19b047e65e1763eff4b46f3d50df", 768, 0x2440, GID_SQ2, Common::kPlatformCoCo3), + // Troll's Tale GAMEpre_PS("troll", "", "troll.img", "62903f264b3d849be4214b3a5c42a2fa", 184320, 0x0000, GID_TROLL, Common::kPlatformPC), @@ -568,6 +640,9 @@ static const AGIGameDescription gameDescriptions[] = { // Xmas Card 1986 (PC) [AGI 2.272] GAME("xmascard", "1986-11-13 [version 1]", "3067b8d5957e2861e069c3c0011bd43d", 0x2272, GID_XMASCARD), + // Xmas Card 1986 (CoCo3 360k) [AGI 2.072] + GAME_PS("xmascard", "", "25ad35e9628fc77e5e0dd35852a272b6", 768, 0x2440, GID_XMASCARD, Common::kPlatformCoCo3), + FANMADE_F("2 Player Demo", "4279f46b3cebd855132496476b1d2cca", GF_AGIMOUSE), FANMADE("AGI Contest 1 Template", "d879aed25da6fc655564b29567358ae2"), FANMADE("AGI Contest 2 Template", "5a2fb2894207eff36c72f5c1b08bcc07"), @@ -630,6 +705,7 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Elfintard", "c3b847e9e9e978af9708df76a0751dc2"), FANMADE("Enclosure (v1.01)", "f08e66fee9ecdde77db7ee9a10c96ba2"), FANMADE("Enclosure (v1.03)", "e4a0613ed02401502e506ba3565a8c40"), + FANMADE_SVP("Enclosure", "fe98e6126db74c6cc6fd8fe395cc6e8c", 345, 0x2440, Common::kPlatformCoCo3), FANMADE("Epic Fighting (v0.1)", "aff24a1b3bdd676187685c4d95ba4294"), FANMADE("Escape Quest (v0.0.3)", "2346b65619b1da0298b715b06d1a45a1"), FANMADE("Escape from the Desert (beta 1)", "dfdc634d340854bd6ece28024010758d"), @@ -777,8 +853,10 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("Sorceror's Appraisal", "fe62615557b3cb7b08dd60c9d35efef1"), FANMADE_I("sq0", "v1.03", "d2fd6f7404e86182458494e64375e590"), FANMADE_I("sq0", "v1.04", "2ad9d1a4624a98571ee77dcc83f231b6"), + FANMADE_ISVP("sq0", "", "e1a8e4efcce86e1efcaa14633b9eb986", 762, 0x2440, Common::kPlatformCoCo3), FANMADE_I("sqx", "v10.0 Feb 05", "c992ae2f8ab18360404efdf16fa9edd1"), FANMADE_I("sqx", "v10.0 Jul 18", "812edec45cefad559d190ffde2f9c910"), + FANMADE_ISVP("sqx", "", "f0a59044475a5fa37c055d8c3eb4d1a7", 768, 0x2440, Common::kPlatformCoCo3), FANMADE_F("Space Quest 3.5", "c077bc28d7b36213dd99dc9ecb0147fc", GF_AGIMOUSE|GF_AGIPAL), FANMADE_F("Space Trek (v1.0)", "807a1aeadb2ace6968831d36ab5ea37a", GF_CLIPCOORDS), FANMADE("Special Delivery", "88764dfe61126b8e73612c851b510a33"), @@ -805,6 +883,7 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("The Shadow Plan", "c02cd10267e721f4e836b1431f504a0a"), FANMADE("Time Quest (Demo v0.1)", "12e1a6f03ea4b8c5531acd0400b4ed8d"), FANMADE("Time Quest (Demo v0.2)", "7b710608abc99e0861ac59b967bf3f6d"), + FANMADE_SVP("Time Quest", "90314f473d8317be5cd1f0306f139aea", 300, 0x2440, Common::kPlatformCoCo3), FANMADE("Tonight The Shrieking Corpses Bleed (Demo v0.11)", "bcc57a7c8d563fa0c333107ae1c0a6e6"), FANMADE("Tonight The Shrieking Corpses Bleed (v1.01)", "36b38f621b38e8d104aa0807302dc8c9"), FANMADE("Turks' Quest - Heir to the Planet", "3d19254b737c8b218e5bc4580542b79a"), @@ -826,6 +905,7 @@ static const AGIGameDescription gameDescriptions[] = { GF_FANMADE, 0x3149, }, + FANMADE_SVP("V - The Graphical Adventure", "1646eaade74f137a9041eb427a389969", 768, 0x2440, Common::kPlatformCoCo3), FANMADE("Voodoo Girl - Queen of the Darned (v1.2 2002 Jan 1)", "ae95f0c77d9a97b61420fd192348b937"), FANMADE("Voodoo Girl - Queen of the Darned (v1.2 2002 Mar 29)", "11d0417b7b886f963d0b36789dac4c8f"), diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp index a620788de2..97255097bc 100644 --- a/engines/agi/op_cmd.cpp +++ b/engines/agi/op_cmd.cpp @@ -1520,7 +1520,8 @@ cmd(print_at_v) { } cmd(push_script) { - if (g_agi->getFeatures() & GF_AGIMOUSE) { + // We run AGIMOUSE always as a side effect + if (g_agi->getFeatures() & GF_AGIMOUSE || 1) { game.vars[27] = g_mouse.button; game.vars[28] = g_mouse.x / 2; game.vars[29] = g_mouse.y; diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp index b0856f6ddf..fb73c6b71f 100644 --- a/engines/agi/sound.cpp +++ b/engines/agi/sound.cpp @@ -367,7 +367,7 @@ void SoundMgr::startSound(int resnum, int flag) { _vm->_game.sounds[resnum]->play(); _playingSound = resnum; - debugC(3, kDebugLevelSound, "startSound(resnum = %d, flag = %d)", resnum, flag); + debugC(3, kDebugLevelSound, "startSound(resnum = %d, flag = %d) type = %d", resnum, flag, type); switch (type) { case AGI_SOUND_SAMPLE: { @@ -411,6 +411,8 @@ void SoundMgr::startSound(int resnum, int flag) { void SoundMgr::stopSound() { int i; + debugC(3, kDebugLevelSound, "stopSound() --> %d", _playingSound); + _endflag = -1; if (_vm->_soundemu != SOUND_EMU_APPLE2GS) { for (i = 0; i < NUM_CHANNELS; i++) @@ -418,7 +420,8 @@ void SoundMgr::stopSound() { } if (_playingSound != -1) { - _vm->_game.sounds[_playingSound]->stop(); + if (_vm->_game.sounds[_playingSound]) // sanity checking + _vm->_game.sounds[_playingSound]->stop(); if (_vm->_soundemu == SOUND_EMU_APPLE2GS) { _gsSound.stopSounds(); @@ -474,6 +477,8 @@ int SoundMgr::initSound() { case SOUND_EMU_APPLE2GS: _disabledMidi = !loadInstruments(); break; + case SOUND_EMU_COCO3: + break; } report("Initializing sound:\n"); @@ -819,6 +824,35 @@ void SoundMgr::playSampleSound() { _playing = _gsSound.activeSounds() > 0; } +static int cocoFrequencies[] = { + 130, 138, 146, 155, 164, 174, 184, 195, 207, 220, 233, 246, + 261, 277, 293, 311, 329, 349, 369, 391, 415, 440, 466, 493, + 523, 554, 587, 622, 659, 698, 739, 783, 830, 880, 932, 987, + 1046, 1108, 1174, 1244, 1318, 1396, 1479, 1567, 1661, 1760, 1864, 1975, + 2093, 2217, 2349, 2489, 2637, 2793, 2959, 3135, 3322, 3520, 3729, 3951 +}; + +void SoundMgr::playCoCoSound() { + int i = 0; + CoCoNote note; + + do { + note.read(_chn[i].ptr); + + if (note.freq != 0xff) { + playNote(0, cocoFrequencies[note.freq], note.volume); + + uint32 start_time = _vm->_system->getMillis(); + + while (_vm->_system->getMillis() < start_time + note.duration) { + _vm->_system->updateScreen(); + + _vm->_system->delayMillis(10); + } + } + } while (note.freq != 0xff); +} + void SoundMgr::playAgiSound() { int i; AgiNote note; @@ -875,6 +909,8 @@ void SoundMgr::playSound() { playSampleSound(); } } + } else if (_vm->_soundemu == SOUND_EMU_COCO3) { + playCoCoSound(); } else { //debugC(3, kDebugLevelSound, "playSound: Trying to play a PCjr 4-channel sound"); playAgiSound(); diff --git a/engines/agi/sound.h b/engines/agi/sound.h index fd178e3a1d..a24a665b2a 100644 --- a/engines/agi/sound.h +++ b/engines/agi/sound.h @@ -51,6 +51,7 @@ namespace Agi { #define SOUND_EMU_MAC 3 #define SOUND_EMU_AMIGA 4 #define SOUND_EMU_APPLE2GS 5 +#define SOUND_EMU_COCO3 6 #define WAVEFORM_SIZE 64 #define ENV_ATTACK 10000 /**< envelope attack rate */ @@ -228,27 +229,42 @@ struct IIgsChannelInfo { bool playing(); ///< Is there a note playing on this channel? }; - /** - * AGI sound resource types. - * It's probably coincidence that all the values here are powers of two - * as they're simply the different used values in AGI sound resources' - * starts (The first 16-bit little endian word, to be precise). - */ - enum AgiSoundType { - AGI_SOUND_SAMPLE = 0x0001, - AGI_SOUND_MIDI = 0x0002, - AGI_SOUND_4CHN = 0x0008 - }; - enum AgiSoundFlags { - AGI_SOUND_LOOP = 0x0001, - AGI_SOUND_ENVELOPE = 0x0002 - }; - enum AgiSoundEnv { - AGI_SOUND_ENV_ATTACK = 3, - AGI_SOUND_ENV_DECAY = 2, - AGI_SOUND_ENV_SUSTAIN = 1, - AGI_SOUND_ENV_RELEASE = 0 - }; +struct CoCoNote { + uint8 freq; + uint8 volume; + uint16 duration; ///< Note duration + + /** Reads a CoCoNote through the given pointer. */ + void read(const uint8 *ptr) { + freq = *ptr; + volume = *(ptr + 1); + duration = READ_LE_UINT16(ptr + 2); + } +}; + +/** + * AGI sound resource types. + * It's probably coincidence that all the values here are powers of two + * as they're simply the different used values in AGI sound resources' + * starts (The first 16-bit little endian word, to be precise). + */ +enum AgiSoundType { + AGI_SOUND_SAMPLE = 0x0001, + AGI_SOUND_MIDI = 0x0002, + AGI_SOUND_4CHN = 0x0008 +}; +enum AgiSoundFlags { + AGI_SOUND_LOOP = 0x0001, + AGI_SOUND_ENVELOPE = 0x0002 +}; +enum AgiSoundEnv { + AGI_SOUND_ENV_ATTACK = 3, + AGI_SOUND_ENV_DECAY = 2, + AGI_SOUND_ENV_SUSTAIN = 1, + AGI_SOUND_ENV_RELEASE = 0 +}; + + /** * AGI engine sound channel structure. */ @@ -485,6 +501,7 @@ public: void stopNote(int i); void playNote(int i, int freq, int vol); void playAgiSound(); + void playCoCoSound(); uint32 mixSound(); bool loadInstruments(); void playMidiSound(); diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 3be552a083..36399a7b2f 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -367,12 +367,7 @@ bool MoviePlayerDXA::processFrame() { copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth); _vm->_system->unlockScreen(); - if ((_bgSoundStream == NULL) || ((int)(_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 < getCurFrame() + 1) || - _frameSkipped > getFrameRate()) { - if (_frameSkipped > getFrameRate()) { - warning("force frame %i redraw", getCurFrame()); - _frameSkipped = 0; - } + if ((_bgSoundStream == NULL) || ((int)(_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 < getCurFrame() + 1)) { if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) { while (_mixer->isSoundHandleActive(_bgSound) && (_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 < (uint32)getCurFrame()) { @@ -392,7 +387,6 @@ bool MoviePlayerDXA::processFrame() { } warning("dropped frame %i", getCurFrame()); - _frameSkipped++; return false; } diff --git a/engines/agos/animation.h b/engines/agos/animation.h index 9cd6913f08..4ebcb3d4b3 100644 --- a/engines/agos/animation.h +++ b/engines/agos/animation.h @@ -52,7 +52,6 @@ class MoviePlayer { bool _rightButtonDown; bool _skipMovie; uint32 _ticks; - uint16 _frameSkipped; char baseName[40]; public: diff --git a/engines/agos/charset-fontdata.cpp b/engines/agos/charset-fontdata.cpp index 910c5cd5a6..d23e772306 100644 --- a/engines/agos/charset-fontdata.cpp +++ b/engines/agos/charset-fontdata.cpp @@ -2105,9 +2105,9 @@ void AGOSEngine::windowDrawChar(WindowBlock *window, uint x, uint y, byte chr) { w = getFeebleFontSize(chr); if (_language == Common::PL_POL) - src = feeble_windowFont + (chr - 32) * 13; - else src = polish_feeble_windowFont + (chr - 32) * 13; + else + src = feeble_windowFont + (chr - 32) * 13; } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { dst = (byte *)screen->pixels + y * _dxSurfacePitch + x + window->textColumnOffset; h = 8; diff --git a/engines/cine/bg.cpp b/engines/cine/bg.cpp index cc7e843c2b..08722c42e5 100644 --- a/engines/cine/bg.cpp +++ b/engines/cine/bg.cpp @@ -82,7 +82,6 @@ byte loadCtOS(const char *ctName) { ptr += 2; if (bpp == 8) { - memcpy(collisionPage, ptr + 256 * 3, 320 * 200); renderer->loadCt256(ptr, ctName); } else { gfxConvertSpriteToRaw(collisionPage, ptr + 32, 160, 200); diff --git a/engines/cine/cine.h b/engines/cine/cine.h index bf56e9189b..1031d6d449 100644 --- a/engines/cine/cine.h +++ b/engines/cine/cine.h @@ -127,11 +127,15 @@ extern CineEngine *g_cine; #define COPY_PROT_FAIL_PRC_NAME "L201.ANI" enum { - VAR_MOUSE_X_MODE = 253, + // Both FW and OS VAR_MOUSE_X_POS = 249, - VAR_MOUSE_Y_MODE = 251, VAR_MOUSE_Y_POS = 250, + // FW only + VAR_MOUSE_X_MODE = 253, + VAR_MOUSE_Y_MODE = 251, // OS only + VAR_MOUSE_X_POS_2ND = 251, // Many times used in conjunction with VAR_MOUSE_X_POS + VAR_MOUSE_Y_POS_2ND = 252, // Many times used in conjunction with VAR_MOUSE_Y_POS VAR_BYPASS_PROTECTION = 255, VAR_LOW_MEMORY = 0 }; diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index d388a9e206..ddc2d48152 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -90,9 +90,9 @@ static const byte cursorPalette[] = { /*! \brief Initialize renderer */ -FWRenderer::FWRenderer() : _background(NULL), _palette(NULL), _cmd(""), +FWRenderer::FWRenderer() : _background(NULL), _backupPal(), _cmd(""), _cmdY(0), _messageBg(0), _backBuffer(new byte[_screenSize]), - _activeLowPal(NULL), _changePal(0), _showCollisionPage(false) { + _activePal(), _changePal(0), _showCollisionPage(false) { assert(_backBuffer); @@ -104,21 +104,17 @@ FWRenderer::FWRenderer() : _background(NULL), _palette(NULL), _cmd(""), */ FWRenderer::~FWRenderer() { delete[] _background; - delete[] _palette; delete[] _backBuffer; - delete[] _activeLowPal; } /* \brief Reset renderer state */ void FWRenderer::clear() { delete[] _background; - delete[] _palette; - delete[] _activeLowPal; _background = NULL; - _palette = NULL; - _activeLowPal = NULL; + _backupPal.clear(); + _activePal.clear(); memset(_backBuffer, 0, _screenSize); @@ -550,59 +546,39 @@ void FWRenderer::setCommand(Common::String cmd) { /*! \brief Refresh current palette */ void FWRenderer::refreshPalette() { - int i; - byte pal[16*4]; - - assert(_activeLowPal); - - for (i = 0; i < 16; i++) { - pal[i * 4 + 2] = ((_activeLowPal[i] & 0x007) >> 0) * 32; - pal[i * 4 + 1] = ((_activeLowPal[i] & 0x070) >> 4) * 32; - pal[i * 4 + 0] = ((_activeLowPal[i] & 0x700) >> 8) * 32; - pal[i * 4 + 3] = 0; - } - - g_system->setPalette(pal, 0, 16); + assert(_activePal.isValid() && !_activePal.empty()); + _activePal.setGlobalOSystemPalette(); _changePal = 0; } /*! \brief Load palette of current background */ void FWRenderer::reloadPalette() { - assert(_palette); - - if (!_activeLowPal) { - _activeLowPal = new uint16[_lowPalSize]; - } - - assert(_activeLowPal); - - memcpy(_activeLowPal, _palette, _lowPalSize * sizeof (uint16)); + assert(_backupPal.isValid() && !_backupPal.empty()); + _activePal = _backupPal; _changePal = 1; } /*! \brief Load background into renderer * \param bg Raw background data + * \todo Combine with OSRenderer's version of loadBg16 */ void FWRenderer::loadBg16(const byte *bg, const char *name, unsigned int idx) { assert(idx == 0); - int i; if (!_background) { _background = new byte[_screenSize]; } - if (!_palette) { - _palette = new uint16[_lowPalSize]; - } - - assert(_background && _palette); + assert(_background); strcpy(_bgName, name); - for (i = 0; i < _lowPalSize; i++, bg += 2) { - _palette[i] = READ_BE_UINT16(bg); - } + // Load the 16 color palette + _backupPal.load(bg, kLowPalNumBytes, kLowPalFormat, kLowPalNumColors, CINE_BIG_ENDIAN); + + // Jump over the palette data to the background data + bg += kLowPalNumBytes; gfxConvertSpriteToRaw(_background, bg, 160, 200); } @@ -668,25 +644,15 @@ const char *FWRenderer::getBgName(uint idx) const { * \param fHandle Savefile open for reading */ void FWRenderer::restorePalette(Common::SeekableReadStream &fHandle) { - int i; - - if (!_palette) { - _palette = new uint16[_lowPalSize]; - } - - if (!_activeLowPal) { - _activeLowPal = new uint16[_lowPalSize]; - } - - assert(_palette && _activeLowPal); + byte buf[kLowPalNumBytes]; - for (i = 0; i < _lowPalSize; i++) { - _activeLowPal[i] = fHandle.readUint16BE(); - } + // Load the active 16 color palette from file + fHandle.read(buf, kLowPalNumBytes); + _activePal.load(buf, sizeof(buf), kLowPalFormat, kLowPalNumColors, CINE_BIG_ENDIAN); - for (i = 0; i < _lowPalSize; i++) { - _palette[i] = fHandle.readUint16BE(); - } + // Load the backup 16 color palette from file + fHandle.read(buf, kLowPalNumBytes); + _backupPal.load(buf, sizeof(buf), kLowPalFormat, kLowPalNumColors, CINE_BIG_ENDIAN); _changePal = 1; } @@ -695,58 +661,59 @@ void FWRenderer::restorePalette(Common::SeekableReadStream &fHandle) { * \param fHandle Savefile open for writing */ void FWRenderer::savePalette(Common::OutSaveFile &fHandle) { - int i; + byte buf[kLowPalNumBytes]; - assert(_palette && _activeLowPal); + // Make sure the active palette has the correct format and color count + assert(_activePal.colorFormat() == kLowPalFormat); + assert(_activePal.colorCount() == kLowPalNumColors); - for (i = 0; i < _lowPalSize; i++) { - fHandle.writeUint16BE(_activeLowPal[i]); - } + // Make sure the backup palette has the correct format and color count + assert(_backupPal.colorFormat() == kLowPalFormat); + assert(_backupPal.colorCount() == kLowPalNumColors); - for (i = 0; i < _lowPalSize; i++) { - fHandle.writeUint16BE(_palette[i]); - } + // Write the active palette to the file + _activePal.save(buf, sizeof(buf), CINE_BIG_ENDIAN); + fHandle.write(buf, kLowPalNumBytes); + + // Write the backup palette to the file + _backupPal.save(buf, sizeof(buf), CINE_BIG_ENDIAN); + fHandle.write(buf, kLowPalNumBytes); } /*! \brief Write active and backup palette to save * \param fHandle Savefile open for writing + * \todo Add support for saving the palette in the 16 color version of Operation Stealth. + * Possibly combine with FWRenderer's savePalette-method? */ void OSRenderer::savePalette(Common::OutSaveFile &fHandle) { - int i; + byte buf[kHighPalNumBytes]; - assert(_activeHiPal); + // Make sure the active palette has the correct format and color count + assert(_activePal.colorFormat() == kHighPalFormat); + assert(_activePal.colorCount() == kHighPalNumColors); // Write the active 256 color palette. - for (i = 0; i < _hiPalSize; i++) { - fHandle.writeByte(_activeHiPal[i]); - } + _activePal.save(buf, sizeof(buf), CINE_LITTLE_ENDIAN); + fHandle.write(buf, kHighPalNumBytes); // Write the active 256 color palette a second time. // FIXME: The backup 256 color palette should be saved here instead of the active one. - for (i = 0; i < _hiPalSize; i++) { - fHandle.writeByte(_activeHiPal[i]); - } + fHandle.write(buf, kHighPalNumBytes); } /*! \brief Restore active and backup palette from save * \param fHandle Savefile open for reading */ void OSRenderer::restorePalette(Common::SeekableReadStream &fHandle) { - int i; - - if (!_activeHiPal) { - _activeHiPal = new byte[_hiPalSize]; - } + byte buf[kHighPalNumBytes]; - assert(_activeHiPal); - - for (i = 0; i < _hiPalSize; i++) { - _activeHiPal[i] = fHandle.readByte(); - } + // Load the active 256 color palette from file + fHandle.read(buf, kHighPalNumBytes); + _activePal.load(buf, sizeof(buf), kHighPalFormat, kHighPalNumColors, CINE_LITTLE_ENDIAN); // Jump over the backup 256 color palette. // FIXME: Load the backup 256 color palette and use it properly. - fHandle.seek(_hiPalSize, SEEK_CUR); + fHandle.seek(kHighPalNumBytes, SEEK_CUR); _changePal = 1; } @@ -754,10 +721,10 @@ void OSRenderer::restorePalette(Common::SeekableReadStream &fHandle) { /*! \brief Rotate active palette * \param a First color to rotate * \param b Last color to rotate - * \param c Possibly rotation step, must be equal to 1 at the moment + * \param c Possibly rotation step, must be 0 or 1 at the moment */ void FWRenderer::rotatePalette(int a, int b, int c) { - palRotate(_activeLowPal, a, b, c); + _activePal.rotateRight(a, b, c); refreshPalette(); } @@ -769,12 +736,11 @@ void FWRenderer::rotatePalette(int a, int b, int c) { * \param b Blue channel transformation */ void FWRenderer::transformPalette(int first, int last, int r, int g, int b) { - if (!_activeLowPal) { - _activeLowPal = new uint16[_lowPalSize]; - memset(_activeLowPal, 0, _lowPalSize * sizeof (uint16)); + if (!_activePal.isValid() || _activePal.empty()) { + _activePal = Cine::Palette(kLowPalFormat, kLowPalNumColors); } - transformPaletteRange(_activeLowPal, _palette, first, last, r, g, b); + _backupPal.saturatedAddColor(_activePal, first, last, r, g, b); refreshPalette(); } @@ -889,22 +855,16 @@ void FWRenderer::drawInputBox(const char *info, const char *input, int cursor, i } /*! \brief Fade to black + * \bug Operation Stealth sometimes seems to fade to black using + * transformPalette resulting in double fadeout */ void FWRenderer::fadeToBlack() { - // FIXME: _activeLowPal is invalid when starting Operation Stealth - // Adding this sanity check fixes a crash when the game - // starts, but I'm not sure if this is the best place to check it - if (!_activeLowPal) { - warning("_activeLowPal is invalid"); - return; - } - - assert(_activeLowPal); + assert(_activePal.isValid() && !_activePal.empty()); for (int i = 0; i < 8; i++) { - for (int j = 0; j < 16; j++) { - _activeLowPal[j] = transformColor(_activeLowPal[j], -1, -1, -1); - } + // Fade out the whole palette by 1/7th + // (Operation Stealth used 36 / 252, which is 1 / 7. Future Wars used 1 / 7 directly). + _activePal.saturatedAddNormalizedGray(_activePal, 0, _activePal.colorCount() - 1, -1, 7); refreshPalette(); g_system->updateScreen(); @@ -914,45 +874,25 @@ void FWRenderer::fadeToBlack() { /*! \brief Initialize Operation Stealth renderer */ -OSRenderer::OSRenderer() : _activeHiPal(NULL), _currentBg(0), _scrollBg(0), +OSRenderer::OSRenderer() : FWRenderer(), _bgTable(), _currentBg(0), _scrollBg(0), _bgShift(0) { - int i; - for (i = 0; i < 9; i++) { - _bgTable[i].bg = NULL; - _bgTable[i].lowPal = NULL; - _bgTable[i].hiPal = NULL; - memset(_bgTable[i].name, 0, sizeof (_bgTable[i].name)); - } + _bgTable.resize(9); // Resize the background table to its required size } /*! \brief Destroy Operation Stealth renderer */ OSRenderer::~OSRenderer() { - delete[] _activeHiPal; - - for (int i = 0; i < 9; i++) { - delete[] _bgTable[i].bg; - delete[] _bgTable[i].lowPal; - delete[] _bgTable[i].hiPal; + for (uint i = 0; i < _bgTable.size(); i++) { + _bgTable[i].clear(); } } /*! \brief Reset Operation Stealth renderer state */ void OSRenderer::clear() { - delete[] _activeHiPal; - _activeHiPal = NULL; - - for (int i = 0; i < 9; i++) { - delete[] _bgTable[i].bg; - delete[] _bgTable[i].lowPal; - delete[] _bgTable[i].hiPal; - - _bgTable[i].bg = NULL; - _bgTable[i].lowPal = NULL; - _bgTable[i].hiPal = NULL; - memset(_bgTable[i].name, 0, sizeof (_bgTable[i].name)); + for (uint i = 0; i < _bgTable.size(); i++) { + _bgTable[i].clear(); } _currentBg = 0; @@ -1159,28 +1099,6 @@ void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) { } } -/*! \brief Refresh current palette - */ -void OSRenderer::refreshPalette() { - if (!_activeHiPal) { - FWRenderer::refreshPalette(); - return; - } - - int i; - byte pal[256*4]; - - for (i = 0; i < 256; i++) { - pal[i * 4 + 0] = _activeHiPal[i * 3 + 0]; - pal[i * 4 + 1] = _activeHiPal[i * 3 + 1]; - pal[i * 4 + 2] = _activeHiPal[i * 3 + 2]; - pal[i * 4 + 3] = 0; - } - - g_system->setPalette(pal, 0, 256); - _changePal = 0; -} - /*! \brief Load palette of current background */ void OSRenderer::reloadPalette() { @@ -1188,49 +1106,12 @@ void OSRenderer::reloadPalette() { // and 14, shift background has it right palBg *bg = _bgShift ? &_bgTable[_scrollBg] : &_bgTable[_currentBg]; - assert(bg->lowPal || bg->hiPal); - - if (bg->lowPal) { - if (!_activeLowPal) { - _activeLowPal = new uint16[_lowPalSize]; - } + assert(bg->pal.isValid() && !(bg->pal.empty())); - assert(_activeLowPal); - - delete[] _activeHiPal; - _activeHiPal = NULL; - - memcpy(_activeLowPal, bg->lowPal, _lowPalSize * sizeof (uint16)); - } else { - if (!_activeHiPal) { - _activeHiPal = new byte[_hiPalSize]; - } - - assert(_activeHiPal); - - delete[] _activeLowPal; - _activeLowPal = NULL; - - memcpy(_activeHiPal, bg->hiPal, _hiPalSize); - } + _activePal = bg->pal; _changePal = 1; } -/*! \brief Rotate active palette - * \param a First color to rotate - * \param b Last color to rotate - * \param c Possibly rotation step, must be equal to 1 at the moment - */ -void OSRenderer::rotatePalette(int a, int b, int c) { - if (_activeLowPal) { - FWRenderer::rotatePalette(a, b, c); - return; - } - - palRotate(_activeHiPal, a, b, c); - refreshPalette(); -} - /*! \brief Copy part of backup palette to active palette and transform * \param first First color to transform * \param last Last color to transform @@ -1241,28 +1122,12 @@ void OSRenderer::rotatePalette(int a, int b, int c) { void OSRenderer::transformPalette(int first, int last, int r, int g, int b) { palBg *bg = _bgShift ? &_bgTable[_scrollBg] : &_bgTable[_currentBg]; - if (!bg->lowPal) { - if (!_activeHiPal) { - _activeHiPal = new byte[_hiPalSize]; - memset(_activeHiPal, 0, _hiPalSize); - } - - delete[] _activeLowPal; - _activeLowPal = NULL; - - transformPaletteRange(_activeHiPal, bg->hiPal, first, last, r, g, b); - } else { - if (!_activeLowPal) { - _activeLowPal = new uint16[_lowPalSize]; - memset(_activeLowPal, 0, _lowPalSize * sizeof (uint16)); - } - - delete[] _activeHiPal; - _activeHiPal = NULL; - - transformPaletteRange(_activeLowPal, bg->lowPal, first, last, r, g, b); + // Initialize active palette to current background's palette format and size if they differ + if (_activePal.colorFormat() != bg->pal.colorFormat() || _activePal.colorCount() != bg->pal.colorCount()) { + _activePal = Cine::Palette(bg->pal.colorFormat(), bg->pal.colorCount()); } + bg->pal.saturatedAddColor(_activePal, first, last, r, g, b, kLowPalFormat); refreshPalette(); } @@ -1270,29 +1135,24 @@ void OSRenderer::transformPalette(int first, int last, int r, int g, int b) { * \param bg Raw background data * \param name Background filename * \param pos Background index + * \todo Combine with FWRenderer's version of loadBg16 */ void OSRenderer::loadBg16(const byte *bg, const char *name, unsigned int idx) { - int i; assert(idx < 9); if (!_bgTable[idx].bg) { _bgTable[idx].bg = new byte[_screenSize]; } - if (!_bgTable[idx].lowPal) { - _bgTable[idx].lowPal = new uint16[_lowPalSize]; - } - - assert(_bgTable[idx].bg && _bgTable[idx].lowPal); - - delete[] _bgTable[idx].hiPal; - _bgTable[idx].hiPal = NULL; + assert(_bgTable[idx].bg); strcpy(_bgTable[idx].name, name); - for (i = 0; i < _lowPalSize; i++, bg += 2) { - _bgTable[idx].lowPal[i] = READ_BE_UINT16(bg); - } + // Load the 16 color palette + _bgTable[idx].pal.load(bg, kLowPalNumBytes, kLowPalFormat, kLowPalNumColors, CINE_BIG_ENDIAN); + + // Jump over the palette data to the background data + bg += kLowPalNumBytes; gfxConvertSpriteToRaw(_bgTable[idx].bg, bg, 160, 200); } @@ -1302,7 +1162,10 @@ void OSRenderer::loadBg16(const byte *bg, const char *name, unsigned int idx) { * \param name Background filename */ void OSRenderer::loadCt16(const byte *ct, const char *name) { - loadBg16(ct, name, 8); + // Make the 9th background point directly to the collision page + // and load the picture into it. + _bgTable[kCollisionPageBgIdxAlias].bg = collisionPage; + loadBg16(ct, name, kCollisionPageBgIdxAlias); } /*! \brief Load 256 color background into renderer @@ -1317,18 +1180,11 @@ void OSRenderer::loadBg256(const byte *bg, const char *name, unsigned int idx) { _bgTable[idx].bg = new byte[_screenSize]; } - if (!_bgTable[idx].hiPal) { - _bgTable[idx].hiPal = new byte[_hiPalSize]; - } - - assert(_bgTable[idx].bg && _bgTable[idx].hiPal); - - delete[] _bgTable[idx].lowPal; - _bgTable[idx].lowPal = NULL; + assert(_bgTable[idx].bg); strcpy(_bgTable[idx].name, name); - memcpy(_bgTable[idx].hiPal, bg, _hiPalSize); - memcpy(_bgTable[idx].bg, bg + _hiPalSize, _screenSize); + _bgTable[idx].pal.load(bg, kHighPalNumBytes, kHighPalFormat, kHighPalNumColors, CINE_LITTLE_ENDIAN); + memcpy(_bgTable[idx].bg, bg + kHighPalNumBytes, _screenSize); } /*! \brief Load 256 color CT data as background into renderer @@ -1336,7 +1192,10 @@ void OSRenderer::loadBg256(const byte *bg, const char *name, unsigned int idx) { * \param name Background filename */ void OSRenderer::loadCt256(const byte *ct, const char *name) { - loadBg256(ct, name, 8); + // Make the 9th background point directly to the collision page + // and load the picture into it. + _bgTable[kCollisionPageBgIdxAlias].bg = collisionPage; + loadBg256(ct, name, kCollisionPageBgIdxAlias); } /*! \brief Select active background and load its palette @@ -1344,7 +1203,7 @@ void OSRenderer::loadCt256(const byte *ct, const char *name) { */ void OSRenderer::selectBg(unsigned int idx) { assert(idx < 9 && _bgTable[idx].bg); - assert(_bgTable[idx].lowPal || _bgTable[idx].hiPal); + assert(_bgTable[idx].pal.isValid() && !(_bgTable[idx].pal.empty())); _currentBg = idx; reloadPalette(); @@ -1392,13 +1251,7 @@ void OSRenderer::removeBg(unsigned int idx) { _scrollBg = 0; } - delete[] _bgTable[idx].bg; - delete[] _bgTable[idx].lowPal; - delete[] _bgTable[idx].hiPal; - _bgTable[idx].bg = NULL; - _bgTable[idx].lowPal = NULL; - _bgTable[idx].hiPal = NULL; - memset(_bgTable[idx].name, 0, sizeof (_bgTable[idx].name)); + _bgTable[idx].clear(); } void OSRenderer::saveBgNames(Common::OutSaveFile &fHandle) { @@ -1412,27 +1265,6 @@ const char *OSRenderer::getBgName(uint idx) const { return _bgTable[idx].name; } -/*! \brief Fade to black - * \bug Operation Stealth sometimes seems to fade to black using - * transformPalette resulting in double fadeout - */ -void OSRenderer::fadeToBlack() { - if (!_activeHiPal) { - FWRenderer::fadeToBlack(); - return; - } - - for (int i = 0; i < 8; i++) { - for (int j = 0; j < _hiPalSize; j++) { - _activeHiPal[j] = CLIP(_activeHiPal[j] - 32, 0, 255); - } - - refreshPalette(); - g_system->updateScreen(); - g_system->delayMillis(50); - } -} - void setMouseCursor(int cursor) { static int currentMouseCursor = -1; assert(cursor >= 0 && cursor < 3); diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index 0ed1626ab0..f1503a4c46 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -31,13 +31,34 @@ namespace Cine { +extern byte *collisionPage; +static const int kCollisionPageBgIdxAlias = 8; + /*! \brief Background with palette */ struct palBg { byte *bg; ///< Background data - byte *hiPal; ///< 256 color palette - uint16 *lowPal; ///< 16 color palette + Cine::Palette pal; ///< Background color palette char name[15]; ///< Background filename + + /** @brief Default constructor. */ + palBg() : bg(NULL), pal(), name() { + // Make sure the name is empty (Maybe this is not needed?) + memset(this->name, 0, sizeof(this->name)); + } + + /** @brief Clears the struct (Releases allocated memory etc). */ + void clear() { + // In Operation Stealth the 9th background is sometimes aliased to + // the collision page so we should take care not to double delete it + // (The collision page is deleted elsewhere). + if (this->bg != collisionPage) { + delete[] this->bg; + } + this->bg = NULL; + this->pal.clear(); + memset(this->name, 0, sizeof(this->name)); + } }; /*! \brief Future Wars renderer @@ -46,10 +67,10 @@ struct palBg { * without calling drawFrame() all the time */ class FWRenderer : public Common::NonCopyable { +protected: private: byte *_background; ///< Current background char _bgName[13]; ///< Background filename - uint16 *_palette; ///< 16 color backup palette Common::String _cmd; ///< Player command string @@ -57,10 +78,10 @@ protected: static const int _screenSize = 320 * 200; ///< Screen size static const int _screenWidth = 320; ///< Screen width static const int _screenHeight = 200; ///< Screen height - static const int _lowPalSize = 16; ///< 16 color palette size byte *_backBuffer; ///< Screen backbuffer - uint16 *_activeLowPal; ///< Active 16 color palette + Cine::Palette _backupPal; ///< The backup color palette + Cine::Palette _activePal; ///< The active color palette int _changePal; ///< Load active palette to video backend on next frame bool _showCollisionPage; ///< Should we show the collision page instead of the back buffer? Used for debugging. @@ -130,15 +151,12 @@ public: */ class OSRenderer : public FWRenderer { private: - // FIXME: Background table's size is probably 8 instead of 9. Check to make sure and correct if necessary. - palBg _bgTable[9]; ///< Table of backgrounds loaded into renderer - byte *_activeHiPal; ///< Active 256 color palette + Common::Array<palBg> _bgTable; ///< Table of backgrounds loaded into renderer (Maximum is 9) unsigned int _currentBg; ///< Current background unsigned int _scrollBg; ///< Current scroll background unsigned int _bgShift; ///< Background shift protected: - static const int _hiPalSize = 256 * 3; ///< 256 color palette size void drawSprite(const objectStruct &obj); int drawChar(char character, int x, int y); @@ -169,19 +187,15 @@ public: void saveBgNames(Common::OutSaveFile &fHandle); const char *getBgName(uint idx = 0) const; - void refreshPalette(); void reloadPalette(); void restorePalette(Common::SeekableReadStream &fHandle); void savePalette(Common::OutSaveFile &fHandle); - void rotatePalette(int a, int b, int c); void transformPalette(int first, int last, int r, int g, int b); - void fadeToBlack(); }; void gfxDrawSprite(byte *src4, uint16 sw, uint16 sh, byte *dst4, int16 sx, int16 sy); -extern byte *collisionPage; extern FWRenderer *renderer; void setMouseCursor(int cursor); diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index c6bca84e46..44e4e43a6c 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -288,6 +288,8 @@ void CineEngine::mainLoop(int bootScriptIdx) { globalVars[VAR_MOUSE_X_POS] = 0; globalVars[VAR_MOUSE_Y_POS] = 0; if (g_cine->getGameType() == Cine::GType_OS) { + globalVars[VAR_MOUSE_X_POS_2ND] = 0; + globalVars[VAR_MOUSE_Y_POS_2ND] = 0; globalVars[VAR_BYPASS_PROTECTION] = 0; // set to 1 to bypass the copy protection globalVars[VAR_LOW_MEMORY] = 0; // set to 1 to disable some animations, sounds etc. } diff --git a/engines/cine/pal.cpp b/engines/cine/pal.cpp index 49edaef5e4..b3e3629239 100644 --- a/engines/cine/pal.cpp +++ b/engines/cine/pal.cpp @@ -103,65 +103,6 @@ void loadRelatedPalette(const char *fileName) { } } -void palRotate(uint16 *pal, byte a, byte b, byte c) { - assert(pal); - - if (c == 1) { - uint16 currentColor = pal[b]; - - for (int i = b; i > a; i--) { - pal[i] = pal[i - 1]; - } - - pal[a] = currentColor; - } -} - -void palRotate(byte *pal, byte a, byte b, byte c) { - assert(pal); - - if (c == 1) { - byte currentR = pal[3 * b + 0]; - byte currentG = pal[3 * b + 1]; - byte currentB = pal[3 * b + 2]; - - for (int i = b; i > a; i--) { - pal[3 * i + 0] = pal[3 * (i - 1) + 0]; - pal[3 * i + 1] = pal[3 * (i - 1) + 1]; - pal[3 * i + 2] = pal[3 * (i - 1) + 2]; - } - - pal[3 * a + 0] = currentR; - pal[3 * a + 1] = currentG; - pal[3 * a + 2] = currentB; - } -} - -uint16 transformColor(uint16 baseColor, int r, int g, int b) { - int8 oriR = CLIP( (baseColor & 0x007) + b, 0, 7); - int8 oriG = CLIP(((baseColor & 0x070) >> 4) + g, 0, 7); - int8 oriB = CLIP(((baseColor & 0x700) >> 8) + r, 0, 7); - - return oriR | (oriG << 4) | (oriB << 8); -} - -void transformPaletteRange(uint16 *dstPal, uint16 *srcPal, int startColor, int stopColor, int r, int g, int b) { - assert(srcPal && dstPal); - - for (int i = startColor; i <= stopColor; i++) - dstPal[i] = transformColor(srcPal[i], r, g, b); -} - -void transformPaletteRange(byte *dstPal, byte *srcPal, int startColor, int stopColor, int r, int g, int b) { - assert(srcPal && dstPal); - - for (int i = startColor; i <= stopColor; i++) { - dstPal[3 * i + 0] = CLIP(srcPal[3 * i + 0] + r * 36, 0, 252); - dstPal[3 * i + 1] = CLIP(srcPal[3 * i + 1] + g * 36, 0, 252); - dstPal[3 * i + 2] = CLIP(srcPal[3 * i + 2] + b * 36, 0, 252); - } -} - /*! \brief Shift byte to the left by given amount (Handles negative shifting amounts too, otherwise this would be trivial). */ byte shiftByteLeft(const byte value, const signed shiftLeft) { if (shiftLeft >= 0) @@ -198,13 +139,17 @@ int bytePos(const int bitPos, const int numBytes, const bool bigEndian) { } // a.k.a. palRotate -Palette &Palette::rotateRight(byte firstIndex, byte lastIndex) { - const Color lastColor = _colors[lastIndex]; +Palette &Palette::rotateRight(byte firstIndex, byte lastIndex, signed rotationAmount) { + assert(rotationAmount == 0 || rotationAmount == 1); + + if (rotationAmount == 1) { + const Color lastColor = _colors[lastIndex]; - for (int i = lastIndex; i > firstIndex; i--) - _colors[i] = _colors[i - 1]; + for (int i = lastIndex; i > firstIndex; i--) + _colors[i] = _colors[i - 1]; - _colors[firstIndex] = lastColor; + _colors[firstIndex] = lastColor; + } return *this; } @@ -277,18 +222,18 @@ Palette &Palette::saturatedAddColor(Palette& output, byte firstIndex, byte lastI Palette &Palette::saturatedAddColor(Palette& output, byte firstIndex, byte lastIndex, signed rSource, signed gSource, signed bSource, const Graphics::PixelFormat &sourceFormat) { // Convert the source color to the internal color format ensuring that no divide by zero will happen - const signed r = _format.rMax() * rSource / MAX<int>(sourceFormat.rMax(), 1); - const signed g = _format.gMax() * gSource / MAX<int>(sourceFormat.gMax(), 1); - const signed b = _format.bMax() * bSource / MAX<int>(sourceFormat.bMax(), 1); + const signed r = ((signed) _format.rMax()) * rSource / MAX<int>(sourceFormat.rMax(), 1); + const signed g = ((signed) _format.gMax()) * gSource / MAX<int>(sourceFormat.gMax(), 1); + const signed b = ((signed) _format.bMax()) * bSource / MAX<int>(sourceFormat.bMax(), 1); return saturatedAddColor(output, firstIndex, lastIndex, r, g, b); } Palette &Palette::saturatedAddNormalizedGray(Palette& output, byte firstIndex, byte lastIndex, int grayDividend, int grayDenominator) { assert(grayDenominator != 0); - const signed r = _format.rMax() * grayDividend / grayDenominator; - const signed g = _format.gMax() * grayDividend / grayDenominator; - const signed b = _format.bMax() * grayDividend / grayDenominator; + const signed r = ((signed) _format.rMax()) * grayDividend / grayDenominator; + const signed g = ((signed) _format.gMax()) * grayDividend / grayDenominator; + const signed b = ((signed) _format.bMax()) * grayDividend / grayDenominator; return saturatedAddColor(output, firstIndex, lastIndex, r, g, b); } diff --git a/engines/cine/pal.h b/engines/cine/pal.h index f59dee53df..4764d5a474 100644 --- a/engines/cine/pal.h +++ b/engines/cine/pal.h @@ -73,16 +73,8 @@ void loadPal(const char *fileName); void loadRelatedPalette(const char *fileName); -void palRotate(uint16 *pal, byte a, byte b, byte c); -void palRotate(byte *pal, byte a, byte b, byte c); -uint16 transformColor(uint16 baseColor, int r, int g, int b); -void transformPaletteRange(uint16 *srcPal, uint16 *dstPal, int startColor, int stopColor, int r, int g, int b); -void transformPaletteRange(byte *srcPal, byte *dstPal, int startColor, int stopColor, int r, int g, int b); - -// This class might be used for handling Cine-engine's palettes in the future. WIP! -// TODO: Document -// TODO: Make use of -// TODO: Test +// A class for handling Cine-engine's palettes. +// TODO: Test a bit more class Palette { public: struct Color { @@ -135,7 +127,10 @@ public: */ byte *save(byte *buf, const uint size, const Graphics::PixelFormat format, const uint numColors, const EndianType endian, const byte firstIndex = 0) const; - Palette &rotateRight(byte firstIndex, byte lastIndex); + /*! \brief Rotate the palette in color range [firstIndex, lastIndex] to the right by the specified rotation amount. + * \param rotationAmount Amount to rotate the sub-palette to the right. Only values 0 and 1 are currently supported! + */ + Palette &rotateRight(byte firstIndex, byte lastIndex, signed rotationAmount = 1); Palette &saturatedAddColor(Palette& output, byte firstIndex, byte lastIndex, signed r, signed g, signed b); /*! \brief Saturated add an RGB color in given color format to current palette's subset and save the modified colors in the given output palette. diff --git a/engines/cine/sound.cpp b/engines/cine/sound.cpp index 164c5a9ca5..65b384ac7d 100644 --- a/engines/cine/sound.cpp +++ b/engines/cine/sound.cpp @@ -507,8 +507,6 @@ void AdlibSoundDriverADL::setChannelFrequency(int channel, int frequency) { } int freq, note, oct; findNote(frequency, ¬e, &oct); - - note += oct * 12; if (ins->amDepth) { note = ins->amDepth; } diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 1ec558c217..7192afcd92 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -1095,8 +1095,8 @@ uint16 executePlayerInput(void) { // This fixes swimming at the bottom of the ocean after // having been thrown into it with the girl. if (g_cine->getGameType() == Cine::GType_OS) { - globalVars[251] = globalVars[VAR_MOUSE_X_POS]; - globalVars[252] = globalVars[VAR_MOUSE_Y_POS]; + globalVars[VAR_MOUSE_X_POS_2ND] = globalVars[VAR_MOUSE_X_POS]; + globalVars[VAR_MOUSE_Y_POS_2ND] = globalVars[VAR_MOUSE_Y_POS]; } return var_5E; @@ -1501,10 +1501,7 @@ void processSeqListElement(SeqListElement &element) { if (xMoveKeyb != kKeybMoveRight) { adder = -adder; } - // FIXME: In Operation Stealth's disassembly global variable 251 is used here - // but it's named as VAR_MOUSE_Y_MODE in ScummVM. Is it correct or a - // left over from Future Wars's reverse engineering? - globalVars[VAR_MOUSE_X_POS] = globalVars[251] = ptr1[4] + x + adder; + globalVars[VAR_MOUSE_X_POS] = globalVars[VAR_MOUSE_X_POS_2ND] = ptr1[4] + x + adder; } if (yMoveKeyb && allowPlayerInput) { @@ -1512,8 +1509,7 @@ void processSeqListElement(SeqListElement &element) { if (yMoveKeyb != kKeybMoveDown) { adder = -adder; } - // TODO: Name currently unnamed global variable 252 - globalVars[VAR_MOUSE_Y_POS] = globalVars[252] = ptr1[5] + y + adder; + globalVars[VAR_MOUSE_Y_POS] = globalVars[VAR_MOUSE_Y_POS_2ND] = ptr1[5] + y + adder; } if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) { diff --git a/engines/cruise/cruise.cpp b/engines/cruise/cruise.cpp index 734f4b95c5..4656704cb8 100644 --- a/engines/cruise/cruise.cpp +++ b/engines/cruise/cruise.cpp @@ -52,26 +52,24 @@ CruiseEngine::CruiseEngine(OSystem * syst, const CRUISEGameDescription *gameDesc _currentVolumeFile = new Common::File(); #endif - Common::addDebugChannel(kCruiseDebugScript, "Script", - "Script debug level"); + Common::addDebugChannel(kCruiseDebugScript, "scripts", "Scripts debug level"); + Common::addDebugChannel(kCruiseDebugSound, "sound", "Sound debug level"); // Setup mixer _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, - ConfMan.getInt("sfx_volume")); + ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, - ConfMan.getInt("music_volume")); + ConfMan.getInt("music_volume")); _vm = this; _debugger = new Debugger(); - _music = new MusicPlayer(); - _sound = new SoundPlayer(); + _sound = new PCSound(_mixer, this); syst->getEventManager()->registerRandomSource(_rnd, "cruise"); } CruiseEngine::~CruiseEngine() { delete _debugger; - delete _music; delete _sound; freeSystem(); @@ -126,9 +124,8 @@ void CruiseEngine::initialize() { readVolCnf(); // Setup mixer - _musicVolume = ConfMan.getInt("music_volume"); - _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); - _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); +// _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); +// _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); _mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); @@ -230,4 +227,8 @@ const char *CruiseEngine::getSavegameFile(int saveGameIdx) { return buffer; } +void CruiseEngine::syncSoundSettings() { + _sound->syncSounds(); +} + } // End of namespace Cruise diff --git a/engines/cruise/cruise.h b/engines/cruise/cruise.h index 2fc69acea0..af098b4997 100644 --- a/engines/cruise/cruise.h +++ b/engines/cruise/cruise.h @@ -57,10 +57,8 @@ private: bool _preLoad; Debugger *_debugger; MidiDriver *_driver; - MusicPlayer *_music; - SoundPlayer *_sound; + PCSound *_sound; bool _mt32, _adlib; - int _musicVolume; Common::StringList _langStrings; CursorType _savedCursor; uint32 lastTick, lastTickDebug; @@ -90,8 +88,7 @@ public: uint32 getFeatures() const; Common::Language getLanguage() const; Common::Platform getPlatform() const; - MusicPlayer &music() { return *_music; } - SoundPlayer &sound() { return *_sound; } + PCSound &sound() { return *_sound; } bool mt32() const { return _mt32; } bool adlib() const { return _adlib; } virtual GUI::Debugger *getDebugger() { return _debugger; } @@ -103,6 +100,7 @@ public: virtual bool canLoadGameStateCurrently(); virtual Common::Error saveGameState(int slot, const char *desc); virtual bool canSaveGameStateCurrently(); + virtual void syncSoundSettings(); const CRUISEGameDescription *_gameDescription; void initAllData(void); @@ -128,7 +126,8 @@ enum { }; enum { - kCruiseDebugScript = 1 << 0 + kCruiseDebugScript = 1 << 0, + kCruiseDebugSound = 1 << 1 }; enum { diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp index 136aa92b81..938e823fe9 100644 --- a/engines/cruise/cruise_main.cpp +++ b/engines/cruise/cruise_main.cpp @@ -81,12 +81,11 @@ int getNumObjectsByClass(int scriptIdx, int param) { return (counter); } -void resetFileEntryRange(int param1, int param2) { +void resetFileEntryRange(int start, int count) { int i; - for (i = param1; i < param2; i++) { - resetFileEntry(i); - } + for (i = 0; i < count; ++i) + resetFileEntry(start + i); } int getProcParam(int overlayIdx, int param2, const char *name) { @@ -294,15 +293,15 @@ int loadFileSub1(uint8 **ptr, const char *name, uint8 *ptr2) { if (!strcmp(buffer, ".SPL")) { removeExtention(name, buffer); - // if (useH32) - { - strcat(buffer, ".H32"); - } - /* else + /* if (useH32) + *{ + * strcat(buffer, ".H32"); + *} + * else * if (useAdlib) - * { - * strcatuint8(buffer,".ADL"); - * } + * { */ + strcat(buffer,".ADL"); + /* } * else * { * strcatuint8(buffer,".HP"); @@ -1739,6 +1738,9 @@ void CruiseEngine::mainLoop(void) { int quitValue2 = 1; int quitValue = 0; + if (ConfMan.hasKey("save_slot")) + loadGameState(ConfMan.getInt("save_slot")); + do { // Handle frame delay uint32 currentTick = g_system->getMillis(); diff --git a/engines/cruise/dataLoader.cpp b/engines/cruise/dataLoader.cpp index d725e1bb89..3cf3957703 100644 --- a/engines/cruise/dataLoader.cpp +++ b/engines/cruise/dataLoader.cpp @@ -257,13 +257,15 @@ int loadFile(const char* name, int idx, int destIdx) { return loadFNTSub(ptr, idx); break; } - case type_UNK: { - break; - } case type_SPL: { + // Sound file + loadSPLSub(ptr, idx); break; } + default: + error("Unknown fileType in loadFile"); } + return -1; } @@ -293,13 +295,15 @@ int loadFileRange(const char *name, int startIdx, int currentEntryIdx, int numId loadFNTSub(ptr, startIdx); break; } - case type_UNK: { - break; - } case type_SPL: { + // Sound file + loadSPLSub(ptr, startIdx); break; } + default: + error("Unknown fileType in loadFileRange"); } + return 0; } @@ -316,6 +320,7 @@ int loadFullBundle(const char *name, int startIdx) { switch (fileType) { case type_SET: { + // Sprite set int i; int numMaxEntriesInSet; @@ -328,15 +333,17 @@ int loadFullBundle(const char *name, int startIdx) { break; } case type_FNT: { + // Font file loadFNTSub(ptr, startIdx); break; } - case type_UNK: { - break; - } case type_SPL: { + // Sound file + loadSPLSub(ptr, startIdx); break; } + default: + error("Unknown fileType in loadFullBundle"); } return 0; @@ -387,6 +394,23 @@ int loadFNTSub(uint8 *ptr, int destIdx) { return 1; } +int loadSPLSub(uint8 *ptr, int destIdx) { + uint8 *destPtr; + int fileIndex; + + if (destIdx == -1) { + fileIndex = createResFileEntry(loadFileVar1, 1, loadFileVar1, 1); + } else { + fileIndex = updateResFileEntry(loadFileVar1, 1, loadFileVar1, destIdx, 1); + } + + destPtr = filesDatabase[fileIndex].subData.ptr; + memcpy(destPtr, ptr, loadFileVar1); + + return 1; +} + + int loadSetEntry(const char *name, uint8 *ptr, int currentEntryIdx, int currentDestEntry) { uint8 *ptr3; int offset; diff --git a/engines/cruise/dataLoader.h b/engines/cruise/dataLoader.h index 2e433acfcb..f6bea29cde 100644 --- a/engines/cruise/dataLoader.h +++ b/engines/cruise/dataLoader.h @@ -29,6 +29,7 @@ namespace Cruise { int loadFNTSub(uint8 *ptr, int destIdx); +int loadSPLSub(uint8 *ptr, int destIdx); int loadSetEntry(const char *name, uint8 *ptr, int currentEntryIdx, int currentDestEntry); int loadFile(const char* name, int idx, int destIdx); int loadData(const char * name, int startIdx); diff --git a/engines/cruise/detection.cpp b/engines/cruise/detection.cpp index a0a8cce970..879fad0210 100644 --- a/engines/cruise/detection.cpp +++ b/engines/cruise/detection.cpp @@ -209,7 +209,8 @@ bool CruiseMetaEngine::hasFeature(MetaEngineFeature f) const { (f == kSupportsListSaves) || (f == kSupportsDeleteSave) || (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail); + (f == kSavesSupportThumbnail) || + (f == kSupportsLoadingDuringStartup); } SaveStateList CruiseMetaEngine::listSaves(const char *target) const { diff --git a/engines/cruise/function.cpp b/engines/cruise/function.cpp index 7789cb6fb1..eab69c6846 100644 --- a/engines/cruise/function.cpp +++ b/engines/cruise/function.cpp @@ -32,6 +32,10 @@ namespace Cruise { +uint32 Period(uint32 hz) { + return ((uint32)(100000000L / ((uint32)hz * 28L))); +} + //#define FUNCTION_DEBUG int16 Op_LoadOverlay(void) { @@ -198,15 +202,15 @@ int16 Op_Random(void) { int16 Op_PlayFX(void) { int volume = popVar(); int speed = popVar(); - int channelNum = popVar(); + /*int channelNum = */popVar(); int sampleNum = popVar(); if ((sampleNum >= 0) && (sampleNum < NUM_FILE_ENTRIES) && (filesDatabase[sampleNum].subData.ptr)) { if (speed == -1) speed = filesDatabase[sampleNum].subData.transparency; - _vm->sound().startSound(channelNum, filesDatabase[sampleNum].subData.ptr, - filesDatabase[sampleNum].width, speed, volume, false); + _vm->sound().playSound(filesDatabase[sampleNum].subData.ptr, + filesDatabase[sampleNum].width, volume); } return (0); @@ -215,15 +219,15 @@ int16 Op_PlayFX(void) { int16 Op_LoopFX(void) { int volume = popVar(); int speed = popVar(); - int channelNum = popVar(); + /*int channelNum = */popVar(); int sampleNum = popVar(); if ((sampleNum >= 0) && (sampleNum < NUM_FILE_ENTRIES) && (filesDatabase[sampleNum].subData.ptr)) { if (speed == -1) speed = filesDatabase[sampleNum].subData.transparency; - _vm->sound().startSound(channelNum, filesDatabase[sampleNum].subData.ptr, - filesDatabase[sampleNum].width, speed, volume, true); + _vm->sound().playSound(filesDatabase[sampleNum].subData.ptr, + filesDatabase[sampleNum].width, volume); } return (0); @@ -246,15 +250,14 @@ int16 Op_StopFX(void) { int16 Op_FreqFX(void) { int volume = popVar(); - int speed = popVar(); + int freq2 = popVar(); int channelNum = popVar(); int sampleNum = popVar(); if ((sampleNum >= 0) && (sampleNum < NUM_FILE_ENTRIES) && (filesDatabase[sampleNum].subData.ptr)) { - if (speed == -1) - speed = filesDatabase[sampleNum].subData.transparency; - - _vm->sound().startNote(channelNum, volume, speed); + int freq = Period(freq2 * 1000); + + _vm->sound().startNote(channelNum, volume, freq); } return (0); @@ -357,10 +360,10 @@ int16 Op_FindSet(void) { } int16 Op_RemoveFrame(void) { - int var1 = popVar(); - int var2 = popVar(); + int count = popVar(); + int start = popVar(); - resetFileEntryRange(var2, var1); + resetFileEntryRange(start, count); return (0); } @@ -563,26 +566,22 @@ int16 Op_LoadFrame(void) { } int16 Op_LoadAbs(void) { - int param1; -// int param2; -// int param3; + int slot; char name[36] = ""; char *ptr; int result = 0; ptr = (char *) popPtr(); + slot = popVar(); - strcpy(name, ptr); - - param1 = popVar(); - - if (param1 >= 0 || param1 < NUM_FILE_ENTRIES) { + if ((slot >= 0) && (slot < NUM_FILE_ENTRIES)) { + strcpy(name, ptr); strToUpper(name); gfxModuleData_gfxWaitVSync(); gfxModuleData_gfxWaitVSync(); - result = loadFullBundle(name, param1); + result = loadFullBundle(name, slot); } changeCursor(CURSOR_NORMAL); @@ -774,8 +773,6 @@ int16 Op_UnfreezeParent(void) { return 0; } -int16 protectionCode = 0; - int16 Op_ProtectionFlag(void) { int16 temp = protectionCode; int16 newVar; @@ -1356,22 +1353,22 @@ int16 Op_LoadSong(void) { strcpy(buffer, ptr); strToUpper(buffer); - _vm->music().loadSong(buffer); + _vm->sound().loadMusic(buffer); changeCursor(CURSOR_NORMAL); return 0; } int16 Op_PlaySong(void) { - if (_vm->music().songLoaded() && !_vm->music().songPlayed()) - _vm->music().startSong(); + if (_vm->sound().songLoaded() && !_vm->sound().songPlayed()) + _vm->sound().playMusic(); return 0; } int16 Op_StopSong(void) { - if (_vm->music().isPlaying()) - _vm->music().stop(); + if (_vm->sound().isPlaying()) + _vm->sound().stopMusic(); return 0; } @@ -1385,12 +1382,12 @@ int16 Op_RestoreSong(void) { int16 Op_SongSize(void) { int size, oldSize; - if (_vm->music().songLoaded()) { - byte *pSize = _vm->music().songData() + 470; - oldSize = *pSize; + if (_vm->sound().songLoaded()) { + oldSize = _vm->sound().numOrders(); + size = popVar(); if ((size >= 1) && (size < 128)) - *pSize = size; + _vm->sound().setNumOrders(size); } else oldSize = 0; @@ -1401,35 +1398,34 @@ int16 Op_SetPattern(void) { int value = popVar(); int offset = popVar(); - if (_vm->music().songLoaded()) { - byte *pData = _vm->music().songData(); - *(pData + 472 + offset) = (byte)value; + if (_vm->sound().songLoaded()) { + _vm->sound().setPattern(offset, value); } return 0; } int16 Op_FadeSong(void) { - _vm->music().fadeSong(); + _vm->sound().fadeSong(); return 0; } int16 Op_FreeSong(void) { - _vm->music().stop(); - _vm->music().removeSong(); + _vm->sound().stopMusic(); + _vm->sound().removeMusic(); return 0; } int16 Op_SongLoop(void) { - bool oldLooping = _vm->music().looping(); - _vm->music().setLoop(popVar() != 0); + bool oldLooping = _vm->sound().musicLooping(); + _vm->sound().musicLoop(popVar() != 0); return oldLooping; } int16 Op_SongPlayed(void) { - return _vm->music().songPlayed(); + return _vm->sound().songPlayed(); } void setVar49Value(int value) { @@ -1634,25 +1630,29 @@ int16 Op_GetNodeY(void) { } int16 Op_SetVolume(void) { - int oldVolume = _vm->music().getVolume() >> 2; + int oldVolume = _vm->sound().getVolume(); int newVolume = popVar(); - // TODO: The game seems to expect the volume will only range from 0 - 63, so for now - // I'm doing a translation of the full range 0 - 255 to the 0 - 63 for this script. - // Need to verify at some point that there's no problem with this if (newVolume > 63) newVolume = 63; if (newVolume >= 0) { int volume = 63 - newVolume; - _vm->music().setVolume(volume << 2); + _vm->sound().setVolume(volume); } return oldVolume >> 2; } int16 Op_SongExist(void) { - char* songName = (char*)popPtr(); + const char *songName = (char*)popPtr(); + + if (songName) { + char name[33]; + strcpy(name, songName); + strToUpper(name); - warning("Unimplemented \"Op_SongExist\": %s", songName); + if (!strcmp(_vm->sound().musicName(), name)) + return 1; + } return 0; } diff --git a/engines/cruise/menu.cpp b/engines/cruise/menu.cpp index 136bd281dc..0e9ab55c82 100644 --- a/engines/cruise/menu.cpp +++ b/engines/cruise/menu.cpp @@ -207,7 +207,7 @@ int playerMenu(int menuX, int menuY) { if (playerMenuEnabled && displayOn) { if (remdo) { - _vm->music().removeSong(); + _vm->sound().stopMusic(); freeStuff2(); } /* @@ -261,6 +261,7 @@ int playerMenu(int menuX, int menuY) { loadSavegameData(0); break; case 6: // restart + _vm->sound().fadeOutMusic(); Op_FadeOut(); memset(globalScreen, 0, 320 * 200); initVars(); diff --git a/engines/cruise/saveload.cpp b/engines/cruise/saveload.cpp index 0084b10cb9..d151950c5e 100644 --- a/engines/cruise/saveload.cpp +++ b/engines/cruise/saveload.cpp @@ -25,6 +25,7 @@ #include "cruise/cruise_main.h" #include "cruise/cruise.h" +#include "cruise/vars.h" #include "common/serializer.h" #include "common/savefile.h" @@ -143,6 +144,7 @@ static void syncBasicInfo(Common::Serializer &s) { s.syncAsSint16LE(flagCt); s.syncAsSint16LE(var41); s.syncAsSint16LE(playerMenuEnabled); + s.syncAsSint16LE(protectionCode); } static void syncBackgroundTable(Common::Serializer &s) { @@ -608,7 +610,7 @@ static void syncCT(Common::Serializer &s) { static void DoSync(Common::Serializer &s) { syncBasicInfo(s); - _vm->music().doSync(s); + _vm->sound().doSync(s); syncPalette(s, newPal); syncPalette(s, workpal); @@ -818,6 +820,7 @@ Common::Error loadSavegameData(int saveGameIdx) { printInfoBlackBox("Loading in progress..."); initVars(); + _vm->sound().stopMusic(); // Skip over the savegame header CruiseSavegameHeader header; @@ -926,8 +929,6 @@ Common::Error loadSavegameData(int saveGameIdx) { currentcellHead = currentcellHead->next; } - //TODO: here, restart music - if (strlen(currentCtpName)) { loadCtFromSave = 1; initCt(currentCtpName); diff --git a/engines/cruise/sound.cpp b/engines/cruise/sound.cpp index fd638e6be5..92c2ac6256 100644 --- a/engines/cruise/sound.cpp +++ b/engines/cruise/sound.cpp @@ -30,199 +30,856 @@ #include "cruise/sound.h" #include "cruise/volume.h" +#include "sound/audiostream.h" +#include "sound/fmopl.h" +#include "sound/mods/soundfx.h" + namespace Cruise { -MusicPlayer::MusicPlayer(): _looping(false), _isPlaying(false), _songPlayed(false) { - _songPointer = NULL; - _masterVolume = 0; +class PCSoundDriver { +public: + typedef void (*UpdateCallback)(void *); + + virtual ~PCSoundDriver() {} + + virtual void setupChannel(int channel, const byte *data, int instrument, int volume) = 0; + virtual void setChannelFrequency(int channel, int frequency) = 0; + virtual void stopChannel(int channel) = 0; + virtual void playSample(const byte *data, int size, int channel, int volume) = 0; + virtual void stopAll() = 0; + virtual const char *getInstrumentExtension() const { return ""; } + virtual void syncSounds(); + + void setUpdateCallback(UpdateCallback upCb, void *ref); + void resetChannel(int channel); + void findNote(int freq, int *note, int *oct) const; + + +protected: + UpdateCallback _upCb; + void *_upRef; + uint8 _musicVolume; + uint8 _sfxVolume; + + static const int _noteTable[]; + static const int _noteTableCount; +}; + +const int PCSoundDriver::_noteTable[] = { + 0xEEE, 0xE17, 0xD4D, 0xC8C, 0xBD9, 0xB2F, 0xA8E, 0x9F7, + 0x967, 0x8E0, 0x861, 0x7E8, 0x777, 0x70B, 0x6A6, 0x647, + 0x5EC, 0x597, 0x547, 0x4FB, 0x4B3, 0x470, 0x430, 0x3F4, + 0x3BB, 0x385, 0x353, 0x323, 0x2F6, 0x2CB, 0x2A3, 0x27D, + 0x259, 0x238, 0x218, 0x1FA, 0x1DD, 0x1C2, 0x1A9, 0x191, + 0x17B, 0x165, 0x151, 0x13E, 0x12C, 0x11C, 0x10C, 0x0FD, + 0x0EE, 0x0E1, 0x0D4, 0x0C8, 0x0BD, 0x0B2, 0x0A8, 0x09F, + 0x096, 0x08E, 0x086, 0x07E, 0x077, 0x070, 0x06A, 0x064, + 0x05E, 0x059, 0x054, 0x04F, 0x04B, 0x047, 0x043, 0x03F, + 0x03B, 0x038, 0x035, 0x032, 0x02F, 0x02C, 0x02A, 0x027, + 0x025, 0x023, 0x021, 0x01F, 0x01D, 0x01C, 0x01A, 0x019, + 0x017, 0x016, 0x015, 0x013, 0x012, 0x011, 0x010, 0x00F +}; + +const int PCSoundDriver::_noteTableCount = ARRAYSIZE(_noteTable); + +struct AdlibRegisterSoundInstrument { + uint8 vibrato; + uint8 attackDecay; + uint8 sustainRelease; + uint8 feedbackStrength; + uint8 keyScaling; + uint8 outputLevel; + uint8 freqMod; +}; + +struct AdlibSoundInstrument { + byte mode; + byte channel; + AdlibRegisterSoundInstrument regMod; + AdlibRegisterSoundInstrument regCar; + byte waveSelectMod; + byte waveSelectCar; + byte amDepth; +}; + +struct VolumeEntry { + int original; + int adjusted; +}; + +class AdlibSoundDriver : public PCSoundDriver, Audio::AudioStream { +public: + AdlibSoundDriver(Audio::Mixer *mixer); + virtual ~AdlibSoundDriver(); + + // PCSoundDriver interface + virtual void setupChannel(int channel, const byte *data, int instrument, int volume); + virtual void stopChannel(int channel); + virtual void stopAll(); + + // AudioStream interface + virtual int readBuffer(int16 *buffer, const int numSamples); + virtual bool isStereo() const { return false; } + virtual bool endOfData() const { return false; } + virtual int getRate() const { return _sampleRate; } + + void initCard(); + void update(int16 *buf, int len); + void setupInstrument(const byte *data, int channel); + void setupInstrument(const AdlibSoundInstrument *ins, int channel); + void loadRegisterInstrument(const byte *data, AdlibRegisterSoundInstrument *reg); + virtual void loadInstrument(const byte *data, AdlibSoundInstrument *asi) = 0; + virtual void syncSounds(); + + void adjustVolume(int channel, int volume); + +protected: + FM_OPL *_opl; + int _sampleRate; + Audio::Mixer *_mixer; + Audio::SoundHandle _soundHandle; + + byte _vibrato; + VolumeEntry _channelsVolumeTable[5]; + AdlibSoundInstrument _instrumentsTable[5]; + + static const int _freqTable[]; + static const int _freqTableCount; + static const int _operatorsTable[]; + static const int _operatorsTableCount; + static const int _voiceOperatorsTable[]; + static const int _voiceOperatorsTableCount; +}; + +const int AdlibSoundDriver::_freqTable[] = { + 0x157, 0x16C, 0x181, 0x198, 0x1B1, 0x1CB, + 0x1E6, 0x203, 0x222, 0x243, 0x266, 0x28A +}; + +const int AdlibSoundDriver::_freqTableCount = ARRAYSIZE(_freqTable); + +const int AdlibSoundDriver::_operatorsTable[] = { + 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21 +}; + +const int AdlibSoundDriver::_operatorsTableCount = ARRAYSIZE(_operatorsTable); + +const int AdlibSoundDriver::_voiceOperatorsTable[] = { + 0, 3, 1, 4, 2, 5, 6, 9, 7, 10, 8, 11, 12, 15, 16, 16, 14, 14, 17, 17, 13, 13 +}; + +const int AdlibSoundDriver::_voiceOperatorsTableCount = ARRAYSIZE(_voiceOperatorsTable); + +class AdlibSoundDriverADL : public AdlibSoundDriver { +public: + AdlibSoundDriverADL(Audio::Mixer *mixer) : AdlibSoundDriver(mixer) {} + virtual const char *getInstrumentExtension() const { return ".ADL"; } + virtual void loadInstrument(const byte *data, AdlibSoundInstrument *asi); + virtual void setChannelFrequency(int channel, int frequency); + virtual void playSample(const byte *data, int size, int channel, int volume); +}; + +class PCSoundFxPlayer { +private: + enum { + NUM_INSTRUMENTS = 15, + NUM_CHANNELS = 4 + }; + + void update(); + void handleEvents(); + void handlePattern(int channel, const byte *patternData); + + char _musicName[33]; + bool _playing; + bool _songPlayed; + int _currentPos; + int _currentOrder; + int _numOrders; + int _eventsDelay; + bool _looping; + int _fadeOutCounter; + int _updateTicksCounter; + int _instrumentsChannelTable[NUM_CHANNELS]; + byte *_sfxData; + byte *_instrumentsData[NUM_INSTRUMENTS]; + PCSoundDriver *_driver; + +public: + PCSoundFxPlayer(PCSoundDriver *driver); + ~PCSoundFxPlayer(); + + bool load(const char *song); + void play(); + void stop(); + void unload(); + void fadeOut(); + void doSync(Common::Serializer &s); + + static void updateCallback(void *ref); + + bool songLoaded() const { return _sfxData != NULL; } + bool songPlayed() const { return _songPlayed; } + bool playing() const { return _playing; } + uint8 numOrders() const { assert(_sfxData); return _sfxData[470]; } + void setNumOrders(uint8 v) { assert(_sfxData); _sfxData[470] = v; } + void setPattern(int offset, uint8 value) { assert(_sfxData); _sfxData[472 + offset] = value; } + const char *musicName() { return _musicName; } + + // Note: Original game never actually uses looping variable. Songs are hardcoded to loop + bool looping() const { return _looping; } + void setLooping(bool v) { _looping = v; } +}; + +byte *readBundleSoundFile(const char *name) { + // Load the correct file + int fileIdx = findFileInDisks(name); + if (fileIdx < 0) return NULL; + + int unpackedSize = volumePtrToFileDescriptor[fileIdx].extSize + 2; + byte *data = (byte *)malloc(unpackedSize); + assert(data); + + if (volumePtrToFileDescriptor[fileIdx].size + 2 != unpackedSize) { + uint8 *packedBuffer = (uint8 *)mallocAndZero(volumePtrToFileDescriptor[fileIdx].size + 2); + + loadPackedFileToMem(fileIdx, packedBuffer); + + //uint32 realUnpackedSize = READ_BE_UINT32(packedBuffer + volumePtrToFileDescriptor[fileIdx].size - 4); + + delphineUnpack(data, packedBuffer, volumePtrToFileDescriptor[fileIdx].size); + + free(packedBuffer); + } else { + loadPackedFileToMem(fileIdx, data); + } + + return data; } -MusicPlayer::~MusicPlayer() { - stop(); - if (_songPointer != NULL) - free(_songPointer); + +void PCSoundDriver::setUpdateCallback(UpdateCallback upCb, void *ref) { + _upCb = upCb; + _upRef = ref; } -void MusicPlayer::setVolume(int volume) { - _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); +void PCSoundDriver::findNote(int freq, int *note, int *oct) const { + *note = _noteTableCount - 1; + for (int i = 0; i < _noteTableCount; ++i) { + if (_noteTable[i] <= freq) { + *note = i; + break; + } + } - if (_masterVolume == volume) - return; + *oct = *note / 12; + *note %= 12; +} - _masterVolume = volume; +void PCSoundDriver::resetChannel(int channel) { + stopChannel(channel); + stopAll(); } -void MusicPlayer::stop() { - _isPlaying = false; - _songPlayed = songLoaded(); +void PCSoundDriver::syncSounds() { + // Get the new music and sfx volumes + _musicVolume = ConfMan.getBool("music_mute") ? 0 : MIN(255, ConfMan.getInt("music_volume")); + _sfxVolume = ConfMan.getBool("sfx_mute") ? 0 : MIN(255, ConfMan.getInt("sfx_volume")); } -void MusicPlayer::pause() { - setVolume(-1); - _isPlaying = false; +AdlibSoundDriver::AdlibSoundDriver(Audio::Mixer *mixer) + : _mixer(mixer) { + _sampleRate = _mixer->getOutputRate(); + _opl = makeAdlibOPL(_sampleRate); + + for (int i = 0; i < 5; ++i) { + _channelsVolumeTable[i].original = 0; + _channelsVolumeTable[i].adjusted = 0; + } + memset(_instrumentsTable, 0, sizeof(_instrumentsTable)); + initCard(); + _mixer->playInputStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true); + + _musicVolume = ConfMan.getBool("music_mute") ? 0 : MIN(255, ConfMan.getInt("music_volume")); + _sfxVolume = ConfMan.getBool("sfx_mute") ? 0 : MIN(255, ConfMan.getInt("sfx_volume")); } -void MusicPlayer::resume() { - setVolume(_masterVolume); - _isPlaying = true; - _songPlayed = false; +AdlibSoundDriver::~AdlibSoundDriver() { + _mixer->stopHandle(_soundHandle); + OPLDestroy(_opl); } -void MusicPlayer::doSync(Common::Serializer &s) { - // synchronise current music name, if any, state, and position - s.syncBytes((byte *)_musicName, 33); - uint16 v = (uint16)songLoaded(); - s.syncAsSint16LE(v); - s.syncAsSint16LE(_songPlayed); - s.syncAsSint16LE(_looping); +void AdlibSoundDriver::syncSounds() { + PCSoundDriver::syncSounds(); + + // Force all instruments to reload on the next playing point + for (int i = 0; i < 5; ++i) { + adjustVolume(i, _channelsVolumeTable[i].original); + AdlibSoundInstrument *ins = &_instrumentsTable[i]; + setupInstrument(ins, i); + } } -void MusicPlayer::loadSong(const char *name) { - char tempName[20], baseName[20]; - uint8 *sampleData; +void AdlibSoundDriver::adjustVolume(int channel, int volume) { + _channelsVolumeTable[channel].original = volume; - if (songLoaded()) - removeSong(); + if (volume > 80) { + volume = 80; + } else if (volume < 0) { + volume = 0; + } + volume += volume / 4; + if (volume > 127) { + volume = 127; + } - // Load the correct file - int fileIdx = findFileInDisks(name); - if (fileIdx < 0) return; + int volAdjust = (channel == 4) ? _sfxVolume : _musicVolume; + volume = (volume * volAdjust) / 128; - int unpackedSize = volumePtrToFileDescriptor[fileIdx].extSize + 2; - _songPointer = (byte *)malloc(unpackedSize); - assert(_songPointer); + if (volume > 127) + volume = 127; - if (volumePtrToFileDescriptor[fileIdx].size + 2 != unpackedSize) { - uint8 *packedBuffer = (uint8 *)mallocAndZero(volumePtrToFileDescriptor[fileIdx].size + 2); + _channelsVolumeTable[channel].adjusted = volume; +} - loadPackedFileToMem(fileIdx, packedBuffer); +void AdlibSoundDriver::setupChannel(int channel, const byte *data, int instrument, int volume) { + assert(channel < 5); + if (data) { + adjustVolume(channel, volume); + setupInstrument(data, channel); + } +} - uint32 realUnpackedSize = READ_BE_UINT32(packedBuffer + volumePtrToFileDescriptor[fileIdx].size - 4); +void AdlibSoundDriver::stopChannel(int channel) { + assert(channel < 5); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + if (ins->mode != 0 && ins->channel == 6) { + channel = 6; + } + if (ins->mode == 0 || channel == 6) { + OPLWriteReg(_opl, 0xB0 | channel, 0); + } + if (ins->mode != 0) { + _vibrato &= ~(1 << (10 - ins->channel)); + OPLWriteReg(_opl, 0xBD, _vibrato); + } +} - delphineUnpack(_songPointer, packedBuffer, volumePtrToFileDescriptor[fileIdx].size); - _songSize = realUnpackedSize; +void AdlibSoundDriver::stopAll() { + int i; + for (i = 0; i < 18; ++i) { + OPLWriteReg(_opl, 0x40 | _operatorsTable[i], 63); + } + for (i = 0; i < 9; ++i) { + OPLWriteReg(_opl, 0xB0 | i, 0); + } + OPLWriteReg(_opl, 0xBD, 0); +} - free(packedBuffer); - } else { - loadPackedFileToMem(fileIdx, _songPointer); - _songSize = unpackedSize; +int AdlibSoundDriver::readBuffer(int16 *buffer, const int numSamples) { + update(buffer, numSamples); + return numSamples; +} + +void AdlibSoundDriver::initCard() { + _vibrato = 0x20; + OPLWriteReg(_opl, 0xBD, _vibrato); + OPLWriteReg(_opl, 0x08, 0x40); + + static const int oplRegs[] = { 0x40, 0x60, 0x80, 0x20, 0xE0 }; + + for (int i = 0; i < 9; ++i) { + OPLWriteReg(_opl, 0xB0 | i, 0); + } + for (int i = 0; i < 9; ++i) { + OPLWriteReg(_opl, 0xC0 | i, 0); } - strcpy(_musicName, name); + for (int j = 0; j < 5; j++) { + for (int i = 0; i < 18; ++i) { + OPLWriteReg(_opl, oplRegs[j] | _operatorsTable[i], 0); + } + } - // Get the details of the song - // TODO: Figure this out for sure for use in actually playing song - //int size = *(_songPointer + 470); - //int speed = 244 - *(_songPointer + 471); - //int musicSpeed = (speed * 100) / 1060; + OPLWriteReg(_opl, 1, 0x20); + OPLWriteReg(_opl, 1, 0); +} +void AdlibSoundDriver::update(int16 *buf, int len) { + static int samplesLeft = 0; + while (len != 0) { + int count = samplesLeft; + if (count > len) { + count = len; + } + samplesLeft -= count; + len -= count; + YM3812UpdateOne(_opl, buf, count); + if (samplesLeft == 0) { + if (_upCb) { + (*_upCb)(_upRef); + } + samplesLeft = _sampleRate / 50; + } + buf += count; + } +} - // Get the file without the extension - strcpy(baseName, name); - char *p = strchr(baseName, '.'); - if (p) - *p = '\0'; +void AdlibSoundDriver::setupInstrument(const byte *data, int channel) { + assert(channel < 5); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + loadInstrument(data, ins); - // Get the instruments states file - strcpy(tempName, baseName); - strcat(tempName, ".IST"); + setupInstrument(ins, channel); +} + +void AdlibSoundDriver::setupInstrument(const AdlibSoundInstrument *ins, int channel) { + int mod, car, tmp; + const AdlibRegisterSoundInstrument *reg; - fileIdx = findFileInDisks(tempName); - if (fileIdx >= 0) { - // TODO: Figure out instrument state usage - uint8 instrumentState[15]; - loadPackedFileToMem(fileIdx, instrumentState); + if (ins->mode != 0) { + mod = _operatorsTable[_voiceOperatorsTable[2 * ins->channel + 0]]; + car = _operatorsTable[_voiceOperatorsTable[2 * ins->channel + 1]]; + } else { + mod = _operatorsTable[_voiceOperatorsTable[2 * channel + 0]]; + car = _operatorsTable[_voiceOperatorsTable[2 * channel + 1]]; } - for (int instrumentCtr = 0; instrumentCtr < 15; ++instrumentCtr) { - if (_vm->mt32()) { - // Handle loading Roland instrument data - strcpy(tempName, baseName); - strcat(tempName, ".H32"); + if (ins->mode == 0 || ins->channel == 6) { + reg = &ins->regMod; + OPLWriteReg(_opl, 0x20 | mod, reg->vibrato); + if (reg->freqMod) { + tmp = reg->outputLevel & 0x3F; + } else { + tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel].adjusted; + tmp = 63 - (2 * tmp + 127) / (2 * 127); + } + OPLWriteReg(_opl, 0x40 | mod, tmp | (reg->keyScaling << 6)); + OPLWriteReg(_opl, 0x60 | mod, reg->attackDecay); + OPLWriteReg(_opl, 0x80 | mod, reg->sustainRelease); + if (ins->mode != 0) { + OPLWriteReg(_opl, 0xC0 | ins->channel, reg->feedbackStrength); + } else { + OPLWriteReg(_opl, 0xC0 | channel, reg->feedbackStrength); + } + OPLWriteReg(_opl, 0xE0 | mod, ins->waveSelectMod); + } - sampleData = loadInstrument(tempName, instrumentCtr); - if (sampleData) { - int v = *sampleData; - if ((v >= 128) && (v < 192)) - patchMidi(0x80000L + (instrumentCtr * 512), sampleData + 1, 254); + reg = &ins->regCar; + OPLWriteReg(_opl, 0x20 | car, reg->vibrato); + tmp = (63 - (reg->outputLevel & 0x3F)) * _channelsVolumeTable[channel].adjusted; + tmp = 63 - (2 * tmp + 127) / (2 * 127); + OPLWriteReg(_opl, 0x40 | car, tmp | (reg->keyScaling << 6)); + OPLWriteReg(_opl, 0x60 | car, reg->attackDecay); + OPLWriteReg(_opl, 0x80 | car, reg->sustainRelease); + OPLWriteReg(_opl, 0xE0 | car, ins->waveSelectCar); +} - // TODO: Currently I'm freeing the instrument data immediately. The original - // holds onto the sample data, so it may actually still be needed - free(sampleData); - } - } else if (_vm->adlib()) { - // Handle loading Adlib instrument data - strcpy(tempName, baseName); - strcat(tempName, ".ADL"); +void AdlibSoundDriver::loadRegisterInstrument(const byte *data, AdlibRegisterSoundInstrument *reg) { + reg->vibrato = 0; + if (READ_LE_UINT16(data + 18)) { // amplitude vibrato + reg->vibrato |= 0x80; + } + if (READ_LE_UINT16(data + 20)) { // frequency vibrato + reg->vibrato |= 0x40; + } + if (READ_LE_UINT16(data + 10)) { // sustaining sound + reg->vibrato |= 0x20; + } + if (READ_LE_UINT16(data + 22)) { // envelope scaling + reg->vibrato |= 0x10; + } + reg->vibrato |= READ_LE_UINT16(data + 2) & 0xF; // frequency multiplier - fileIdx = findFileInDisks(tempName); - if (fileIdx >= 0) { - sampleData = (byte *)malloc(volumePtrToFileDescriptor[fileIdx].extSize + 2); - assert(sampleData); - loadPackedFileToMem(fileIdx, sampleData); + reg->attackDecay = READ_LE_UINT16(data + 6) << 4; // attack rate + reg->attackDecay |= READ_LE_UINT16(data + 12) & 0xF; // decay rate - // TODO: Make use of sample data + reg->sustainRelease = READ_LE_UINT16(data + 8) << 4; // sustain level + reg->sustainRelease |= READ_LE_UINT16(data + 14) & 0xF; // release rate - free(sampleData); - } + reg->feedbackStrength = READ_LE_UINT16(data + 4) << 1; // feedback + if (READ_LE_UINT16(data + 24) == 0) { // frequency modulation + reg->feedbackStrength |= 1; + } + + reg->keyScaling = READ_LE_UINT16(data); + reg->outputLevel = READ_LE_UINT16(data + 16); + reg->freqMod = READ_LE_UINT16(data + 24); +} + +void AdlibSoundDriverADL::loadInstrument(const byte *data, AdlibSoundInstrument *asi) { + asi->mode = *data++; + asi->channel = *data++; + asi->waveSelectMod = *data++ & 3; + asi->waveSelectCar = *data++ & 3; + asi->amDepth = *data++; + ++data; + loadRegisterInstrument(data, &asi->regMod); data += 26; + loadRegisterInstrument(data, &asi->regCar); data += 26; +} + +void AdlibSoundDriverADL::setChannelFrequency(int channel, int frequency) { + assert(channel < 5); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + if (ins->mode != 0) { + channel = ins->channel; + if (channel == 9) { + channel = 8; + } else if (channel == 10) { + channel = 7; } } + int freq, note, oct; + findNote(frequency, ¬e, &oct); - _songPlayed = false; - _isPlaying = false; + note += oct * 12; + if (ins->amDepth) { + note = ins->amDepth; + } + if (note < 0) { + note = 0; + } + + freq = _freqTable[note % 12]; + OPLWriteReg(_opl, 0xA0 | channel, freq); + freq = ((note / 12) << 2) | ((freq & 0x300) >> 8); + if (ins->mode == 0) { + freq |= 0x20; + } + OPLWriteReg(_opl, 0xB0 | channel, freq); + if (ins->mode != 0) { + _vibrato |= 1 << (10 - channel); + OPLWriteReg(_opl, 0xBD, _vibrato); + } } -void MusicPlayer::startSong() { - if (songLoaded()) { - // Start playing song here +void AdlibSoundDriverADL::playSample(const byte *data, int size, int channel, int volume) { + assert(channel < 5); + adjustVolume(channel, 127); + + setupInstrument(data, channel); + AdlibSoundInstrument *ins = &_instrumentsTable[channel]; + if (ins->mode != 0 && ins->channel == 6) { + OPLWriteReg(_opl, 0xB0 | channel, 0); + } + if (ins->mode != 0) { + _vibrato &= ~(1 << (10 - ins->channel)); + OPLWriteReg(_opl, 0xBD, _vibrato); } + if (ins->mode != 0) { + channel = ins->channel; + if (channel == 9) { + channel = 8; + } else if (channel == 10) { + channel = 7; + } + } + uint16 note = 48; + if (ins->amDepth) { + note = ins->amDepth; + } + int freq = _freqTable[note % 12]; + OPLWriteReg(_opl, 0xA0 | channel, freq); + freq = ((note / 12) << 2) | ((freq & 0x300) >> 8); + if (ins->mode == 0) { + freq |= 0x20; + } + OPLWriteReg(_opl, 0xB0 | channel, freq); + if (ins->mode != 0) { + _vibrato |= 1 << (10 - channel); + OPLWriteReg(_opl, 0xBD, _vibrato); + } +} + +PCSoundFxPlayer::PCSoundFxPlayer(PCSoundDriver *driver) + : _playing(false), _songPlayed(false), _driver(driver) { + memset(_instrumentsData, 0, sizeof(_instrumentsData)); + _sfxData = NULL; + _fadeOutCounter = 0; + _driver->setUpdateCallback(updateCallback, this); } -void MusicPlayer::removeSong() { - if (isPlaying()) +PCSoundFxPlayer::~PCSoundFxPlayer() { + _driver->setUpdateCallback(NULL, NULL); + if (_playing) { stop(); + } +} + +bool PCSoundFxPlayer::load(const char *song) { + debug(9, "PCSoundFxPlayer::load('%s')", song); - if (_songPointer) { - free(_songPointer); - _songPointer = NULL; + /* stop (w/ fade out) the previous song */ + while (_fadeOutCounter != 0 && _fadeOutCounter < 100) { + g_system->delayMillis(50); + } + _fadeOutCounter = 0; + + if (_playing) { + stop(); } + strcpy(_musicName, song); _songPlayed = false; + _looping = false; + _sfxData = readBundleSoundFile(song); + if (!_sfxData) { + warning("Unable to load soundfx module '%s'", song); + return 0; + } + + for (int i = 0; i < NUM_INSTRUMENTS; ++i) { + _instrumentsData[i] = NULL; + + char instrument[64]; + memset(instrument, 0, 64); // Clear the data first + memcpy(instrument, _sfxData + 20 + i * 30, 12); + instrument[63] = '\0'; - strcpy(_musicName, ""); + if (strlen(instrument) != 0) { + char *dot = strrchr(instrument, '.'); + if (dot) { + *dot = '\0'; + } + strcat(instrument, _driver->getInstrumentExtension()); + _instrumentsData[i] = readBundleSoundFile(instrument); + if (!_instrumentsData[i]) { + warning("Unable to load soundfx instrument '%s'", instrument); + } + } + } + return 1; } -void MusicPlayer::fadeSong() { - // TODO: Implement fading properly - stop(); +void PCSoundFxPlayer::play() { + debug(9, "PCSoundFxPlayer::play()"); + if (_sfxData) { + for (int i = 0; i < NUM_CHANNELS; ++i) { + _instrumentsChannelTable[i] = -1; + } + _currentPos = 0; + _currentOrder = 0; + _numOrders = _sfxData[470]; + _eventsDelay = (244 - _sfxData[471]) * 100 / 1060; + _updateTicksCounter = 0; + _playing = true; + } } -void MusicPlayer::patchMidi(uint32 adr, const byte *data, int size) { - // TODO: Handle patching midi +void PCSoundFxPlayer::stop() { + if (_playing || _fadeOutCounter != 0) { + _fadeOutCounter = 0; + _playing = false; + for (int i = 0; i < NUM_CHANNELS; ++i) { + _driver->stopChannel(i); + } + _driver->stopAll(); + unload(); + } } -byte *MusicPlayer::loadInstrument(const char *name, int i) { - // Find the resource - int fileIdx = findFileInDisks(name); - if (fileIdx < 0) { - warning("Instrument '%s' not found", name); - return NULL; +void PCSoundFxPlayer::fadeOut() { + if (_playing) { + _fadeOutCounter = 1; + _playing = false; + } +} + +void PCSoundFxPlayer::updateCallback(void *ref) { + ((PCSoundFxPlayer *)ref)->update(); +} + +void PCSoundFxPlayer::update() { + if (_playing || (_fadeOutCounter != 0 && _fadeOutCounter < 100)) { + ++_updateTicksCounter; + if (_updateTicksCounter > _eventsDelay) { + handleEvents(); + _updateTicksCounter = 0; + } } +} + +void PCSoundFxPlayer::handleEvents() { + const byte *patternData = _sfxData + 600 + 1800; + const byte *orderTable = _sfxData + 472; + uint16 patternNum = orderTable[_currentOrder] * 1024; - int size = volumePtrToFileDescriptor[fileIdx].extSize; + for (int i = 0; i < 4; ++i) { + handlePattern(i, patternData + patternNum + _currentPos); + patternData += 4; + } - // Get the data - byte *tmp = (byte *)malloc(size); - assert(tmp); - loadPackedFileToMem(fileIdx, tmp); + if (_fadeOutCounter != 0 && _fadeOutCounter < 100) { + _fadeOutCounter += 2; + } + if (_fadeOutCounter >= 100) { + stop(); + return; + } - // Create a copy of the resource that's 22 bytes smaller - byte *result = (byte *)malloc(size - 22); - assert(result); - Common::copy(tmp, tmp + size - 22, result); + _currentPos += 16; + if (_currentPos >= 1024) { + _currentPos = 0; + ++_currentOrder; + if (_currentOrder == _numOrders) { + _currentOrder = 0; + } + } + debug(7, "_currentOrder=%d/%d _currentPos=%d", _currentOrder, _numOrders, _currentPos); +} + +void PCSoundFxPlayer::handlePattern(int channel, const byte *patternData) { + int instrument = patternData[2] >> 4; + if (instrument != 0) { + --instrument; + if (_instrumentsChannelTable[channel] != instrument || _fadeOutCounter != 0) { + _instrumentsChannelTable[channel] = instrument; + const int volume = _sfxData[instrument] - _fadeOutCounter; + _driver->setupChannel(channel, _instrumentsData[instrument], instrument, volume); + } + } + int16 freq = (int16)READ_BE_UINT16(patternData); + if (freq > 0) { + _driver->stopChannel(channel); + _driver->setChannelFrequency(channel, freq); + } +} + +void PCSoundFxPlayer::unload() { + for (int i = 0; i < NUM_INSTRUMENTS; ++i) { + free(_instrumentsData[i]); + _instrumentsData[i] = NULL; + } + free(_sfxData); + _sfxData = NULL; + _songPlayed = true; +} + +void PCSoundFxPlayer::doSync(Common::Serializer &s) { + s.syncBytes((byte *)_musicName, 33); + uint16 v = (uint16)songLoaded(); + s.syncAsSint16LE(v); + + if (s.isLoading() && v) { + load(_musicName); + + for (int i = 0; i < NUM_CHANNELS; ++i) { + _instrumentsChannelTable[i] = -1; + } + } + + s.syncAsSint16LE(_songPlayed); + s.syncAsSint16LE(_looping); + s.syncAsSint16LE(_currentPos); + s.syncAsSint16LE(_currentOrder); + s.syncAsSint16LE(_playing); +} + +PCSound::PCSound(Audio::Mixer *mixer, CruiseEngine *vm) { + _vm = vm; + _mixer = mixer; + _soundDriver = new AdlibSoundDriverADL(_mixer); + _player = new PCSoundFxPlayer(_soundDriver); +} + +PCSound::~PCSound() { + delete _player; + delete _soundDriver; +} + +void PCSound::loadMusic(const char *name) { + debugC(5, kCruiseDebugSound, "PCSound::loadMusic('%s')", name); + _player->load(name); +} + +void PCSound::playMusic() { + debugC(5, kCruiseDebugSound, "PCSound::playMusic()"); + _player->play(); +} + +void PCSound::stopMusic() { + debugC(5, kCruiseDebugSound, "PCSound::stopMusic()"); + _player->stop(); +} + +void PCSound::removeMusic() { + debugC(5, kCruiseDebugSound, "PCSound::removeMusic()"); + _player->unload(); +} + +void PCSound::fadeOutMusic() { + debugC(5, kCruiseDebugSound, "PCSound::fadeOutMusic()"); + _player->fadeOut(); +} + +void PCSound::playSound(const uint8 *data, int size, int volume) { + debugC(5, kCruiseDebugSound, "PCSound::playSound() channel %d size %d", 4, size); + _soundDriver->playSample(data, size, 4, volume); +} + +void PCSound::stopSound(int channel) { + debugC(5, kCruiseDebugSound, "PCSound::stopSound() channel %d", channel); + _soundDriver->resetChannel(channel); +} + +void PCSound::stopChannel(int channel) { + debugC(5, kCruiseDebugSound, "PCSound::stopChannel() channel %d", channel); + _soundDriver->stopChannel(channel); +} + +bool PCSound::isPlaying() const { + return _player->playing(); +} + +bool PCSound::songLoaded() const { + return _player->songLoaded(); +} + +bool PCSound::songPlayed() const { + return _player->songPlayed(); +} + +void PCSound::fadeSong() { + _player->fadeOut(); +} + +uint8 PCSound::numOrders() const { + return _player->numOrders(); +} + +void PCSound::setNumOrders(uint8 v) { + _player->setNumOrders(v); +} + +void PCSound::setPattern(int offset, uint8 value) { + _player->setPattern(offset, value); +} + +bool PCSound::musicLooping() const { + return _player->looping(); +} + +void PCSound::musicLoop(bool v) { + _player->setLooping(v); +} + +void PCSound::startNote(int channel, int volume, int freq) { + warning("TODO: startNote"); +// _soundDriver->setVolume(channel, volume); + _soundDriver->setChannelFrequency(channel, freq); +} + +void PCSound::doSync(Common::Serializer &s) { + _player->doSync(s); + s.syncAsSint16LE(_genVolume); +} + +const char *PCSound::musicName() { + return _player->musicName(); +} - free(tmp); - return result; +void PCSound::syncSounds() { + _soundDriver->syncSounds(); } } // End of namespace Cruise diff --git a/engines/cruise/sound.h b/engines/cruise/sound.h index faf3df995d..13a6b2ac5a 100644 --- a/engines/cruise/sound.h +++ b/engines/cruise/sound.h @@ -29,62 +29,55 @@ #include "sound/mididrv.h" #include "sound/midiparser.h" #include "sound/mixer.h" + +#include "common/config-manager.h" #include "common/serializer.h" namespace Cruise { -class MusicPlayer { -private: - byte _channelVolume[16]; - int _fadeVolume; - char _musicName[33]; - - bool _isPlaying; - bool _songPlayed; - bool _looping; - byte _masterVolume; - - byte *_songPointer; - // TODO: lib_SongSize - int _songSize; +class CruiseEngine; +class PCSoundDriver; +class PCSoundFxPlayer; - void patchMidi(uint32 adr, const byte *data, int size); - byte *loadInstrument(const char *name, int i); +class PCSound { +private: + Audio::Mixer *_mixer; + CruiseEngine *_vm; + int _genVolume; +protected: + PCSoundDriver *_soundDriver; + PCSoundFxPlayer *_player; public: - MusicPlayer(); - ~MusicPlayer(); - - void setVolume(int volume); - int getVolume() const { return _masterVolume; } - - void stop(); - void pause(); - void resume(); - - // Common public access methods + PCSound(Audio::Mixer *mixer, CruiseEngine *vm); + virtual ~PCSound(); + + virtual void loadMusic(const char *name); + virtual void playMusic(); + virtual void stopMusic(); + virtual void removeMusic(); + virtual void fadeOutMusic(); + + virtual void playSound(const uint8 *data, int size, int volume); + virtual void stopSound(int channel); + void doSync(Common::Serializer &s); - void loadSong(const char *name); - void startSong(); - void stopSong(); - void removeSong(); + const char *musicName(); + void stopChannel(int channel); + bool isPlaying() const; + bool songLoaded() const; + bool songPlayed() const; void fadeSong(); - - bool songLoaded() const { return _songPointer != NULL; } - bool songPlayed() const { return _songPlayed; } - bool isPlaying() const { return _isPlaying; } - bool looping() const { return _looping; } - byte *songData() { return _songPointer; } - void setPlaying(bool playing) { _isPlaying = playing; } - void setLoop(bool loop) { _looping = loop; } -}; - -class SoundPlayer { -public: - SoundPlayer() {} - - void startSound(int channelNum, const byte *ptr, int size, int speed, int volume, bool loop) {} - void startNote(int channelNum, int speed, int volume) {} - void stopChannel(int channelNum) {} + uint8 numOrders() const; + void setNumOrders(uint8 v); + void setPattern(int offset, uint8 value); + bool musicLooping() const; + void musicLoop(bool v); + void startNote(int channel, int volume, int freq); + void syncSounds(); + + // Note: Volume variable accessed by these methods is never actually used in original game + void setVolume(int volume) { _genVolume = volume; } + uint8 getVolume() const { return _genVolume; } }; } // End of namespace Cruise diff --git a/engines/cruise/vars.cpp b/engines/cruise/vars.cpp index 3ea591ed43..94fd00cbfd 100644 --- a/engines/cruise/vars.cpp +++ b/engines/cruise/vars.cpp @@ -79,6 +79,8 @@ int16 volumeNumberOfEntry; int16 displayOn = 1; +int16 protectionCode = 0; + int16 globalVars[2000]; dataFileEntry filesDatabase[NUM_FILE_ENTRIES]; diff --git a/engines/cruise/vars.h b/engines/cruise/vars.h index 7208a8bea0..4bb94ff691 100644 --- a/engines/cruise/vars.h +++ b/engines/cruise/vars.h @@ -183,6 +183,8 @@ extern int16 volumeNumberOfEntry; extern int16 displayOn; +extern int16 protectionCode; + #define NUM_FILE_ENTRIES 257 extern int16 globalVars[2000]; diff --git a/engines/cruise/volume.cpp b/engines/cruise/volume.cpp index fda3b6bc1f..2b8cce0f05 100644 --- a/engines/cruise/volume.cpp +++ b/engines/cruise/volume.cpp @@ -107,11 +107,8 @@ int getVolumeDataEntry(volumeDataStruct *entry) { changeCursor(CURSOR_DISK); - currentVolumeFile.read(&volumeNumberOfEntry, 2); - currentVolumeFile.read(&volumeSizeOfEntry, 2); - - bigEndianShortToNative(&volumeNumberOfEntry); - bigEndianShortToNative(&volumeSizeOfEntry); + volumeNumberOfEntry = currentVolumeFile.readSint16BE(); + volumeSizeOfEntry = currentVolumeFile.readSint16BE(); volumeNumEntry = volumeNumberOfEntry; @@ -129,16 +126,10 @@ int getVolumeDataEntry(volumeDataStruct *entry) { for (i = 0; i < volumeNumEntry; i++) { currentVolumeFile.read(&volumePtrToFileDescriptor[i].name, 14); - currentVolumeFile.read(&volumePtrToFileDescriptor[i].offset, 4); - currentVolumeFile.read(&volumePtrToFileDescriptor[i].size, 4); - currentVolumeFile.read(&volumePtrToFileDescriptor[i].extSize, 4); - currentVolumeFile.read(&volumePtrToFileDescriptor[i].unk3, 4); - } - - for (i = 0; i < volumeNumEntry; i++) { - bigEndianLongToNative(&volumePtrToFileDescriptor[i].offset); - bigEndianLongToNative(&volumePtrToFileDescriptor[i].size); - bigEndianLongToNative(&volumePtrToFileDescriptor[i].extSize); + volumePtrToFileDescriptor[i].offset = currentVolumeFile.readSint32BE(); + volumePtrToFileDescriptor[i].size = currentVolumeFile.readSint32BE(); + volumePtrToFileDescriptor[i].extSize = currentVolumeFile.readSint32BE(); + volumePtrToFileDescriptor[i].unk3 = currentVolumeFile.readSint32BE(); } strcpy(currentBaseName, entry->ident); @@ -355,29 +346,23 @@ int16 readVolCnf(void) { return (0); } - fileHandle.read(&numOfDisks, 2); - bigEndianShortToNative(&numOfDisks); - - fileHandle.read(&sizeHEntry, 2); - bigEndianShortToNative(&sizeHEntry); // size of one header entry - 20 bytes + numOfDisks = fileHandle.readSint16BE(); + sizeHEntry = fileHandle.readSint16BE(); // size of one header entry - 20 bytes for (i = 0; i < numOfDisks; i++) { // fread(&volumeData[i],20,1,fileHandle); fileHandle.read(&volumeData[i].ident, 10); fileHandle.read(&volumeData[i].ptr, 4); - fileHandle.read(&volumeData[i].diskNumber, 2); - fileHandle.read(&volumeData[i].size, 4); + volumeData[i].diskNumber = fileHandle.readSint16BE(); + volumeData[i].size = fileHandle.readSint32BE(); - bigEndianShortToNative(&volumeData[i].diskNumber); debug(1, "Disk number: %d", volumeData[i].diskNumber); - bigEndianLongToNative(&volumeData[i].size); } for (i = 0; i < numOfDisks; i++) { dataFileName *ptr; - fileHandle.read(&volumeData[i].size, 4); - bigEndianLongToNative(&volumeData[i].size); + volumeData[i].size = fileHandle.readSint32BE(); ptr = (dataFileName *) mallocAndZero(volumeData[i].size); diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index a37586aee6..f59fa80e8d 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -239,7 +239,7 @@ int16 DataIO::getChunk(const char *chunkName) { } dataDesc = _dataFiles[file]; - for (int16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { + for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) continue; @@ -334,7 +334,6 @@ uint32 DataIO::getChunkPos(int16 handle) const { int32 DataIO::getChunkSize(const char *chunkName) { int16 file; - int16 chunk; struct ChunkDesc *dataDesc; int16 slot; int32 realSize; @@ -344,7 +343,7 @@ int32 DataIO::getChunkSize(const char *chunkName) { return -1; dataDesc = _dataFiles[file]; - for (chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { + for (uint16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { if (scumm_stricmp(chunkName, dataDesc->chunkName) != 0) continue; @@ -488,6 +487,16 @@ int16 DataIO::openData(const char *path) { return file_open(path); } +bool DataIO::existData(const char *path) { + int16 handle = openData(path); + + if (handle < 0) + return false; + + closeData(handle); + return true; +} + DataStream *DataIO::openAsStream(int16 handle, bool dispose) { uint32 curPos = getPos(handle); seekData(handle, 0, SEEK_END); @@ -575,6 +584,9 @@ byte *DataIO::getData(const char *path) { } DataStream *DataIO::getDataStream(const char *path) { + if (!path || (path[0] == '\0') || !existData(path)) + return 0; + uint32 size = getDataSize(path); byte *data = getData(path); diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index c67dc89df8..1f55cac90d 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -80,6 +80,7 @@ public: byte *getUnpackedData(const char *name); void closeData(int16 handle); int16 openData(const char *path); + bool existData(const char *path); DataStream *openAsStream(int16 handle, bool dispose = false); int32 getDataSize(const char *name); @@ -92,7 +93,7 @@ public: protected: Common::File _filesHandles[MAX_FILES]; struct ChunkDesc *_dataFiles[MAX_DATA_FILES]; - int16 _numDataChunks[MAX_DATA_FILES]; + uint16 _numDataChunks[MAX_DATA_FILES]; int16 _dataFileHandles[MAX_DATA_FILES]; bool _dataFileItk[MAX_DATA_FILES]; int32 _chunkPos[MAX_SLOT_COUNT * MAX_DATA_FILES]; diff --git a/engines/gob/demos/demoplayer.cpp b/engines/gob/demos/demoplayer.cpp index ede90af333..0229bb7515 100644 --- a/engines/gob/demos/demoplayer.cpp +++ b/engines/gob/demos/demoplayer.cpp @@ -123,7 +123,9 @@ void DemoPlayer::init() { void DemoPlayer::clearScreen() { debugC(1, kDebugDemo, "Clearing the screen"); - _vm->_video->clearScreen(); + _vm->_video->clearSurf(*_vm->_draw->_backSurface); + _vm->_draw->forceBlit(); + _vm->_video->retrace(); } void DemoPlayer::playVideo(const char *fileName) { diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index af64a53b60..9426c01ef2 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -61,13 +61,14 @@ static const PlainGameDescriptor gobGames[] = { {"woodruff", "The Bizarre Adventures of Woodruff and the Schnibble"}, {"dynasty", "The Last Dynasty"}, {"urban", "Urban Runner"}, - {"archi", "Playtoon 1 - Uncle Archibald"}, - {"spirou", "Playtoon 2 - The Case of the Counterfeit Collaborator"}, - {"chato", "Playtoon 3 - The Secret of the Castle"}, - {"manda", "Playtoon 4 - The Mandarine Prince"}, - {"wakan", "Playtoon 5 - The Stone of Wakan"}, - {"playtnck2", "Playtoon Construction Kit 2 - Les chevaliers"}, - {"bambou", "Playtoon Limited Edition - Bambou le sauveur de la jungle"}, + {"playtoons1", "Playtoons 1 - Uncle Archibald"}, + {"playtoons2", "Playtoons 2 - The Case of the Counterfeit Collaborator"}, + {"playtoons3", "Playtoons 3 - The Secret of the Castle"}, + {"playtoons4", "Playtoons 4 - The Mandarine Prince"}, + {"playtoons5", "Playtoons 5 - The Stone of Wakan"}, + {"playtnck1", "Playtoons Construction Kit 1 - Monsters"}, + {"playtnck2", "Playtoons Construction Kit 2 - Knights"}, + {"bambou", "Playtoons Limited Edition - Bambou le sauveur de la jungle"}, {"fascination", "Fascination"}, {"geisha", "Geisha"}, {"adibou4", "Adibou v4"}, @@ -84,6 +85,7 @@ static const ADObsoleteGameID obsoleteGameIDsTable[] = { namespace Gob { using Common::GUIO_NOSPEECH; +using Common::GUIO_NOSUBTITLES; using Common::GUIO_NONE; static const GOBGameDescription gameDescriptions[] = { @@ -95,7 +97,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesEGA, @@ -109,7 +111,7 @@ static const GOBGameDescription gameDescriptions[] = { RU_RUS, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesEGA, @@ -123,7 +125,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesNone, @@ -137,7 +139,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesAdlib, @@ -151,7 +153,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -165,7 +167,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -179,7 +181,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -193,7 +195,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -207,7 +209,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -221,7 +223,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -235,7 +237,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -249,7 +251,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -263,7 +265,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -277,7 +279,63 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob1cd", + "v1.02", + AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), + HU_HUN, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob1cd", + "v1.02", + AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob1cd", + "v1.02", + AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob1cd", + "v1.02", + AD_ENTRY1s("intro.stk", "40d4a53818f4fce3f5997d02c3fafe73", 4049248), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -291,7 +349,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformAmiga, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesNone, @@ -305,7 +363,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesNone, @@ -319,7 +377,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesNone, @@ -333,7 +391,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesNone, @@ -347,7 +405,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesNone, @@ -361,7 +419,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesAdlib, @@ -375,7 +433,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesAdlib, @@ -389,7 +447,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesAdlib, @@ -403,7 +461,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesAdlib, @@ -417,13 +475,13 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesAdlib, 0, 0, 0 }, - { + { // Supplied by Hkz on #scummvm { "gob1", "", @@ -435,7 +493,151 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesAdlib, + 0, 0, 0 + }, + { // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesAdlib, + 0, 0, 0 + }, + { // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesAdlib, + 0, 0, 0 + }, + { // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesAdlib, + 0, 0, 0 + }, + { // Supplied by Hkz on #scummvm + { + "gob1", + "", + { + {"intro.stk", 0, "f5f028ee39c456fa51fa63b606583918", 313472}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob1, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "gob1", + "", + { + {"intro.stk", 0, "e157cb59c6d330ca70d12ab0ef1dd12b", 288972}, + {"musmac1.mid", 0, "4f66903b33df8a20edd4c748809c0b56", 8161}, + {0, 0, 0, 0} + }, + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesAdlib, @@ -453,7 +655,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesAdlib, @@ -467,7 +669,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesNone, @@ -481,7 +683,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesNone, @@ -495,7 +697,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesNone, @@ -509,7 +711,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesNone, @@ -527,7 +729,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -545,7 +747,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -559,7 +761,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -573,7 +775,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -587,7 +789,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -601,7 +803,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -615,7 +817,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -629,7 +831,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -643,7 +845,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -657,7 +859,7 @@ static const GOBGameDescription gameDescriptions[] = { RU_RUS, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -671,7 +873,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -685,7 +887,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesCD, @@ -699,7 +901,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesCD, @@ -713,7 +915,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesCD, @@ -727,7 +929,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesCD, @@ -741,7 +943,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesCD, @@ -755,7 +957,77 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + HU_HUN, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob2, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob2cd", + "v1.02", + AD_ENTRY1s("intro.stk", "5ba85a4769a1ab03a283dd694588d526", 5006236), + IT_ITA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesCD, @@ -769,7 +1041,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -783,7 +1055,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -797,7 +1069,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformAmiga, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesNone, @@ -811,7 +1083,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformAmiga, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesNone, @@ -829,7 +1101,43 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob2, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "gob2", + "", + { + {"intro.stk", 0, "25a99827cd59751a80bed9620fb677a0", 893302}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + EN_USA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob2, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "gob2", + "", + { + {"intro.stk", 0, "25a99827cd59751a80bed9620fb677a0", 893302}, + {"musmac1.mid", 0, "834e55205b710d0af5f14a6f2320dd8e", 8661}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -847,7 +1155,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -865,7 +1173,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesNone, @@ -879,7 +1187,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesNone, @@ -893,7 +1201,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesNone, @@ -907,7 +1215,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesNone, @@ -925,7 +1233,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesNone, @@ -943,7 +1251,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesNone, @@ -957,7 +1265,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesNone, @@ -971,7 +1279,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesAdlib, @@ -985,7 +1293,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesAdlib, @@ -999,7 +1307,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesAdlib, @@ -1013,7 +1321,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesAdlib, @@ -1027,7 +1335,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesAdlib, @@ -1041,7 +1349,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesAdlib, @@ -1055,7 +1363,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesAdlib, @@ -1069,7 +1377,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWeen, kFeaturesAdlib, @@ -1083,7 +1391,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBargon, kFeaturesNone, @@ -1097,7 +1405,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformAtariST, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBargon, kFeaturesNone, @@ -1111,7 +1419,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBargon, kFeaturesNone, @@ -1125,7 +1433,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBargon, kFeaturesNone, @@ -1139,7 +1447,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBargon, kFeaturesNone, @@ -1153,7 +1461,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBargon, kFeaturesNone, @@ -1167,7 +1475,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBargon, kFeaturesNone, @@ -1181,7 +1489,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib | kFeaturesEGA, @@ -1195,7 +1503,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib | kFeaturesEGA, @@ -1209,7 +1517,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib | kFeaturesEGA, @@ -1223,7 +1531,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib | kFeaturesEGA, @@ -1237,7 +1545,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib | kFeaturesEGA, @@ -1255,7 +1563,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesNone, @@ -1269,7 +1577,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -1283,7 +1591,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1297,7 +1605,7 @@ static const GOBGameDescription gameDescriptions[] = { HB_ISR, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1311,7 +1619,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1325,7 +1633,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1339,7 +1647,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1357,7 +1665,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1371,7 +1679,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1385,7 +1693,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1399,7 +1707,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1413,7 +1721,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1427,7 +1735,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1441,7 +1749,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1455,7 +1763,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1469,7 +1777,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1483,7 +1791,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1497,7 +1805,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1511,7 +1819,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1525,7 +1833,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -1536,10 +1844,38 @@ static const GOBGameDescription gameDescriptions[] = { "lostintime", "", AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), - UNK_LANG, + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeLostInTime, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), + FR_FRA, kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeLostInTime, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "0ddf39cea1ec30ecc8bfe444ebd7b845", 4207330), + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1553,7 +1889,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES }, kGameTypeFascination, kFeaturesCD, @@ -1567,7 +1903,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesAdlib, @@ -1581,14 +1917,13 @@ static const GOBGameDescription gameDescriptions[] = { HB_ISR, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesAdlib, "intro.stk", 0, 0 }, - //Provided by Sanguine - { + { // Supplied by sanguine { "fascination", "VGA 3 disks edition", @@ -1596,7 +1931,21 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeFascination, + kFeaturesAdlib, + "disk0.stk", 0, 0 + }, + { // Supplied by windlepoons in bug report #2809247 + { + "fascination", + "VGA 3 disks edition", + AD_ENTRY1s("disk0.stk", "3a24e60a035250189643c86a9ceafb97", 1062480), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesAdlib, @@ -1610,7 +1959,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesAdlib, @@ -1624,7 +1973,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesNone, @@ -1638,7 +1987,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesNone, @@ -1652,7 +2001,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesNone, @@ -1666,7 +2015,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesNone, @@ -1680,7 +2029,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGeisha, kFeaturesNone, @@ -1694,7 +2043,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGeisha, kFeaturesNone, @@ -1708,7 +2057,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1722,7 +2071,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -1736,7 +2085,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1750,7 +2099,7 @@ static const GOBGameDescription gameDescriptions[] = { HB_ISR, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1764,7 +2113,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1782,7 +2131,43 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob3, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "gob3", + "", + { + {"intro.stk", 0, "16b014bf32dbd6ab4c5163c44f56fed1", 445104}, + {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob3, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "gob3", + "", + { + {"intro.stk", 0, "16b014bf32dbd6ab4c5163c44f56fed1", 445104}, + {"musmac1.mid", 0, "948c546cad3a9de5bff3fe4107c82bf1", 6404}, + {0, 0, 0, 0} + }, + EN_GRB, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1800,7 +2185,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1814,7 +2199,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1828,7 +2213,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1842,7 +2227,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1856,7 +2241,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1870,7 +2255,7 @@ static const GOBGameDescription gameDescriptions[] = { RU_RUS, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1884,7 +2269,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1898,7 +2283,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -1912,7 +2297,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesNone, @@ -1926,7 +2311,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformAmiga, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesNone, @@ -1940,7 +2325,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesCD, @@ -1954,7 +2339,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesCD, @@ -1968,7 +2353,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesCD, @@ -1982,7 +2367,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesCD, @@ -1996,7 +2381,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesCD, @@ -2010,7 +2395,63 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob3cd", + "v1.02", + AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), + HU_HUN, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob3cd", + "v1.02", + AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob3cd", + "v1.02", + AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeGob3, + kFeaturesCD, + 0, 0, 0 + }, + { // Supplied by goodoldgeorg in bug report #2810082 + { + "gob3cd", + "v1.02", + AD_ENTRY1s("intro.stk", "bfd7d4c6fedeb2cfcc8baa4d5ddb1f74", 616220), + ES_ESP, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesCD, @@ -2024,7 +2465,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -2038,7 +2479,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -2052,7 +2493,7 @@ static const GOBGameDescription gameDescriptions[] = { UNK_LANG, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -2066,7 +2507,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_DEMO, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -2084,7 +2525,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -2098,7 +2539,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesCD, @@ -2112,7 +2553,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesCD, @@ -2126,7 +2567,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesCD, @@ -2140,7 +2581,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesCD, @@ -2154,7 +2595,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesCD, @@ -2168,7 +2609,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesAdlib, @@ -2182,7 +2623,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesAdlib, @@ -2196,7 +2637,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesAdlib, @@ -2210,7 +2651,63 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformWindows, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeInca2, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + DE_DEU, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeInca2, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + IT_ITA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeInca2, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + ES_ESP, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeInca2, + kFeaturesAdlib, + 0, 0, 0 + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "d33011df8758ac64ca3dca77c7719001", 908612), + FR_FRA, + kPlatformWindows, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesAdlib, @@ -2237,7 +2734,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeInca2, kFeaturesAdlib | kFeaturesBATDemo, @@ -2251,7 +2748,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2265,7 +2762,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2279,7 +2776,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2293,7 +2790,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2307,7 +2804,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2321,7 +2818,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2335,7 +2832,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2349,7 +2846,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2363,7 +2860,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2377,7 +2874,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2391,7 +2888,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2405,7 +2902,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2419,7 +2916,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2433,7 +2930,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2447,7 +2944,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2461,7 +2958,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2475,7 +2972,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2489,7 +2986,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2503,7 +3000,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2517,7 +3014,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_GRB, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2531,7 +3028,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2545,7 +3042,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2559,7 +3056,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2573,7 +3070,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2587,7 +3084,7 @@ static const GOBGameDescription gameDescriptions[] = { PL_POL, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -2605,7 +3102,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640 | kFeaturesSCNDemo, @@ -2619,7 +3116,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeDynasty, kFeatures640, @@ -2633,7 +3130,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeDynasty, kFeatures640, @@ -2647,7 +3144,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeDynasty, kFeatures640, @@ -2661,7 +3158,21 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypeDynasty, + kFeatures640, + 0, 0, 0 + }, + { + { + "dynasty", + "", + AD_ENTRY1s("intro.stk", "bdbdac8919200a5e71ffb9fb0709f704", 2446652), + DE_DEU, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeDynasty, kFeatures640, @@ -2717,7 +3228,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_USA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeUrban, kFeatures640, @@ -2731,7 +3242,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeUrban, kFeatures640, @@ -2745,7 +3256,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeUrban, kFeatures640, @@ -2759,7 +3270,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeUrban, kFeatures640, @@ -2786,7 +3297,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "archi", + "playtoons1", "", { {"playtoon.stk", 0, "8c98e9a11be9bb203a55e8c6e68e519b", 25574338}, @@ -2796,7 +3307,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -2804,8 +3315,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "archi", - "Pack mes histoires animées", + "playtoons1", + "Pack mes histoires anim\xE9""es", { {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, {"archi.stk", 0, "8d44b2a0d4e3139471213f9f0ed21e81", 5524674}, @@ -2814,7 +3325,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -2822,7 +3333,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "archi", + "playtoons1", "", { {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, @@ -2832,7 +3343,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -2840,7 +3351,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "archi", + "playtoons1", "Non-Interactive Demo", { {"play123.scn", 0, "4689a31f543915e488c3bc46ea358add", 258}, @@ -2855,7 +3366,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640 | kFeaturesSCNDemo, @@ -2863,7 +3374,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "archi", + "playtoons1", "Non-Interactive Demo", { {"e.scn", 0, "8a0db733c3f77be86e74e8242e5caa61", 124}, @@ -2873,7 +3384,7 @@ static const GOBGameDescription gameDescriptions[] = { EN_ANY, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640 | kFeaturesSCNDemo, @@ -2881,7 +3392,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "archi", + "playtoons1", "Non-Interactive Demo", { {"i.scn", 0, "8b3294474d39970463663edd22341730", 285}, @@ -2895,7 +3406,7 @@ static const GOBGameDescription gameDescriptions[] = { IT_ITA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640 | kFeaturesSCNDemo, @@ -2903,7 +3414,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "archi", + "playtoons1", "Non-Interactive Demo", { {"s.scn", 0, "1f527010626b5490761f16ba7a6f639a", 251}, @@ -2916,7 +3427,7 @@ static const GOBGameDescription gameDescriptions[] = { ES_ESP, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640 | kFeaturesSCNDemo, @@ -2924,7 +3435,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "spirou", + "playtoons2", "", { {"playtoon.stk", 0, "55a85036dd93cce93532d8f743d90074", 17467154}, @@ -2934,7 +3445,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -2942,7 +3453,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "spirou", + "playtoons2", "", { {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, @@ -2952,7 +3463,7 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -2960,7 +3471,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "chato", + "playtoons3", "", { {"playtoon.stk", 0, "8c98e9a11be9bb203a55e8c6e68e519b", 25574338}, @@ -2970,7 +3481,25 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypePlaytoon, + kFeatures640, + "intro2.stk", 0, 0 + }, + { + { + "playtoons3", + "", + { + {"playtoon.stk", 0, "9e513e993a5b0e2496add3f50c08764b", 30448506}, + {"chato.stk", 0, "8fc8d0da5b3e758908d1d7298d497d0b", 6041026}, + {0, 0, 0, 0} + }, + EN_ANY, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -2978,8 +3507,8 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "chato", - "Pack mes histoires animées", + "playtoons3", + "Pack mes histoires anim\xE9""es", { {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, {"chato.stk", 0, "4fa4ed96a427c344e9f916f9f236598d", 6033793}, @@ -2988,7 +3517,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -2996,7 +3525,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "chato", + "playtoons3", "", { {"playtoon.stk", 0, "c5ca2a288cdaefca9556cd9ae4b579cf", 25158926}, @@ -3006,7 +3535,26 @@ static const GOBGameDescription gameDescriptions[] = { DE_DEU, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypePlaytoon, + kFeatures640, + "intro2.stk", 0, 0 + }, + + { + { + "playtoons4", + "", + { + {"playtoon.stk", 0, "b7f5afa2dc1b0f75970b7c07d175db1b", 24340406}, + {"manda.stk", 0, "92529e0b927191d9898a34c2892e9a3a", 6485072}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -3014,7 +3562,7 @@ static const GOBGameDescription gameDescriptions[] = { }, { { - "wakan", + "playtoons5", "", { {"playtoon.stk", 0, "55f0293202963854192e39474e214f5f", 30448474}, @@ -3024,7 +3572,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -3042,11 +3590,29 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBambou, kFeatures640, - 0, 0, 0 + "intro.stk", "intro.tot", 0 + }, + { + { + "playtnck1", + "", + { + {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024}, + {"dan.itk", 0, "906d67b3e438d5e95ec7ea9e781a94f3", 3000320}, + {0, 0, 0, 0} + }, + FR_FRA, + kPlatformPC, + ADGF_NO_FLAGS, + GUIO_NOSUBTITLES | GUIO_NOSPEECH + }, + kGameTypePlaytnCk, + kFeatures640, + "intro2.stk", 0, 0 }, { { @@ -3054,12 +3620,13 @@ static const GOBGameDescription gameDescriptions[] = { "", { {"playtoon.stk", 0, "5f9aae29265f1f105ad8ec195dff81de", 68382024}, + {"dan.itk", 0, "74eeb075bd2cb47b243349730264af01", 3213312}, {0, 0, 0, 0} }, FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytnCk, kFeatures640, @@ -3073,7 +3640,7 @@ static const GOBGameDescription gameDescriptions[] = { FR_FRA, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NONE }, kGameTypeAdibou4, kFeatures640, @@ -3207,7 +3774,7 @@ static const GOBGameDescription gameDescriptions[] = { { { "adibouunknown", - "ADIBÙ 2 Ambiente", + "ADIB\xD9 2 Ambiente", AD_ENTRY1s("intro.stk", "092707829555f27706920e4cacf1fada", 8737958), IT_ITA, kPlatformPC, @@ -3221,7 +3788,7 @@ static const GOBGameDescription gameDescriptions[] = { { { "adibouunknown", - "ADIBÙ prima elementare : Imparo a leggere e a contare", + "ADIB\xD9 prima elementare : Imparo a leggere e a contare", { {"intro.stk", 0, "092707829555f27706920e4cacf1fada", 8737958}, {"appbou2.itk", 0, "f7bf045f6bdce5a7607c720e36704f33", 200005632}, @@ -3239,7 +3806,7 @@ static const GOBGameDescription gameDescriptions[] = { { { "adibouunknown", - "ADIBOU présente La Magie (STK2.1/OBC)", + "ADIBOU pr\xE9sente La Magie (STK2.1/OBC)", { {"adibou.stk", 0, "977d2449d398f3df23238d718fca35b5", 61097}, {"magic.stk", 0, "9776765dead3e338a32c43bf344b5819", 302664}, @@ -3320,7 +3887,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesNone, @@ -3334,7 +3901,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob1, kFeaturesCD, @@ -3348,7 +3915,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -3362,7 +3929,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesAdlib, @@ -3376,7 +3943,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob2, kFeaturesCD, @@ -3390,7 +3957,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBargon, kFeaturesNone, @@ -3404,7 +3971,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesAdlib, @@ -3418,7 +3985,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGob3, kFeaturesCD, @@ -3432,7 +3999,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeWoodruff, kFeatures640, @@ -3446,7 +4013,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -3460,7 +4027,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformMacintosh, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesAdlib, @@ -3474,7 +4041,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeLostInTime, kFeaturesCD, @@ -3488,7 +4055,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NONE + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeUrban, kFeaturesCD, @@ -3496,13 +4063,13 @@ static const GOBGameDescription fallbackDescs[] = { }, { { - "archi", + "playtoons1", "unknown", AD_ENTRY1(0, 0), UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -3510,13 +4077,13 @@ static const GOBGameDescription fallbackDescs[] = { }, { { - "spirou", + "playtoons2", "unknown", AD_ENTRY1(0, 0), UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -3524,13 +4091,13 @@ static const GOBGameDescription fallbackDescs[] = { }, { { - "chato", + "playtoons3", "unknown", AD_ENTRY1(0, 0), UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -3538,13 +4105,13 @@ static const GOBGameDescription fallbackDescs[] = { }, { { - "manda", + "playtoons4", "unknown", AD_ENTRY1(0, 0), UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -3552,13 +4119,13 @@ static const GOBGameDescription fallbackDescs[] = { }, { { - "wakan", + "playtoons5", "unknown", AD_ENTRY1(0, 0), UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytoon, kFeatures640, @@ -3572,7 +4139,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypePlaytnCk, kFeatures640, @@ -3586,7 +4153,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeBambou, kFeatures640, @@ -3600,7 +4167,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeFascination, kFeaturesNone, @@ -3614,7 +4181,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeGeisha, kFeaturesNone, @@ -3628,7 +4195,7 @@ static const GOBGameDescription fallbackDescs[] = { UNK_LANG, kPlatformPC, ADGF_NO_FLAGS, - GUIO_NOSPEECH + GUIO_NOSUBTITLES | GUIO_NOSPEECH }, kGameTypeAdibou4, kFeatures640, diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index 8619e08e8b..b3e5e7418c 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -30,6 +30,7 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/game.h" +#include "gob/script.h" #include "gob/inter.h" #include "gob/video.h" #include "gob/palanim.h" @@ -389,11 +390,10 @@ void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right, adjustCoords(1, &left, &top); adjustCoords(1, &right, &bottom); - if (READ_LE_UINT16(_vm->_game->_totFileData + 0x7E) != 0) { - byte *storedIP = _vm->_global->_inter_execPtr; + uint16 centerOffset = _vm->_game->_script->getFunctionOffset(TOTFile::kFunctionCenter); + if (centerOffset != 0) { + _vm->_game->_script->call(centerOffset); - _vm->_global->_inter_execPtr = _vm->_game->_totFileData + - READ_LE_UINT16(_vm->_game->_totFileData + 0x7E); WRITE_VAR(17, (uint32) id); WRITE_VAR(18, (uint32) left); WRITE_VAR(19, (uint32) top); @@ -401,7 +401,7 @@ void Draw::printTextCentered(int16 id, int16 left, int16 top, int16 right, WRITE_VAR(21, (uint32) (bottom - top + 1)); _vm->_inter->funcBlock(0); - _vm->_global->_inter_execPtr = storedIP; + _vm->_game->_script->pop(); } if (str[0] == '\0') diff --git a/engines/gob/draw_v1.cpp b/engines/gob/draw_v1.cpp index de71f20142..94ee32a031 100644 --- a/engines/gob/draw_v1.cpp +++ b/engines/gob/draw_v1.cpp @@ -32,6 +32,7 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/game.h" +#include "gob/resources.h" #include "gob/scenery.h" #include "gob/inter.h" #include "gob/sound/sound.h" @@ -173,12 +174,12 @@ void Draw_v1::printTotText(int16 id) { _vm->_sound->cdPlayMultMusic(); - if (!_vm->_game->_totTextData || !_vm->_game->_totTextData->dataPtr) + TextItem *textItem = _vm->_game->_resources->getTextItem(id); + if (!textItem) return; - dataPtr = _vm->_game->_totTextData->dataPtr + - _vm->_game->_totTextData->items[id].offset; - ptr = dataPtr; + dataPtr = textItem->getData(); + ptr = dataPtr; destX = READ_LE_UINT16(ptr) & 0x7FFF; destY = READ_LE_UINT16(ptr + 2); @@ -312,7 +313,9 @@ void Draw_v1::printTotText(int16 id) { } } + delete textItem; _renderFlags = savedFlags; + if (_renderFlags & RENDERFLAG_COLLISIONS) _vm->_game->checkCollisions(0, 0, 0, 0); @@ -323,11 +326,10 @@ void Draw_v1::printTotText(int16 id) { } void Draw_v1::spriteOperation(int16 operation) { - uint16 id; - byte *dataBuf; int16 len; int16 x, y; int16 perLine; + Resource *resource; if (_sourceSurface >= 100) _sourceSurface -= 80; @@ -396,30 +398,20 @@ void Draw_v1::spriteOperation(int16 operation) { break; case DRAW_LOADSPRITE: - id = _spriteLeft; - if (id >= 30000) { - dataBuf = - _vm->_game->loadExtData(id, &_spriteRight, &_spriteBottom); - _vm->_video->drawPackedSprite(dataBuf, - _spriteRight, _spriteBottom, - _destSpriteX, _destSpriteY, - _transparency, *_spritesArray[_destSurface]); - dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, - _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1); - delete[] dataBuf; - break; - } + resource = _vm->_game->_resources->getResource((uint16) _spriteLeft, + &_spriteRight, &_spriteBottom); - if (!(dataBuf = _vm->_game->loadTotResource(id, 0, &_spriteRight, &_spriteBottom))) + if (!resource) break; - _vm->_video->drawPackedSprite(dataBuf, - _spriteRight, _spriteBottom, - _destSpriteX, _destSpriteY, - _transparency, *_spritesArray[_destSurface]); + _vm->_video->drawPackedSprite(resource->getData(), + _spriteRight, _spriteBottom, _destSpriteX, _destSpriteY, + _transparency, *_spritesArray[_destSurface]); dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1); + + delete resource; break; case DRAW_PRINTTEXT: diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index 4bb8120e3a..2843456f42 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -32,6 +32,8 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/game.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/scenery.h" #include "gob/inter.h" #include "gob/video.h" @@ -205,12 +207,6 @@ void Draw_v2::printTotText(int16 id) { id &= 0xFFF; - if (!_vm->_game->_totTextData || !_vm->_game->_totTextData->dataPtr || - (id >= _vm->_game->_totTextData->itemsCount) || - (_vm->_game->_totTextData->items[id].offset == -1) || - (_vm->_game->_totTextData->items[id].size == 0)) - return; - _vm->validateLanguage(); // WORKAROUND: In the scripts of some Gobliins 2 versions, the dialog text IDs @@ -234,13 +230,18 @@ void Draw_v2::printTotText(int16 id) { } - size = _vm->_game->_totTextData->items[id].size; - dataPtr = _vm->_game->_totTextData->dataPtr + - _vm->_game->_totTextData->items[id].offset; - ptr = dataPtr; + TextItem *textItem = _vm->_game->_resources->getTextItem(id); + if (!textItem) + return; - if ((_renderFlags & RENDERFLAG_SKIPOPTIONALTEXT) && (ptr[1] & 0x80)) + size = textItem->getSize(); + dataPtr = textItem->getData(); + ptr = dataPtr; + + if ((_renderFlags & RENDERFLAG_SKIPOPTIONALTEXT) && (ptr[1] & 0x80)) { + delete textItem; return; + } if (_renderFlags & RENDERFLAG_DOUBLECOORDS) { destX = (READ_LE_UINT16(ptr) & 0x7FFF) * 2; @@ -328,7 +329,7 @@ void Draw_v2::printTotText(int16 id) { ptrEnd = ptr; while (((ptrEnd - dataPtr) < size) && (*ptrEnd != 1)) { // Converting to unknown commands/characters to spaces - if ((_vm->_game->_totFileData[0x29] < 0x32) && (*ptrEnd > 3) && (*ptrEnd < 32)) + if ((_vm->_game->_script->getVersionMinor() < 2) && (*ptrEnd > 3) && (*ptrEnd < 32)) *ptrEnd = 32; switch (*ptrEnd) { @@ -524,7 +525,7 @@ void Draw_v2::printTotText(int16 id) { case 10: str[0] = (char) 255; WRITE_LE_UINT16((uint16 *) (str + 1), - ptr - _vm->_game->_totTextData->dataPtr); + ptr - _vm->_game->_resources->getTexts()); str[3] = 0; ptr++; for (int i = *ptr++; i > 0; i--) { @@ -597,7 +598,9 @@ void Draw_v2::printTotText(int16 id) { } } + delete textItem; _renderFlags = savedFlags; + if (!(_renderFlags & RENDERFLAG_COLLISIONS)) return; @@ -610,14 +613,13 @@ void Draw_v2::printTotText(int16 id) { } void Draw_v2::spriteOperation(int16 operation) { - uint16 id; - byte *dataBuf; int16 len; int16 x, y; SurfaceDescPtr sourceSurf, destSurf; bool deltaVeto; int16 left; int16 ratio; + Resource *resource; // Always assigned to -1 in Game::loadTotFile() int16 someHandle = -1; @@ -705,6 +707,11 @@ void Draw_v2::spriteOperation(int16 operation) { sourceSurf = _spritesArray[_sourceSurface]; destSurf = _spritesArray[_destSurface]; + if (!destSurf) { + warning("Can't do operation %d on surface %d: nonexistent", operation, _destSurface); + return; + } + switch (operation) { case DRAW_BLITSURF: case DRAW_DRAWLETTER: @@ -755,41 +762,20 @@ void Draw_v2::spriteOperation(int16 operation) { break; case DRAW_LOADSPRITE: - id = _spriteLeft; - - if ((id >= 30000) || (_vm->_game->_lomHandle >= 0)) { - dataBuf = 0; + resource = _vm->_game->_resources->getResource((uint16) _spriteLeft, + &_spriteRight, &_spriteBottom); - if (_vm->_game->_lomHandle >= 0) - warning("Urban Stub: LOADSPRITE %d, LOM", id); - else - dataBuf = _vm->_game->loadExtData(id, &_spriteRight, &_spriteBottom); - - if (!dataBuf) - break; - - _vm->_video->drawPackedSprite(dataBuf, - _spriteRight, _spriteBottom, _destSpriteX, _destSpriteY, - _transparency, *_spritesArray[_destSurface]); - - dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, - _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1); - - delete[] dataBuf; + if (!resource) break; - } - // Load from .TOT resources - if (!(dataBuf = _vm->_game->loadTotResource(id, 0, &_spriteRight, &_spriteBottom))) - break; - - _vm->_video->drawPackedSprite(dataBuf, - _spriteRight, _spriteBottom, - _destSpriteX, _destSpriteY, - _transparency, *_spritesArray[_destSurface]); + _vm->_video->drawPackedSprite(resource->getData(), + _spriteRight, _spriteBottom, _destSpriteX, _destSpriteY, + _transparency, *_spritesArray[_destSurface]); dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1); + + delete resource; break; case DRAW_PRINTTEXT: @@ -802,7 +788,7 @@ void Draw_v2::spriteOperation(int16 operation) { if (((int8) _textToPrint[0]) == -1) { _vm->validateLanguage(); - dataBuf = _vm->_game->_totTextData->dataPtr + _textToPrint[1] + 1; + byte *dataBuf = _vm->_game->_resources->getTexts() + _textToPrint[1] + 1; len = *dataBuf++; for (int i = 0; i < len; i++, dataBuf += 2) { _vm->_video->drawLetter(READ_LE_UINT16(dataBuf), _destSpriteX, diff --git a/engines/gob/expression.cpp b/engines/gob/expression.cpp new file mode 100644 index 0000000000..61376b2212 --- /dev/null +++ b/engines/gob/expression.cpp @@ -0,0 +1,1144 @@ +/* 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 "common/endian.h" + +#include "gob/gob.h" +#include "gob/expression.h" +#include "gob/global.h" +#include "gob/game.h" +#include "gob/script.h" +#include "gob/inter.h" + +namespace Gob { + +Expression::Stack::Stack(size_t size) { + opers = new byte[size]; + values = new int32[size]; + memset(opers , 0, size * sizeof(byte )); + memset(values, 0, size * sizeof(int32)); +} + +Expression::Stack::~Stack() { + delete[] opers; + delete[] values; +} + +Expression::StackFrame::StackFrame(const Stack &stack) { + opers = stack.opers - 1; + values = stack.values - 1; + pos = -1; +} + +void Expression::StackFrame::push(int count) { + opers += count; + values += count; + pos += count; +} + +void Expression::StackFrame::pop(int count) { + opers -= count; + values -= count; + pos -= count; +} + +Expression::Expression(GobEngine *vm) : _vm(vm) { + _resultStr[0] = 0; + _resultInt = 0; +} + +int32 Expression::encodePtr(byte *ptr, int type) { + int32 offset = 0; + + switch (type) { + case kExecPtr: + offset = _vm->_game->_script->getOffset(ptr); + break; + case kInterVar: + offset = ptr - ((byte *) _vm->_inter->_variables->getAddressOff8(0)); + break; + case kResStr: + offset = ptr - ((byte *) _resultStr); + break; + default: + error("Expression::encodePtr(): Unknown pointer type"); + } + assert((offset & 0xF0000000) == 0); + return (type << 28) | offset; +} + +byte *Expression::decodePtr(int32 n) { + byte *ptr; + + switch (n >> 28) { + case kExecPtr: + return _vm->_game->_script->getData((n & 0x0FFFFFFF)); + case kInterVar: + ptr = (byte *) _vm->_inter->_variables->getAddressOff8(0); + break; + case kResStr: + ptr = (byte *) _resultStr; + break; + default: + error("Expression::decodePtr(): Unknown pointer type"); + } + return ptr + (n & 0x0FFFFFFF); +} + +void Expression::skipExpr(char stopToken) { + int16 dimCount; + byte operation; + int16 num; + int16 dim; + + num = 0; + while (true) { + operation = _vm->_game->_script->readByte(); + + if ((operation >= 14) && (operation <= OP_FUNC)) { + switch (operation) { + case 14: + _vm->_game->_script->skip(4); + if (_vm->_game->_script->peekByte() == 97) + _vm->_game->_script->skip(1); + break; + + case OP_LOAD_VAR_INT16: + case OP_LOAD_VAR_INT8: + case OP_LOAD_IMM_INT16: + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_INT32_AS_INT16: + _vm->_game->_script->skip(2); + break; + + case OP_LOAD_IMM_INT32: + _vm->_game->_script->skip(4); + break; + + case OP_LOAD_IMM_INT8: + _vm->_game->_script->skip(1); + break; + + case OP_LOAD_IMM_STR: + _vm->_game->_script->skip(strlen(_vm->_game->_script->peekString()) + 1); + break; + + case OP_LOAD_VAR_STR: + _vm->_game->_script->skip(2); + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + skipExpr(OP_END_MARKER); + } + break; + + case 15: + _vm->_game->_script->skip(2); + + case OP_ARRAY_INT8: + case OP_ARRAY_INT32: + case OP_ARRAY_INT16: + case OP_ARRAY_STR: + dimCount = _vm->_game->_script->peekByte(2); + // skip header and dimensions + _vm->_game->_script->skip(3 + dimCount); + // skip indices + for (dim = 0; dim < dimCount; dim++) + skipExpr(OP_END_MARKER); + + if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + skipExpr(OP_END_MARKER); + } + break; + + case OP_FUNC: + _vm->_game->_script->skip(1); + skipExpr(OP_END_EXPR); + } + continue; + } // if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) + + if (operation == OP_BEGIN_EXPR) { + num++; + continue; + } + + if ((operation == OP_NOT) || ((operation >= OP_NEG) && (operation <= 8))) + continue; + + if ((operation >= OP_OR) && (operation <= OP_NEQ)) + continue; + + if (operation == OP_END_EXPR) + num--; + + if (operation != stopToken) + continue; + + if ((stopToken != OP_END_EXPR) || (num < 0)) + return; + } +} + +void Expression::printExpr(char stopToken) { + // Expression printing disabled by default + return; + + int32 savedPos = _vm->_game->_script->pos(); + printExpr_internal(stopToken); + + // restore IP to start of expression + _vm->_game->_script->seek(savedPos); +} + +void Expression::printExpr_internal(char stopToken) { + int16 dimCount; + byte operation; + int16 num; + int16 dim; + byte *arrDesc; + byte func; + + num = 0; + while (true) { + operation = _vm->_game->_script->readByte(); + + if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) { + // operands + + switch (operation) { + case OP_LOAD_VAR_INT16: // int16 variable load + debugN(5, "var16_%d", _vm->_game->_script->readUint16()); + break; + + case OP_LOAD_VAR_INT8: // int8 variable load: + debugN(5, "var8_%d", _vm->_game->_script->readUint16()); + break; + + case OP_LOAD_IMM_INT32: // int32/uint32 immediate + debugN(5, "%d", _vm->_game->_script->readInt32()); + break; + + case OP_LOAD_IMM_INT16: // int16 immediate + debugN(5, "%d", _vm->_game->_script->readInt16()); + break; + + case OP_LOAD_IMM_INT8: // int8 immediate + debugN(5, "%d", _vm->_game->_script->readInt8()); + break; + + case OP_LOAD_IMM_STR: // string immediate + debugN(5, "\42%s\42", _vm->_game->_script->readString()); + break; + + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_INT32_AS_INT16: + debugN(5, "var_%d", _vm->_game->_script->readUint16()); + break; + + case OP_LOAD_VAR_STR: // string variable load + debugN(5, "(&var_%d)", _vm->_game->_script->readUint16()); + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + debugN(5, "{"); + printExpr_internal(OP_END_MARKER); // this also prints the closing } + } + break; + + case OP_ARRAY_INT8: // int8 array access + case OP_ARRAY_INT32: // int32 array access + case OP_ARRAY_INT16: // int16 array access + case OP_ARRAY_STR: // string array access + debugN(5, "\n"); + if (operation == OP_ARRAY_STR) + debugN(5, "(&"); + + debugN(5, "var_%d[", _vm->_game->_script->readInt16()); + dimCount = _vm->_game->_script->readByte(); + arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(dimCount); + for (dim = 0; dim < dimCount; dim++) { + printExpr_internal(OP_END_MARKER); + debugN(5, " of %d", (int16) arrDesc[dim]); + if (dim != dimCount - 1) + debugN(5, ","); + } + debugN(5, "]"); + if (operation == OP_ARRAY_STR) + debugN(5, ")"); + + if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + debugN(5, "{"); + printExpr_internal(OP_END_MARKER); // this also prints the closing } + } + break; + + case OP_FUNC: // function + func = _vm->_game->_script->readByte(); + if (func == FUNC_SQR) + debugN(5, "sqr("); + else if (func == FUNC_RAND) + debugN(5, "rand("); + else if (func == FUNC_ABS) + debugN(5, "abs("); + else if ((func == FUNC_SQRT1) || (func == FUNC_SQRT2) || (func == FUNC_SQRT3)) + debugN(5, "sqrt("); + else + debugN(5, "id("); + printExpr_internal(OP_END_EXPR); + break; + } + continue; + } // if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) + + // operators + switch (operation) { + case OP_BEGIN_EXPR: + debugN(5, "("); + break; + + case OP_NOT: + debugN(5, "!"); + break; + + case OP_END_EXPR: + debugN(5, ")"); + break; + + case OP_NEG: + debugN(5, "-"); + break; + + case OP_ADD: + debugN(5, "+"); + break; + + case OP_SUB: + debugN(5, "-"); + break; + + case OP_BITOR: + debugN(5, "|"); + break; + + case OP_MUL: + debugN(5, "*"); + break; + + case OP_DIV: + debugN(5, "/"); + break; + + case OP_MOD: + debugN(5, "%%"); + break; + + case OP_BITAND: + debugN(5, "&"); + break; + + case OP_OR: + debugN(5, "||"); + break; + + case 31: + debugN(5, "&&"); + break; + + case OP_LESS: + debugN(5, "<"); + break; + + case OP_LEQ: + debugN(5, "<="); + break; + + case OP_GREATER: + debugN(5, ">"); + break; + + case OP_GEQ: + debugN(5, ">="); + break; + + case OP_EQ: + debugN(5, "=="); + break; + + case OP_NEQ: + debugN(5, "!="); + break; + + case 99: + debugN(5, "\n"); + break; + + case OP_END_MARKER: + debugN(5, "}"); + if (stopToken != OP_END_MARKER) { + debugN(5, "Closing paren without opening?"); + } + break; + + default: + debugN(5, "<%d>", (int16) operation); + error("Expression::printExpr(): invalid operator in expression"); + break; + } + + if (operation == OP_BEGIN_EXPR) { + num++; + continue; + } + + if ((operation == OP_NOT) || ((operation >= OP_NEG) && (operation <= 8))) + continue; + + if ((operation >= OP_OR) && (operation <= OP_NEQ)) + continue; + + if (operation == OP_END_EXPR) + num--; + + if (operation == stopToken) { + if ((stopToken != OP_END_EXPR) || (num < 0)) { + return; + } + } + } +} + + +void Expression::printVarIndex() { + byte *arrDesc; + int16 dim; + int16 dimCount; + int16 operation; + int16 temp; + + int32 pos = _vm->_game->_script->pos(); + + operation = _vm->_game->_script->readByte(); + switch (operation) { + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_STR: + temp = _vm->_game->_script->readUint16() * 4; + debugN(5, "&var_%d", temp); + if ((operation == OP_LOAD_VAR_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + debugN(5, "+"); + printExpr(OP_END_MARKER); + } + break; + + case OP_ARRAY_INT32: + case OP_ARRAY_STR: + debugN(5, "&var_%d[", _vm->_game->_script->readUint16()); + dimCount = _vm->_game->_script->readByte(); + arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(dimCount); + for (dim = 0; dim < dimCount; dim++) { + printExpr(OP_END_MARKER); + debugN(5, " of %d", (int16) arrDesc[dim]); + if (dim != dimCount - 1) + debugN(5, ","); + } + debugN(5, "]"); + + if ((operation == OP_ARRAY_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + debugN(5, "+"); + printExpr(OP_END_MARKER); + } + break; + + default: + debugN(5, "var_0"); + break; + } + debugN(5, "\n"); + + _vm->_game->_script->seek(pos); + return; +} + +int Expression::cmpHelper(const StackFrame &stackFrame) { + byte type = stackFrame.opers[-3]; + int cmpTemp = 0; + + if (type == OP_LOAD_IMM_INT16) { + cmpTemp = (int)stackFrame.values[-3] - (int)stackFrame.values[-1]; + } else if (type == OP_LOAD_IMM_STR) { + if ((char *)decodePtr(stackFrame.values[-3]) != _resultStr) { + strcpy(_resultStr, (char *)decodePtr(stackFrame.values[-3])); + stackFrame.values[-3] = encodePtr((byte *) _resultStr, kResStr); + } + cmpTemp = strcmp(_resultStr, (char *)decodePtr(stackFrame.values[-1])); + } + + return cmpTemp; +} + +bool Expression::getVarBase(uint32 &varBase, bool mindStop, + uint16 *size, uint16 *type) { + + varBase = 0; + + byte operation = _vm->_game->_script->peekByte(); + while ((operation == 14) || (operation == 15)) { + _vm->_game->_script->skip(1); + + if (operation == 14) { + // Add a direct offset + + varBase += _vm->_game->_script->readInt16() * 4; + + if (size) + *size = _vm->_game->_script->peekUint16(); + if (type) + *type = 14; + + _vm->_game->_script->skip(2); + + debugC(2, kDebugExpression, "varBase: %d, by %d", varBase, operation); + + if (_vm->_game->_script->peekByte() != 97) { + if (mindStop) + return true; + } else + _vm->_game->_script->skip(1); + + } else if (operation == 15) { + // Add an offset from an array + + varBase += _vm->_game->_script->readInt16() * 4; + + uint16 offset1 = _vm->_game->_script->readUint16(); + + if (size) + *size = offset1; + if (type) + *type = 15; + + uint8 dimCount = _vm->_game->_script->readByte(); + byte *dimArray = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + + _vm->_game->_script->skip(dimCount); + + uint16 offset2 = 0; + for (int i = 0; i < dimCount; i++) { + int16 dim = CLIP<int>(parseValExpr(OP_END_MARKER), 0, dimArray[i] - 1); + + offset2 = offset2 * dimArray[i] + dim; + } + + varBase += offset2 * offset1 * 4; + + debugC(2, kDebugExpression, "varBase: %d, by %d", varBase, operation); + + if (_vm->_game->_script->peekByte() != 97) { + if (mindStop) + return true; + } else + _vm->_game->_script->skip(1); + } + + operation = _vm->_game->_script->peekByte(); + } + + return false; +} + +int16 Expression::parseVarIndex(uint16 *size, uint16 *type) { + int16 temp2; + byte *arrDesc; + int16 dim; + int16 dimCount; + int16 operation; + int16 temp; + int16 offset; + int16 val; + uint32 varBase; + + if (getVarBase(varBase, true, size, type)) + return varBase; + + operation = _vm->_game->_script->readByte(); + + if (size) + *size = 0; + if (type) + *type = operation; + + debugC(5, kDebugExpression, "var parse = %d", operation); + switch (operation) { + case OP_ARRAY_INT8: + case OP_ARRAY_INT32: + case OP_ARRAY_INT16: + case OP_ARRAY_STR: + temp = _vm->_game->_script->readInt16(); + dimCount = _vm->_game->_script->readByte(); + arrDesc = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(dimCount); + offset = 0; + for (dim = 0; dim < dimCount; dim++) { + temp2 = parseValExpr(OP_END_MARKER); + offset = arrDesc[dim] * offset + temp2; + } + if (operation == OP_ARRAY_INT8) + return varBase + temp + offset; + if (operation == OP_ARRAY_INT32) + return varBase + (temp + offset) * 4; + if (operation == OP_ARRAY_INT16) + return varBase + (temp + offset) * 2; + temp *= 4; + offset *= 4; + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + temp += parseValExpr(OP_END_MARKER); + } + return varBase + offset * _vm->_global->_inter_animDataSize + temp; + + case OP_LOAD_VAR_INT16: + return varBase + _vm->_game->_script->readInt16() * 2; + + case OP_LOAD_VAR_INT8: + return varBase + _vm->_game->_script->readInt16(); + + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_INT32_AS_INT16: + case OP_LOAD_VAR_STR: + temp = _vm->_game->_script->readInt16() * 4; + debugC(5, kDebugExpression, "oper = %d", _vm->_game->_script->peekInt16()); + if ((operation == OP_LOAD_VAR_STR) && (_vm->_game->_script->peekByte() == 13)) { + _vm->_game->_script->skip(1); + val = parseValExpr(OP_END_MARKER); + temp += val; + debugC(5, kDebugExpression, "parse subscript = %d", val); + } + return varBase + temp; + + default: + return 0; + } +} + +int16 Expression::parseValExpr(byte stopToken) { + parseExpr(stopToken, 0); + + return _resultInt; +} + +// Load a value according to the operation +void Expression::loadValue(byte operation, uint32 varBase, const StackFrame &stackFrame) { + int16 dimCount; + int16 temp; + int16 temp2; + int16 offset; + int16 dim; + byte *arrDescPtr; + int32 prevPrevVal; + int32 prevVal; + int32 curVal; + + switch (operation) { + case OP_ARRAY_INT8: + case OP_ARRAY_INT32: + case OP_ARRAY_INT16: + case OP_ARRAY_STR: + *stackFrame.opers = (operation == OP_ARRAY_STR) ? OP_LOAD_IMM_STR : OP_LOAD_IMM_INT16; + temp = _vm->_game->_script->readInt16(); + dimCount = _vm->_game->_script->readByte(); + arrDescPtr = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(dimCount); + offset = 0; + for (dim = 0; dim < dimCount; dim++) { + temp2 = parseValExpr(OP_END_MARKER); + offset = offset * arrDescPtr[dim] + temp2; + } + if (operation == OP_ARRAY_INT8) + *stackFrame.values = (int8) READ_VARO_UINT8(varBase + temp + offset); + else if (operation == OP_ARRAY_INT32) + *stackFrame.values = READ_VARO_UINT32(varBase + temp * 4 + offset * 4); + else if (operation == OP_ARRAY_INT16) + *stackFrame.values = (int16) READ_VARO_UINT16(varBase + temp * 2 + offset * 2); + else if (operation == OP_ARRAY_STR) { + *stackFrame.values = encodePtr(_vm->_inter->_variables->getAddressOff8( + varBase + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4), + kInterVar); + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + temp2 = parseValExpr(OP_END_MARKER); + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = READ_VARO_UINT8(varBase + temp * 4 + + offset * 4 * _vm->_global->_inter_animDataSize + temp2); + } + } + break; + + case OP_LOAD_VAR_INT16: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = (int16) READ_VARO_UINT16(varBase + _vm->_game->_script->readInt16() * 2); + break; + + case OP_LOAD_VAR_INT8: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = (int8) READ_VARO_UINT8(varBase + _vm->_game->_script->readInt16()); + break; + + case OP_LOAD_IMM_INT32: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = _vm->_game->_script->readInt32(); + break; + + case OP_LOAD_IMM_INT16: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = _vm->_game->_script->readInt16(); + break; + + case OP_LOAD_IMM_INT8: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = _vm->_game->_script->readInt8(); + break; + + case OP_LOAD_IMM_STR: + *stackFrame.opers = OP_LOAD_IMM_STR; + *stackFrame.values = encodePtr((byte *) _vm->_game->_script->readString(), kExecPtr); + break; + + case OP_LOAD_VAR_INT32: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = READ_VARO_UINT32(varBase + _vm->_game->_script->readInt16() * 4); + break; + + case OP_LOAD_VAR_INT32_AS_INT16: + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = (int16) READ_VARO_UINT16(varBase + _vm->_game->_script->readInt16() * 4); + break; + + case OP_LOAD_VAR_STR: + *stackFrame.opers = OP_LOAD_IMM_STR; + temp = _vm->_game->_script->readInt16() * 4; + *stackFrame.values = encodePtr(_vm->_inter->_variables->getAddressOff8(varBase + temp), kInterVar); + if (_vm->_game->_script->peekByte() == 13) { + _vm->_game->_script->skip(1); + temp += parseValExpr(OP_END_MARKER); + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = READ_VARO_UINT8(varBase + temp); + } + break; + + case OP_FUNC: + operation = _vm->_game->_script->readByte(); + parseExpr(OP_END_EXPR, 0); + + switch (operation) { + case FUNC_SQRT1: + case FUNC_SQRT2: + case FUNC_SQRT3: + curVal = 1; + prevVal = 1; + + do { + prevPrevVal = prevVal; + prevVal = curVal; + curVal = (curVal + _resultInt / curVal) / 2; + } while ((curVal != prevVal) && (curVal != prevPrevVal)); + _resultInt = curVal; + break; + + case FUNC_SQR: + _resultInt = + _resultInt * _resultInt; + break; + + case FUNC_ABS: + if (_resultInt < 0) + _resultInt = -_resultInt; + break; + + case FUNC_RAND: + _resultInt = + _vm->_util->getRandom(_resultInt); + break; + } + + *stackFrame.opers = OP_LOAD_IMM_INT16; + *stackFrame.values = _resultInt; + break; + } +} + +void Expression::simpleArithmetic1(StackFrame &stackFrame) { + switch (stackFrame.opers[-1]) { + case OP_ADD: + if (stackFrame.opers[-2] == OP_LOAD_IMM_STR) { + if ((char *) decodePtr(stackFrame.values[-2]) != _resultStr) { + strcpy(_resultStr, (char *) decodePtr(stackFrame.values[-2])); + stackFrame.values[-2] = encodePtr((byte *) _resultStr, kResStr); + } + strcat(_resultStr, (char *) decodePtr(stackFrame.values[0])); + stackFrame.pop(2); + } + break; + + case OP_MUL: + stackFrame.values[-2] *= stackFrame.values[0]; + stackFrame.pop(2); + break; + + case OP_DIV: + stackFrame.values[-2] /= stackFrame.values[0]; + stackFrame.pop(2); + break; + + case OP_MOD: + stackFrame.values[-2] %= stackFrame.values[0]; + stackFrame.pop(2); + break; + + case OP_BITAND: + stackFrame.values[-2] &= stackFrame.values[0]; + stackFrame.pop(2); + break; + } +} + +void Expression::simpleArithmetic2(StackFrame &stackFrame) { + if (stackFrame.pos > 1) { + if (stackFrame.opers[-2] == OP_NEG) { + stackFrame.opers[-2] = OP_LOAD_IMM_INT16; + stackFrame.values[-2] = -stackFrame.values[-1]; + stackFrame.pop(); + } else if (stackFrame.opers[-2] == OP_NOT) { + stackFrame.opers[-2] = (stackFrame.opers[-1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(); + } + } + + if (stackFrame.pos > 2) { + switch (stackFrame.opers[-2]) { + case OP_MUL: + stackFrame.values[-3] *= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_DIV: + stackFrame.values[-3] /= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_MOD: + stackFrame.values[-3] %= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_BITAND: + stackFrame.values[-3] &= stackFrame.values[-1]; + stackFrame.pop(2); + break; + } + } + +} + +// Complex arithmetics with brackets +bool Expression::complexArithmetic(Stack &stack, StackFrame &stackFrame, int16 brackStart) { + switch (stackFrame.opers[-2]) { + case OP_ADD: + if (stack.opers[brackStart] == OP_LOAD_IMM_INT16) { + stack.values[brackStart] += stackFrame.values[-1]; + } else if (stack.opers[brackStart] == OP_LOAD_IMM_STR) { + if ((char *) decodePtr(stack.values[brackStart]) != _resultStr) { + strcpy(_resultStr, (char *) decodePtr(stack.values[brackStart])); + stack.values[brackStart] = + encodePtr((byte *) _resultStr, kResStr); + } + strcat(_resultStr, (char *) decodePtr(stackFrame.values[-1])); + } + stackFrame.pop(2); + break; + + case OP_SUB: + stack.values[brackStart] -= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_BITOR: + stack.values[brackStart] |= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_MUL: + stackFrame.values[-3] *= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_DIV: + stackFrame.values[-3] /= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_MOD: + stackFrame.values[-3] %= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_BITAND: + stackFrame.values[-3] &= stackFrame.values[-1]; + stackFrame.pop(2); + break; + + case OP_OR: + // (x OR false) == x + // (x OR true) == true + if (stackFrame.opers[-3] == GOB_FALSE) + stackFrame.opers[-3] = stackFrame.opers[-1]; + stackFrame.pop(2); + break; + + case OP_AND: + // (x AND false) == false + // (x AND true) == x + if (stackFrame.opers[-3] == GOB_TRUE) + stackFrame.opers[-3] = stackFrame.opers[-1]; + stackFrame.pop(2); + break; + + case OP_LESS: + stackFrame.opers[-3] = (cmpHelper(stackFrame) < 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_LEQ: + stackFrame.opers[-3] = (cmpHelper(stackFrame) <= 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_GREATER: + stackFrame.opers[-3] = (cmpHelper(stackFrame) > 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_GEQ: + stackFrame.opers[-3] = (cmpHelper(stackFrame) >= 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_EQ: + stackFrame.opers[-3] = (cmpHelper(stackFrame) == 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + case OP_NEQ: + stackFrame.opers[-3] = (cmpHelper(stackFrame) != 0) ? GOB_TRUE : GOB_FALSE; + stackFrame.pop(2); + break; + + default: + return true; + } + + return false; +} + +// Assign the result to the appropriate _result variable +void Expression::getResult(byte operation, int32 value, byte *type) { + if (type != 0) + *type = operation; + + switch (operation) { + case OP_NOT: + if (type != 0) + *type ^= 1; + break; + + case OP_LOAD_IMM_INT16: + _resultInt = value; + break; + + case OP_LOAD_IMM_STR: + if ((char *) decodePtr(value) != _resultStr) + strcpy(_resultStr, (char *) decodePtr(value)); + break; + + case OP_LOAD_VAR_INT32: + case OP_LOAD_VAR_INT32_AS_INT16: + break; + + default: + _resultInt = 0; + if (type != 0) + *type = OP_LOAD_IMM_INT16; + break; + } +} + +int16 Expression::parseExpr(byte stopToken, byte *type) { + Stack stack; + StackFrame stackFrame(stack); + byte operation; + bool escape; + int16 brackStart; + uint32 varBase; + + while (true) { + getVarBase(varBase); + + stackFrame.push(); + + operation = _vm->_game->_script->readByte(); + if ((operation >= OP_ARRAY_INT8) && (operation <= OP_FUNC)) { + + loadValue(operation, varBase, stackFrame); + + if ((stackFrame.pos > 0) && ((stackFrame.opers[-1] == OP_NEG) || (stackFrame.opers[-1] == OP_NOT))) { + stackFrame.pop(); + + if (*stackFrame.opers == OP_NEG) { + *stackFrame.opers = OP_LOAD_IMM_INT16; + stackFrame.values[0] = -stackFrame.values[1]; + } else + *stackFrame.opers = (stackFrame.opers[1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; + } + + if (stackFrame.pos <= 0) + continue; + + simpleArithmetic1(stackFrame); + + continue; + } // (op >= OP_ARRAY_INT8) && (op <= OP_FUNC) + + if ((operation == stopToken) || (operation == OP_OR) || + (operation == OP_AND) || (operation == OP_END_EXPR)) { + while (stackFrame.pos >= 2) { + escape = false; + if ((stackFrame.opers[-2] == OP_BEGIN_EXPR) && + ((operation == OP_END_EXPR) || (operation == stopToken))) { + stackFrame.opers[-2] = stackFrame.opers[-1]; + if ((stackFrame.opers[-2] == OP_LOAD_IMM_INT16) || (stackFrame.opers[-2] == OP_LOAD_IMM_STR)) + stackFrame.values[-2] = stackFrame.values[-1]; + + stackFrame.pop(); + + simpleArithmetic2(stackFrame); + + if (operation != stopToken) + break; + } // if ((stackFrame.opers[-2] == OP_BEGIN_EXPR) && ...) + + for (brackStart = (stackFrame.pos - 2); (brackStart > 0) && + (stack.opers[brackStart] < OP_OR) && (stack.opers[brackStart] != OP_BEGIN_EXPR); + brackStart--) + ; + + if ((stack.opers[brackStart] >= OP_OR) || (stack.opers[brackStart] == OP_BEGIN_EXPR)) + brackStart++; + + if (complexArithmetic(stack, stackFrame, brackStart)) + break; + + } // while (stackFrame.pos >= 2) + + if ((operation == OP_OR) || (operation == OP_AND)) { + if (stackFrame.opers[-1] == OP_LOAD_IMM_INT16) { + if (stackFrame.values[-1] != 0) + stackFrame.opers[-1] = GOB_TRUE; + else + stackFrame.opers[-1] = GOB_FALSE; + } + + if (((operation == OP_OR) && (stackFrame.opers[-1] == GOB_TRUE)) || + ((operation == OP_AND) && (stackFrame.opers[-1] == GOB_FALSE))) { + if ((stackFrame.pos > 1) && (stackFrame.opers[-2] == OP_BEGIN_EXPR)) { + skipExpr(OP_END_EXPR); + stackFrame.opers[-2] = stackFrame.opers[-1]; + stackFrame.pop(2); + } else { + skipExpr(stopToken); + } + operation = _vm->_game->_script->peekByte(-1); + if ((stackFrame.pos > 0) && (stackFrame.opers[-1] == OP_NOT)) { + if (stackFrame.opers[0] == GOB_FALSE) + stackFrame.opers[-1] = GOB_TRUE; + else + stackFrame.opers[-1] = GOB_FALSE; + + stackFrame.pop(); + } + } else + stackFrame.opers[0] = operation; + } else + stackFrame.pop(); + + if (operation != stopToken) + continue; + + getResult(stack.opers[0], stack.values[0], type); + + return 0; + } // (operation == stopToken) || (operation == OP_OR) || (operation == OP_AND) || (operation == OP_END_EXPR) + + if ((operation < OP_NEG) || (operation > OP_NOT)) { + if ((operation < OP_LESS) || (operation > OP_NEQ)) + continue; + + if (stackFrame.pos > 2) { + if (stackFrame.opers[-2] == OP_ADD) { + if (stackFrame.opers[-3] == OP_LOAD_IMM_INT16) { + stackFrame.values[-3] += stackFrame.values[-1]; + } else if (stackFrame.opers[-3] == OP_LOAD_IMM_STR) { + if ((char *) decodePtr(stackFrame.values[-3]) != _resultStr) { + strcpy(_resultStr, (char *) decodePtr(stackFrame.values[-3])); + stackFrame.values[-3] = encodePtr((byte *) _resultStr, kResStr); + } + strcat(_resultStr, (char *) decodePtr(stackFrame.values[-1])); + } + stackFrame.pop(2); + + } else if (stackFrame.opers[-2] == OP_SUB) { + stackFrame.values[-3] -= stackFrame.values[-1]; + stackFrame.pop(2); + } else if (stackFrame.opers[-2] == OP_BITOR) { + stackFrame.values[-3] |= stackFrame.values[-1]; + stackFrame.pop(2); + } + } + } + *stackFrame.opers = operation; + } +} + +int32 Expression::getResultInt() { + return _resultInt; +} + +char *Expression::getResultStr() { + return _resultStr; +} + +} // End of namespace Gob diff --git a/engines/gob/expression.h b/engines/gob/expression.h new file mode 100644 index 0000000000..894704e2a9 --- /dev/null +++ b/engines/gob/expression.h @@ -0,0 +1,178 @@ +/* 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 GOB_EXPRESSION_H +#define GOB_EXPRESSION_H + +#include "common/scummsys.h" + +namespace Gob { + +class GobEngine; + +enum { + OP_NEG = 1, + OP_ADD = 2, + OP_SUB = 3, + OP_BITOR = 4, + OP_MUL = 5, + OP_DIV = 6, + OP_MOD = 7, + OP_BITAND = 8, + OP_BEGIN_EXPR = 9, + OP_END_EXPR = 10, + OP_NOT = 11, + + OP_END_MARKER = 12, // Marks end of an array or string + + + OP_ARRAY_INT8 = 16, + OP_LOAD_VAR_INT16 = 17, + OP_LOAD_VAR_INT8 = 18, + OP_LOAD_IMM_INT32 = 19, + OP_LOAD_IMM_INT16 = 20, + OP_LOAD_IMM_INT8 = 21, + OP_LOAD_IMM_STR = 22, + OP_LOAD_VAR_INT32 = 23, + OP_LOAD_VAR_INT32_AS_INT16 = 24, + OP_LOAD_VAR_STR = 25, + OP_ARRAY_INT32 = 26, + OP_ARRAY_INT16 = 27, + OP_ARRAY_STR = 28, + + OP_FUNC = 29, + + OP_OR = 30, // Logical OR + OP_AND = 31, // Logical AND + OP_LESS = 32, + OP_LEQ = 33, + OP_GREATER = 34, + OP_GEQ = 35, + OP_EQ = 36, + OP_NEQ = 37 +}; + +enum { + FUNC_SQRT1 = 0, + FUNC_SQRT2 = 1, + FUNC_SQRT3 = 6, + + FUNC_SQR = 5, + FUNC_ABS = 7, + FUNC_RAND = 10 +}; + +enum { + TYPE_IMM_INT8 = OP_LOAD_IMM_INT8, // 21 + TYPE_IMM_INT32 = OP_LOAD_IMM_INT32, // 19 + TYPE_IMM_INT16 = OP_LOAD_IMM_INT16, // 20 + TYPE_IMM_STR = OP_LOAD_IMM_STR, // 22 + TYPE_VAR_INT8 = OP_LOAD_VAR_INT8, // 18 + TYPE_VAR_INT16 = OP_LOAD_VAR_INT16, // 17 + TYPE_VAR_INT32 = OP_LOAD_VAR_INT32, // 23 + TYPE_VAR_STR = OP_LOAD_VAR_STR, // 25 + TYPE_ARRAY_INT8 = OP_ARRAY_INT8, // 16 + TYPE_ARRAY_INT16 = OP_ARRAY_INT16, // 27 + TYPE_ARRAY_INT32 = OP_ARRAY_INT32, // 26 + TYPE_ARRAY_STR = OP_ARRAY_STR, // 28 + TYPE_VAR_INT32_AS_INT16 = OP_LOAD_VAR_INT32_AS_INT16 // 24 +}; + +enum { + // FIXME: The following two 'truth values' are stored inside the list + // of "operators". So they somehow coincide with OP_LOAD_VAR_INT32 + // and OP_LOAD_VAR_INT32_AS_INT16. I haven't yet quite understood + // how, resp. what that means. You have been warned. + GOB_TRUE = 24, + GOB_FALSE = 23 +}; + +class Expression { +public: + Expression(GobEngine *vm); + virtual ~Expression() {} + + void skipExpr(char stopToken); + void printExpr(char stopToken); + void printVarIndex(void); + + int16 parseVarIndex(uint16 *size = 0, uint16 *type = 0); + int16 parseValExpr(byte stopToken = 99); + int16 parseExpr(byte stopToken, byte *type); + + int32 getResultInt(); + char *getResultStr(); + +private: + class Stack { + public: + byte *opers; + int32 *values; + + Stack(size_t size = 20); + ~Stack(); + }; + class StackFrame { + public: + byte *opers; + int32 *values; + int16 pos; + + StackFrame(const Stack &stack); + + void push(int count = 1); + void pop(int count = 1); + }; + + enum PointerType { + kExecPtr = 0, + kInterVar = 1, + kResStr = 2 + }; + + GobEngine *_vm; + + int32 _resultInt; + char _resultStr[200]; + + int32 encodePtr(byte *ptr, int type); + byte *decodePtr(int32 n); + + void printExpr_internal(char stopToken); + + bool getVarBase(uint32 &varBase, bool mindStop = false, + uint16 *size = 0, uint16 *type = 0); + int cmpHelper(const StackFrame &stackFrame); + void loadValue(byte operation, uint32 varBase, const StackFrame &stackFrame); + + void simpleArithmetic1(StackFrame &stackFrame); + void simpleArithmetic2(StackFrame &stackFrame); + bool complexArithmetic(Stack &stack, StackFrame &stackFrame, int16 brackStart); + void getResult(byte operation, int32 value, byte *type); +}; + +} // End of namespace Gob + +#endif // GOB_EXPRESSION_H diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index 09addc3900..5771ee9f76 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -31,8 +31,10 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/dataio.h" +#include "gob/variables.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/inter.h" -#include "gob/parse.h" #include "gob/draw.h" #include "gob/mult.h" #include "gob/videoplayer.h" @@ -40,21 +42,139 @@ namespace Gob { +Environments::Environments(GobEngine *vm) : _vm(vm) { + _environments = new Environment[kEnvironmentCount]; + + for (uint i = 0; i < kEnvironmentCount; i++) { + Environment &e = _environments[i]; + + e.cursorHotspotX = 0; + e.cursorHotspotY = 0; + e.variables = 0; + e.script = 0; + e.resources = 0; + e.curTotFile[0] = '\0'; + } +} + +Environments::~Environments() { + clear(); + + delete[] _environments; +} + +void Environments::clear() { + // Deleting unique variables, script and resources + + for (uint i = 0; i < kEnvironmentCount; i++) { + if (_environments[i].variables == _vm->_inter->_variables) + continue; + + if (!has(_environments[i].variables, i + 1)) + delete _environments[i].variables; + } + + for (uint i = 0; i < kEnvironmentCount; i++) { + if (_environments[i].script == _vm->_game->_script) + continue; + + if (!has(_environments[i].script, i + 1)) + delete _environments[i].script; + } + + for (uint i = 0; i < kEnvironmentCount; i++) { + if (_environments[i].resources == _vm->_game->_resources) + continue; + + if (!has(_environments[i].resources, i + 1)) + delete _environments[i].resources; + } +} + +void Environments::set(uint8 env) { + if (env >= kEnvironmentCount) + return; + + Environment &e = _environments[env]; + + // If it already has a unique script or resource assigned, delete them + if ((e.script != _vm->_game->_script) && !has(e.script, 0, env)) + delete e.script; + if ((e.resources != _vm->_game->_resources) && !has(e.resources, 0, env)) + delete e.resources; + + e.cursorHotspotX = _vm->_draw->_cursorHotspotXVar; + e.cursorHotspotY = _vm->_draw->_cursorHotspotYVar; + e.script = _vm->_game->_script; + e.resources = _vm->_game->_resources; + e.variables = _vm->_inter->_variables; + strncpy(e.curTotFile, _vm->_game->_curTotFile, 14); +} + +void Environments::get(uint8 env) const { + if (env >= kEnvironmentCount) + return; + + const Environment &e = _environments[env]; + + _vm->_draw->_cursorHotspotXVar = e.cursorHotspotX; + _vm->_draw->_cursorHotspotYVar = e.cursorHotspotY; + _vm->_game->_script = e.script; + _vm->_game->_resources = e.resources; + _vm->_inter->_variables = e.variables; + strncpy(_vm->_game->_curTotFile, e.curTotFile, 14); +} + +const char *Environments::getTotFile(uint8 env) const { + if (env >= kEnvironmentCount) + return ""; + + return _environments[env].curTotFile; +} + +bool Environments::has(Variables *variables, uint8 startEnv, int16 except) const { + for (uint i = startEnv; i < kEnvironmentCount; i++) { + if ((except >= 0) && (((uint16) except) == i)) + continue; + + if (_environments[i].variables == variables) + return true; + } + + return false; +} + +bool Environments::has(Script *script, uint8 startEnv, int16 except) const { + for (uint i = startEnv; i < kEnvironmentCount; i++) { + if ((except >= 0) && (((uint16) except) == i)) + continue; + + if (_environments[i].script == script) + return true; + } + + return false; +} + +bool Environments::has(Resources *resources, uint8 startEnv, int16 except) const { + for (uint i = startEnv; i < kEnvironmentCount; i++) { + if ((except >= 0) && (((uint16) except) == i)) + continue; + + if (_environments[i].resources == resources) + return true; + } + + return false; +} + + Game::Game(GobEngine *vm) : _vm(vm) { - _extTable = 0; - _totFileData = 0; - _totResourceTable = 0; - _imFileData = 0; - _extHandle = 0; - _lomHandle = -1; _collisionAreas = 0; _shouldPushColls = 0; _captureCount = 0; - _foundTotLoc = false; - _totTextData = 0; - _collStackSize = 0; for (int i = 0; i < 5; i++) { @@ -63,7 +183,6 @@ Game::Game(GobEngine *vm) : _vm(vm) { } _curTotFile[0] = 0; - _curExtFile[0] = 0; _totToLoad[0] = 0; _startTimeKey = 0; @@ -85,138 +204,20 @@ Game::Game(GobEngine *vm) : _vm(vm) { _noCd = false; _tempStr[0] = 0; - _curImaFile[0] = 0; _collStr[0] = 0; - _backupedCount = 0; - _curBackupPos = 0; + _numEnvironments = 0; + _curEnvironment = 0; - for (int i = 0; i < 5; i++) { - _cursorHotspotXArray[i] = 0; - _cursorHotspotYArray[i] = 0; - _totTextDataArray[i] = 0; - _totFileDataArray[i] = 0; - _totResourceTableArray[i] = 0; - _extTableArray[i] = 0; - _extHandleArray[i] = 0; - _imFileDataArray[i] = 0; - _variablesArray[i] = 0; - _curTotFileArray[i][0] = 0; - } + _environments = new Environments(_vm); + _script = new Script(_vm); + _resources = new Resources(_vm); } Game::~Game() { - delete[] _vm->_game->_totFileData; - if (_vm->_game->_totTextData) { - if (_vm->_game->_totTextData->items) - delete[] _vm->_game->_totTextData->items; - delete _vm->_game->_totTextData; - } - if (_vm->_game->_totResourceTable) { - delete[] _vm->_game->_totResourceTable->items; - delete _vm->_game->_totResourceTable; - } -} - -byte *Game::loadExtData(int16 itemId, int16 *pResWidth, - int16 *pResHeight, uint32 *dataSize) { - int16 commonHandle; - int16 itemsCount; - int32 offset; - uint32 size; - uint32 realSize; - ExtItem *item; - bool isPacked; - int16 handle; - int32 tableSize; - char path[20]; - byte *dataBuf; - byte *packedBuf; - byte *dataPtr; - - itemId -= 30000; - if (_extTable == 0) - return 0; - - commonHandle = -1; - itemsCount = _extTable->itemsCount; - item = &_extTable->items[itemId]; - tableSize = szGame_ExtTable + szGame_ExtItem * itemsCount; - - offset = item->offset; - size = item->size; - isPacked = (item->width & 0x8000) != 0; - - if ((pResWidth != 0) && (pResHeight != 0)) { - *pResWidth = item->width & 0x7FFF; - - if (*pResWidth & 0x4000) - size += 1 << 16; - if (*pResWidth & 0x2000) - size += 2 << 16; - if (*pResWidth & 0x1000) - size += 4 << 16; - - *pResWidth &= 0xFFF; - - *pResHeight = item->height; - debugC(7, kDebugFileIO, "loadExtData(%d, %d, %d)", - itemId, *pResWidth, *pResHeight); - } - - debugC(7, kDebugFileIO, "loadExtData(%d, 0, 0)", itemId); - - if (item->height == 0) - size += (item->width & 0x7FFF) << 16; - - debugC(7, kDebugFileIO, "size: %d off: %d", size, offset); - if (offset < 0) { - offset = -(offset + 1); - tableSize = 0; - _vm->_dataIO->closeData(_extHandle); - strcpy(path, "commun.ex1"); - path[strlen(path) - 1] = *(_totFileData + 0x3C) + '0'; - commonHandle = _vm->_dataIO->openData(path); - handle = commonHandle; - } else - handle = _extHandle; - - DataStream *stream = _vm->_dataIO->openAsStream(handle); - - debugC(7, kDebugFileIO, "off: %d size: %d", offset, tableSize); - stream->seek(offset + tableSize); - realSize = size; - if (isPacked) - dataBuf = new byte[size + 2]; - else - dataBuf = new byte[size]; - - dataPtr = dataBuf; - while (size > 32000) { - // BUG: huge->far conversion. Need normalization? - stream->read(dataPtr, 32000); - size -= 32000; - dataPtr += 32000; - } - stream->read(dataPtr, size); - - delete stream; - if (commonHandle != -1) { - _vm->_dataIO->closeData(commonHandle); - _extHandle = _vm->_dataIO->openData(_curExtFile); - } - - if (isPacked) { - packedBuf = dataBuf; - realSize = READ_LE_UINT32(packedBuf); - dataBuf = new byte[realSize]; - _vm->_dataIO->unpackData(packedBuf, dataBuf); - delete[] packedBuf; - } - - if (dataSize) - *dataSize = realSize; - return dataBuf; + delete _environments; + delete _script; + delete _resources; } void Game::freeCollision(int16 id) { @@ -281,39 +282,9 @@ void Game::capturePop(char doDraw) { _vm->_draw->freeSprite(30 + _captureCount); } -byte *Game::loadTotResource(int16 id, - int16 *dataSize, int16 *width, int16 *height) { - - TotResItem *itemPtr; - int32 offset; - - if (id >= _vm->_game->_totResourceTable->itemsCount) { - warning("Trying to load non-existent TOT resource (%s, %d/%d)", - _curTotFile, id, _totResourceTable->itemsCount - 1); - return 0; - } - - itemPtr = &_totResourceTable->items[id]; - offset = itemPtr->offset; - - if (dataSize) - *dataSize = itemPtr->size; - if (width) - *width = itemPtr->width; - if (height) - *height = itemPtr->height; - - if (offset < 0) { - offset = (-offset - 1) * 4; - return _imFileData + (int32) READ_LE_UINT32(_imFileData + offset); - } else - return _totResourceTable->dataPtr + szGame_TotResTable + - szGame_TotResItem * _totResourceTable->itemsCount + offset; -} - void Game::freeSoundSlot(int16 slot) { if (slot == -1) - slot = _vm->_parse->parseValExpr(); + slot = _vm->_game->_script->readValExpr(); _vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(slot)); } @@ -416,104 +387,6 @@ int16 Game::adjustKey(int16 key) { return key - 0x20; } -int32 Game::loadTotFile(const char *path) { - int16 handle; - int32 size; - - _lomHandle = -1; - - size = -1; - handle = _vm->_dataIO->openData(path); - if (handle >= 0) { - - if (!scumm_stricmp(path + strlen(path) - 3, "LOM")) { - warning("Urban Stub: loadTotFile %s", path); - - _lomHandle = handle; - - DataStream *stream = _vm->_dataIO->openAsStream(handle); - - stream->seek(48); - size = stream->readUint32LE(); - stream->seek(0); - - _totFileData = new byte[size]; - stream->read(_totFileData, size); - - delete stream; - } else { - _vm->_dataIO->closeData(handle); - size = _vm->_dataIO->getDataSize(path); - _totFileData = _vm->_dataIO->getData(path); - } - - } else { - Common::MemoryReadStream *videoExtraData = _vm->_vidPlayer->getExtraData(path); - - if (videoExtraData) { - warning("Found \"%s\" in video file", path); - - size = videoExtraData->size(); - _totFileData = new byte[size]; - videoExtraData->read(_totFileData, size); - delete videoExtraData; - } else - _totFileData = 0; - } - - return size; -} - -void Game::loadExtTable(void) { - int16 count; - - // Function is correct. [sev] - - _extHandle = _vm->_dataIO->openData(_curExtFile); - if (_extHandle < 0) - return; - - DataStream *stream = _vm->_dataIO->openAsStream(_extHandle); - count = stream->readUint16LE(); - - stream->seek(0); - _extTable = new ExtTable; - _extTable->items = 0; - if (count) - _extTable->items = new ExtItem[count]; - - _extTable->itemsCount = stream->readUint16LE(); - _extTable->unknown = stream->readByte(); - - for (int i = 0; i < count; i++) { - _extTable->items[i].offset = stream->readUint32LE(); - _extTable->items[i].size = stream->readUint16LE(); - _extTable->items[i].width = stream->readUint16LE(); - _extTable->items[i].height = stream->readUint16LE(); - } - - delete stream; -} - -void Game::loadImFile(void) { - char path[20]; - int16 handle; - - if ((_totFileData[0x3D] != 0) && (_totFileData[0x3B] == 0)) - return; - - strcpy(path, "commun.im1"); - if (_totFileData[0x3B] != 0) - path[strlen(path) - 1] = '0' + _totFileData[0x3B]; - - handle = _vm->_dataIO->openData(path); - if (handle < 0) - return; - - _vm->_dataIO->closeData(handle); - _imFileData = _vm->_dataIO->getData(path); -} - void Game::start(void) { _collisionAreas = new Collision[250]; memset(_collisionAreas, 0, 250 * sizeof(Collision)); @@ -533,27 +406,17 @@ void Game::start(void) { void Game::totSub(int8 flags, const char *newTotFile) { int8 curBackupPos; - if (_backupedCount >= 5) + if (_numEnvironments >= Environments::kEnvironmentCount) return; - _cursorHotspotXArray[_backupedCount] = _vm->_draw->_cursorHotspotXVar; - _cursorHotspotYArray[_backupedCount] = _vm->_draw->_cursorHotspotYVar; - _totTextDataArray[_backupedCount] = _totTextData; - _totFileDataArray[_backupedCount] = _totFileData; - _totResourceTableArray[_backupedCount] = _totResourceTable; - _extTableArray[_backupedCount] = _extTable; - _extHandleArray[_backupedCount] = _extHandle; - _imFileDataArray[_backupedCount] = _imFileData; - _variablesArray[_backupedCount] = _vm->_inter->_variables; - strcpy(_curTotFileArray[_backupedCount], _curTotFile); - - curBackupPos = _curBackupPos; - _backupedCount++; - _curBackupPos = _backupedCount; - - _totTextData = 0; - _totFileData = 0; - _totResourceTable = 0; + _environments->set(_numEnvironments); + + curBackupPos = _curEnvironment; + _numEnvironments++; + _curEnvironment = _numEnvironments; + + _script = new Script(_vm); + _resources = new Resources(_vm); if (flags & 1) _vm->_inter->_variables = 0; @@ -563,8 +426,10 @@ void Game::totSub(int8 flags, const char *newTotFile) { // else strcat(_curTotFile, ".TOT"); - if (_vm->_inter->_terminate != 0) + if (_vm->_inter->_terminate != 0) { + clearUnusedEnvironment(); return; + } pushCollisions(0); @@ -582,197 +447,64 @@ void Game::totSub(int8 flags, const char *newTotFile) { _vm->_inter->delocateVars(); } - _backupedCount--; - _curBackupPos = curBackupPos; - - _vm->_draw->_cursorHotspotXVar = _cursorHotspotXArray[_backupedCount]; - _vm->_draw->_cursorHotspotYVar = _cursorHotspotYArray[_backupedCount]; - _totTextData = _totTextDataArray[_backupedCount]; - _totFileData = _totFileDataArray[_backupedCount]; - _totResourceTable = _totResourceTableArray[_backupedCount]; - _extTable = _extTableArray[_backupedCount]; - _extHandle = _extHandleArray[_backupedCount]; - _imFileData = _imFileDataArray[_backupedCount]; - _vm->_inter->_variables = _variablesArray[_backupedCount]; - strcpy(_curTotFile, _curTotFileArray[_backupedCount]); - strcpy(_curExtFile, _curTotFile); - _curExtFile[strlen(_curExtFile) - 4] = '\0'; - strcat(_curExtFile, ".EXT"); + clearUnusedEnvironment(); + + _numEnvironments--; + _curEnvironment = curBackupPos; + _environments->get(_numEnvironments); } void Game::switchTotSub(int16 index, int16 skipPlay) { int16 backupedCount; int16 curBackupPos; - if ((_backupedCount - index) < 1) + if ((_numEnvironments - index) < 1) + return; + + int16 newPos = _curEnvironment - index - ((index >= 0) ? 1 : 0); + if (newPos >= Environments::kEnvironmentCount) return; - int16 newPos = _curBackupPos - index - ((index >= 0) ? 1 : 0); // WORKAROUND: Some versions don't make the MOVEMENT menu item unselectable // in the dreamland screen, resulting in a crash when it's clicked. if ((_vm->getGameType() == kGameTypeGob2) && (index == -1) && (skipPlay == 7) && - !scumm_stricmp(_curTotFileArray[newPos], "gob06.tot")) + !scumm_stricmp(_environments->getTotFile(newPos), "gob06.tot")) return; - curBackupPos = _curBackupPos; - backupedCount = _backupedCount; - if (_curBackupPos == _backupedCount) { - _cursorHotspotXArray[_backupedCount] = _vm->_draw->_cursorHotspotXVar; - _cursorHotspotYArray[_backupedCount] = _vm->_draw->_cursorHotspotYVar; - _totTextDataArray[_backupedCount] = _totTextData; - _totFileDataArray[_backupedCount] = _totFileData; - _totResourceTableArray[_backupedCount] = _totResourceTable; - _extTableArray[_backupedCount] = _extTable; - _extHandleArray[_backupedCount] = _extHandle; - _imFileDataArray[_backupedCount] = _imFileData; - _variablesArray[_backupedCount] = _vm->_inter->_variables; - strcpy(_curTotFileArray[_backupedCount], _curTotFile); - _backupedCount++; - } - _curBackupPos -= index; - if (index >= 0) - _curBackupPos--; - - _vm->_draw->_cursorHotspotXVar = _cursorHotspotXArray[_curBackupPos]; - _vm->_draw->_cursorHotspotYVar = _cursorHotspotYArray[_curBackupPos]; - _totTextData = _totTextDataArray[_curBackupPos]; - _totFileData = _totFileDataArray[_curBackupPos]; - _totResourceTable = _totResourceTableArray[_curBackupPos]; - _imFileData = _imFileDataArray[_curBackupPos]; - _extTable = _extTableArray[_curBackupPos]; - _extHandle = _extHandleArray[_curBackupPos]; - _vm->_inter->_variables = _variablesArray[_curBackupPos]; - strcpy(_curTotFile, _curTotFileArray[_curBackupPos]); - strcpy(_curExtFile, _curTotFile); - _curExtFile[strlen(_curExtFile) - 4] = '\0'; - strcat(_curExtFile, ".EXT"); - - if (_vm->_inter->_terminate != 0) - return; + curBackupPos = _curEnvironment; + backupedCount = _numEnvironments; + if (_curEnvironment == _numEnvironments) + _environments->set(_numEnvironments++); - _vm->_game->pushCollisions(0); - _vm->_game->playTot(skipPlay); + _curEnvironment -= index; + if (index >= 0) + _curEnvironment--; - if (_vm->_inter->_terminate != 2) - _vm->_inter->_terminate = 0; + clearUnusedEnvironment(); - _vm->_game->popCollisions(); - - _curBackupPos = curBackupPos; - _backupedCount = backupedCount; - _vm->_draw->_cursorHotspotXVar = _cursorHotspotXArray[_curBackupPos]; - _vm->_draw->_cursorHotspotYVar = _cursorHotspotYArray[_curBackupPos]; - _totTextData = _totTextDataArray[_curBackupPos]; - _totFileData = _totFileDataArray[_curBackupPos]; - _totResourceTable = _totResourceTableArray[_curBackupPos]; - _extTable = _extTableArray[_curBackupPos]; - _extHandle = _extHandleArray[_curBackupPos]; - _imFileData = _imFileDataArray[_curBackupPos]; - _vm->_inter->_variables = _variablesArray[_curBackupPos]; - strcpy(_curTotFile, _curTotFileArray[_curBackupPos]); - strcpy(_curExtFile, _curTotFile); - _curExtFile[strlen(_curExtFile) - 4] = '\0'; - strcat(_curExtFile, ".EXT"); -} + _environments->get(_curEnvironment); -int16 Game::openLocTextFile(char *locTextFile, int language) { - int n; - - n = strlen(locTextFile); - if (n < 4) - return -1; - - locTextFile[n - 4] = 0; - switch (language) { - case 0: - strcat(locTextFile, ".dat"); - break; - case 1: - strcat(locTextFile, ".all"); - break; - case 3: - strcat(locTextFile, ".esp"); - break; - case 4: - strcat(locTextFile, ".ita"); - break; - case 5: - strcat(locTextFile, ".usa"); - break; - case 6: - strcat(locTextFile, ".ndl"); - break; - case 7: - strcat(locTextFile, ".kor"); - break; - case 8: - strcat(locTextFile, ".isr"); - break; - default: - strcat(locTextFile, ".ang"); - break; + if (_vm->_inter->_terminate != 0) { + clearUnusedEnvironment(); + return; } - return _vm->_dataIO->openData(locTextFile); -} - -byte *Game::loadLocTexts(int32 *dataSize) { - char locTextFile[20]; - int16 handle; - int i; - - strcpy(locTextFile, _curTotFile); - - handle = openLocTextFile(locTextFile, _vm->_global->_languageWanted); - if (handle >= 0) { - - _foundTotLoc = true; - _vm->_global->_language = _vm->_global->_languageWanted; - - } else if (!_foundTotLoc) { - bool found = false; - - if (_vm->_global->_languageWanted == 2) { - handle = openLocTextFile(locTextFile, 5); - if (handle >= 0) { - _vm->_global->_language = 5; - found = true; - } - } else if (_vm->_global->_languageWanted == 5) { - handle = openLocTextFile(locTextFile, 2); - if (handle >= 0) { - _vm->_global->_language = 2; - found = true; - } - } - if (!found) { - for (i = 0; i < 10; i++) { - handle = openLocTextFile(locTextFile, i); - if (handle >= 0) { - _vm->_global->_language = i; - break; - } - } - } - - } + pushCollisions(0); + playTot(skipPlay); - debugC(1, kDebugFileIO, "Using language %d for %s", - _vm->_global->_language, _curTotFile); + if (_vm->_inter->_terminate != 2) + _vm->_inter->_terminate = 0; - if (handle >= 0) { - _vm->_dataIO->closeData(handle); + popCollisions(); - if (dataSize) - *dataSize = _vm->_dataIO->getDataSize(locTextFile); + clearUnusedEnvironment(); - return _vm->_dataIO->getData(locTextFile); - } - return 0; + _curEnvironment = curBackupPos; + _numEnvironments = backupedCount; + _environments->get(_curEnvironment); } void Game::setCollisions(byte arg_0) { - byte *savedIP; uint16 left; uint16 top; uint16 width; @@ -783,12 +515,12 @@ void Game::setCollisions(byte arg_0) { if (((collArea->id & 0xC000) != 0x8000) || (collArea->funcSub == 0)) continue; - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + collArea->funcSub; - left = _vm->_parse->parseValExpr(); - top = _vm->_parse->parseValExpr(); - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + _script->call(collArea->funcSub); + + left = _script->readValExpr(); + top = _script->readValExpr(); + width = _script->readValExpr(); + height = _script->readValExpr(); if ((_vm->_draw->_renderFlags & RENDERFLAG_CAPTUREPOP) && (left != 0xFFFF)) { left += _vm->_draw->_backDeltaX; @@ -807,16 +539,15 @@ void Game::setCollisions(byte arg_0) { collArea->top = top; collArea->right = left + width - 1; collArea->bottom = top + height - 1; - _vm->_global->_inter_execPtr = savedIP; + + _script->pop(); } } void Game::collSub(uint16 offset) { - byte *savedIP; int16 collStackSize; - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + offset; + _script->call(offset); _shouldPushColls = 1; collStackSize = _collStackSize; @@ -827,7 +558,9 @@ void Game::collSub(uint16 offset) { popCollisions(); _shouldPushColls = 0; - _vm->_global->_inter_execPtr = savedIP; + + _script->pop(); + setCollisions(); } @@ -852,4 +585,16 @@ void Game::collAreaSub(int16 index, int8 enter) { } } +void Game::clearUnusedEnvironment() { + if (!_environments->has(_script)) { + delete _script; + _script = 0; + } + if (!_environments->has(_resources)) { + delete _resources; + _resources = 0; + } + +} + } // End of namespace Gob diff --git a/engines/gob/game.h b/engines/gob/game.h index 3264288a32..ead4a56492 100644 --- a/engines/gob/game.h +++ b/engines/gob/game.h @@ -26,10 +26,45 @@ #ifndef GOB_GAME_H #define GOB_GAME_H -#include "gob/variables.h" - namespace Gob { +class Script; +class Resources; +class Variables; + +class Environments { +public: + static const uint8 kEnvironmentCount = 5; + + Environments(GobEngine *vm); + ~Environments(); + + void set(uint8 env); + void get(uint8 env) const; + + const char *getTotFile(uint8 env) const; + + bool has(Variables *variables, uint8 startEnv = 0, int16 except = -1) const; + bool has(Script *script , uint8 startEnv = 0, int16 except = -1) const; + bool has(Resources *resources, uint8 startEnv = 0, int16 except = -1) const; + + void clear(); + +private: + struct Environment { + int16 cursorHotspotX; + int16 cursorHotspotY; + char curTotFile[14]; + Variables *variables; + Script *script; + Resources *resources; + }; + + GobEngine *_vm; + + Environment *_environments; +}; + class Game { public: @@ -46,20 +81,7 @@ public: uint16 funcEnter; uint16 funcLeave; uint16 funcSub; - byte *totFileData; - } PACKED_STRUCT; - -#define szGame_TotTextItem (2 + 2) - struct TotTextItem { - int16 offset; - int16 size; - } PACKED_STRUCT; - -#define szGame_TotTextTable (2) - struct TotTextTable { - int16 itemsCount; - TotTextItem *items; - byte *dataPtr; + Script *script; } PACKED_STRUCT; struct InputDesc { @@ -74,18 +96,10 @@ public: Collision *_collisionAreas; Collision *_collStack[5]; - bool _foundTotLoc; - TotTextTable *_totTextData; + Script *_script; + Resources *_resources; char _curTotFile[14]; - char _curExtFile[14]; - - byte *_imFileData; - byte *_totFileData; - - int16 _extHandle; - int16 _lomHandle; - char _totToLoad[20]; int32 _startTimeKey; @@ -100,9 +114,6 @@ public: Game(GobEngine *vm); virtual ~Game(); - byte *loadExtData(int16 dataId, int16 *pResWidth, int16 *pResHeight, uint32 *dataSize = 0); - byte *loadTotResource(int16 id, int16 *dataSize = 0, int16 *width = 0, int16 *height = 0); - void capturePush(int16 left, int16 top, int16 width, int16 height); void capturePop(char doDraw); @@ -142,42 +153,6 @@ public: virtual void popCollisions(void) = 0; protected: -#include "common/pack-start.h" // START STRUCT PACKING - -#define szGame_TotResItem (4 + 2 + 2 + 2) - struct TotResItem { - int32 offset; // if > 0, then offset from end of resource table. - // If < 0, then -offset-1 is index in .IM file table - int16 size; - int16 width; - int16 height; - } PACKED_STRUCT; - -#define szGame_TotResTable (2 + 1) - struct TotResTable { - int16 itemsCount; - byte unknown; - TotResItem *items; - byte *dataPtr; - } PACKED_STRUCT; - -#define szGame_ExtItem (4 + 2 + 2 + 2) - struct ExtItem { - int32 offset; // offset from the table end - uint16 size; - int16 width; // width & 0x7FFF: width, width & 0x8000: pack flag - int16 height; // not zero - } PACKED_STRUCT; - -#define szGame_ExtTable (2 + 1) - struct ExtTable { - int16 itemsCount; - byte unknown; - ExtItem *items; - } PACKED_STRUCT; - -#include "common/pack-end.h" // END STRUCT PACKING - int16 _lastCollKey; int16 _lastCollAreaIndex; int16 _lastCollId; @@ -190,10 +165,6 @@ protected: char _tempStr[256]; - TotResTable *_totResourceTable; - ExtTable *_extTable; - char _curImaFile[18]; - int16 _collStackSize; int16 _collStackElemSizes[5]; @@ -206,35 +177,22 @@ protected: char _collStr[256]; // For totSub() - int8 _backupedCount; - int8 _curBackupPos; - int16 _cursorHotspotXArray[5]; - int16 _cursorHotspotYArray[5]; - TotTextTable *_totTextDataArray[5]; - byte *_totFileDataArray[5]; - TotResTable *_totResourceTableArray[5]; - ExtTable *_extTableArray[5]; - int16 _extHandleArray[5]; - byte *_imFileDataArray[5]; - Variables *_variablesArray[5]; - char _curTotFileArray[5][14]; + int8 _curEnvironment; + int8 _numEnvironments; + Environments *_environments; GobEngine *_vm; virtual int16 adjustKey(int16 key); - byte *loadLocTexts(int32 *dataSize = 0); - int32 loadTotFile(const char *path); - void loadExtTable(void); - void loadImFile(void); - void collAreaSub(int16 index, int8 enter); - int16 openLocTextFile(char *locTextFile, int language); virtual void setCollisions(byte arg_0 = 1); virtual void collSub(uint16 offset); virtual int16 checkMousePoint(int16 all, int16 *resId, int16 *resIndex) = 0; + + void clearUnusedEnvironment(); }; class Game_v1 : public Game { diff --git a/engines/gob/game_fascin.cpp b/engines/gob/game_fascin.cpp index 8e77141ce6..38ad03f0f8 100644 --- a/engines/gob/game_fascin.cpp +++ b/engines/gob/game_fascin.cpp @@ -35,7 +35,6 @@ #include "gob/goblin.h" #include "gob/inter.h" #include "gob/mult.h" -#include "gob/parse.h" #include "gob/scenery.h" #include "gob/video.h" #include "gob/videoplayer.h" diff --git a/engines/gob/game_v1.cpp b/engines/gob/game_v1.cpp index ad24d7d9c6..87dc78e3b1 100644 --- a/engines/gob/game_v1.cpp +++ b/engines/gob/game_v1.cpp @@ -32,11 +32,12 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/dataio.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/draw.h" #include "gob/inter.h" #include "gob/mult.h" #include "gob/video.h" -#include "gob/parse.h" #include "gob/scenery.h" #include "gob/sound/sound.h" @@ -49,12 +50,12 @@ void Game_v1::playTot(int16 skipPlay) { int16 _captureCounter; int16 breakFrom; int16 nestLevel; - int32 variablesCount; int16 *oldNestLevel = _vm->_inter->_nestLevel; int16 *oldBreakFrom = _vm->_inter->_breakFromLevel; int16 *oldCaptureCounter = _vm->_scenery->_pCaptureCounter; - byte *savedIP = _vm->_global->_inter_execPtr; + + _script->push(); _vm->_inter->_nestLevel = &nestLevel; _vm->_inter->_breakFromLevel = &breakFrom; @@ -93,86 +94,23 @@ void Game_v1::playTot(int16 skipPlay) { for (int i = 0; i < 20; i++) freeSoundSlot(i); - _totTextData = 0; - _totResourceTable = 0; - _imFileData = 0; - _extTable = 0; - _extHandle = -1; - _totToLoad[0] = 0; - if ((_curTotFile[0] == 0) && (_totFileData == 0)) + if ((_curTotFile[0] == 0) && !_script->isLoaded()) break; - loadTotFile(_curTotFile); - if (_totFileData == 0) { + if (!_script->load(_curTotFile)) { _vm->_draw->blitCursor(); break; } - strcpy(_curImaFile, _curTotFile); - strcpy(_curExtFile, _curTotFile); - - _curImaFile[strlen(_curImaFile) - 4] = 0; - strcat(_curImaFile, ".ima"); - - _curExtFile[strlen(_curExtFile) - 4] = 0; - strcat(_curExtFile, ".ext"); - - debugC(4, kDebugFileIO, "IMA: %s", _curImaFile); - debugC(4, kDebugFileIO, "EXT: %s", _curExtFile); - - byte *filePtr = _totFileData + 0x30; - - _totTextData = 0; - if (READ_LE_UINT32(filePtr) != (uint32) -1) { - _totTextData = new TotTextTable; - _totTextData->dataPtr = - (_totFileData + READ_LE_UINT32(_totFileData + 0x30)); - Common::MemoryReadStream totTextData(_totTextData->dataPtr, - 4294967295U); - - _totTextData->itemsCount = totTextData.readSint16LE(); - - _totTextData->items = new TotTextItem[_totTextData->itemsCount]; - for (int i = 0; i < _totTextData->itemsCount; ++i) { - _totTextData->items[i].offset = totTextData.readSint16LE(); - _totTextData->items[i].size = totTextData.readSint16LE(); - } - } - - filePtr = _totFileData + 0x34; - _totResourceTable = 0; - if (READ_LE_UINT32(filePtr) != (uint32) -1) { - _totResourceTable = new TotResTable; - _totResourceTable->dataPtr = - _totFileData + READ_LE_UINT32( _totFileData + 0x34); - Common::MemoryReadStream totResTable(_totResourceTable->dataPtr, - 4294967295U); - - _totResourceTable->itemsCount = totResTable.readSint16LE(); - _totResourceTable->unknown = totResTable.readByte(); - - _totResourceTable->items = - new TotResItem[_totResourceTable->itemsCount]; - for (int i = 0; i < _totResourceTable->itemsCount; ++i) { - _totResourceTable->items[i].offset = totResTable.readSint32LE(); - _totResourceTable->items[i].size = totResTable.readSint16LE(); - _totResourceTable->items[i].width = totResTable.readSint16LE(); - _totResourceTable->items[i].height = totResTable.readSint16LE(); - } - } - - loadImFile(); - loadExtTable(); + _resources->load(_curTotFile); - _vm->_global->_inter_animDataSize = - READ_LE_UINT16(_totFileData + 0x38); + _vm->_global->_inter_animDataSize = _script->getAnimDataSize(); if (!_vm->_inter->_variables) - _vm->_inter->allocateVars(READ_LE_UINT16(_totFileData + 0x2C)); + _vm->_inter->allocateVars(_script->getVariablesCount() & 0xFFFF); - _vm->_global->_inter_execPtr = _totFileData; - _vm->_global->_inter_execPtr += READ_LE_UINT32(_totFileData + 0x64); + _script->seek(_script->getFunctionOffset(TOTFile::kFunctionStart)); _vm->_inter->renewTimeInVars(); @@ -182,39 +120,16 @@ void Game_v1::playTot(int16 skipPlay) { WRITE_VAR(16, _vm->_global->_language); _vm->_inter->callSub(2); + _script->setFinished(false); if (_totToLoad[0] != 0) _vm->_inter->_terminate = 0; - variablesCount = READ_LE_UINT32(_totFileData + 0x2C); _vm->_draw->blitInvalidated(); - delete[] _totFileData; - _totFileData = 0; - - if (_totTextData) { - delete[] _totTextData->items; - delete _totTextData; - } - _totTextData = 0; - - if (_totResourceTable) { - delete[] _totResourceTable->items; - delete _totResourceTable; - } - _totResourceTable = 0; - - delete[] _imFileData; - _imFileData = 0; - if (_extTable) - delete[] _extTable->items; - delete _extTable; - _extTable = 0; + _script->unload(); - if (_extHandle >= 0) - _vm->_dataIO->closeData(_extHandle); - - _extHandle = -1; + _resources->unload(); for (int i = 0; i < *_vm->_scenery->_pCaptureCounter; i++) capturePop(0); @@ -241,7 +156,8 @@ void Game_v1::playTot(int16 skipPlay) { _vm->_inter->_nestLevel = oldNestLevel; _vm->_inter->_breakFromLevel = oldBreakFrom; _vm->_scenery->_pCaptureCounter = oldCaptureCounter; - _vm->_global->_inter_execPtr = savedIP; + + _script->pop(); } void Game_v1::clearCollisions() { @@ -279,7 +195,7 @@ int16 Game_v1::addNewCollision(int16 id, uint16 left, uint16 top, ptr->funcEnter = funcEnter; ptr->funcLeave = funcLeave; ptr->funcSub = funcSub; - ptr->totFileData = 0; + ptr->script = 0; return i; } @@ -331,7 +247,6 @@ void Game_v1::popCollisions(void) { int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, int16 *pResId, int16 *pResIndex) { - byte *savedIP; int16 resIndex; int16 key; int16 oldIndex; @@ -357,12 +272,9 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, _lastCollKey = checkMousePoint(1, &_lastCollId, &_lastCollAreaIndex); if ((_lastCollKey != 0) && ((_lastCollId & 0x8000) != 0)) { - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + - _collisionAreas[_lastCollAreaIndex].funcEnter; - + _script->call(_collisionAreas[_lastCollAreaIndex].funcEnter); _vm->_inter->funcBlock(0); - _vm->_global->_inter_execPtr = savedIP; + _script->pop(); } } @@ -423,12 +335,10 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, if ((_lastCollKey != 0) && (_collisionAreas[_lastCollAreaIndex].funcLeave != 0)) { - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + - _collisionAreas[_lastCollAreaIndex].funcLeave; + _script->call(_collisionAreas[_lastCollAreaIndex].funcLeave); _vm->_inter->funcBlock(0); - _vm->_global->_inter_execPtr = savedIP; + _script->pop(); } _lastCollKey = 0; @@ -463,12 +373,11 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, if ((_lastCollKey != 0) && (_collisionAreas[_lastCollAreaIndex].funcLeave != 0)) { - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + - _collisionAreas[_lastCollAreaIndex].funcLeave; + _script->call(_collisionAreas[_lastCollAreaIndex].funcLeave); _vm->_inter->funcBlock(0); - _vm->_global->_inter_execPtr = savedIP; + _script->pop(); + } _lastCollKey = 0; return key; @@ -476,24 +385,22 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, if ((_lastCollKey != 0) && (_collisionAreas[_lastCollAreaIndex].funcLeave != 0)) { - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + - _collisionAreas[_lastCollAreaIndex].funcLeave; + _script->call(_collisionAreas[_lastCollAreaIndex].funcLeave); _vm->_inter->funcBlock(0); - _vm->_global->_inter_execPtr = savedIP; + _script->pop(); + } _lastCollKey = checkMousePoint(1, &_lastCollId, &_lastCollAreaIndex); if ((_lastCollKey != 0) && ((_lastCollId & 0x8000) != 0)) { - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + - _collisionAreas[_lastCollAreaIndex].funcEnter; + _script->call(_collisionAreas[_lastCollAreaIndex].funcEnter); _vm->_inter->funcBlock(0); - _vm->_global->_inter_execPtr = savedIP; + _script->pop(); + } } else { @@ -507,23 +414,22 @@ int16 Game_v1::checkCollisions(byte handleMouse, int16 deltaTime, if (key != _lastCollKey) { if ((_lastCollKey != 0) && ((oldId & 0x8000) != 0)) { - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + - _collisionAreas[oldIndex].funcLeave; + _script->call(_collisionAreas[oldIndex].funcLeave); _vm->_inter->funcBlock(0); - _vm->_global->_inter_execPtr = savedIP; + _script->pop(); + } _lastCollKey = key; if ((_lastCollKey != 0) && ((_lastCollId & 0x8000) != 0)) { - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + - _collisionAreas[_lastCollAreaIndex].funcEnter; + _script->call(_collisionAreas[_lastCollAreaIndex].funcEnter); _vm->_inter->funcBlock(0); - _vm->_global->_inter_execPtr = savedIP; + _script->pop(); + } + } } } @@ -588,7 +494,6 @@ void Game_v1::collisionsBlock(void) { int16 array[250]; byte count; int16 collResId; - byte *startIP; int16 curCmd; int16 cmd; int16 cmdHigh; @@ -615,27 +520,27 @@ void Game_v1::collisionsBlock(void) { int16 collStackPos; Collision *collPtr; uint32 timeKey; - byte *savedIP; if (_shouldPushColls) pushCollisions(1); collResId = -1; - _vm->_global->_inter_execPtr++; - count = *_vm->_global->_inter_execPtr++; - _handleMouse = _vm->_global->_inter_execPtr[0]; - deltaTime = 1000 * _vm->_global->_inter_execPtr[1]; - descIndex2 = _vm->_global->_inter_execPtr[2]; - stackPos2 = _vm->_global->_inter_execPtr[3]; - descIndex = _vm->_global->_inter_execPtr[4]; + _script->skip(1); + count = _script->readByte(); + _handleMouse = _script->readByte(); + deltaTime = 1000 * _script->readByte(); + descIndex2 = _script->readByte(); + stackPos2 = _script->readByte(); + descIndex = _script->readByte(); if ((stackPos2 != 0) || (descIndex != 0)) deltaTime /= 100; timeVal = deltaTime; - _vm->_global->_inter_execPtr += 6; + _script->skip(1); + + uint32 startPos = _script->pos(); - startIP = _vm->_global->_inter_execPtr; WRITE_VAR(16, 0); var_22 = 0; index = 0; @@ -643,26 +548,25 @@ void Game_v1::collisionsBlock(void) { for (curCmd = 0; curCmd < count; curCmd++) { array[curCmd] = 0; - cmd = *_vm->_global->_inter_execPtr++; + cmd = _script->readByte(); if ((cmd & 0x40) != 0) { cmd -= 0x40; - cmdHigh = *_vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr++; + cmdHigh = _script->readByte(); cmdHigh <<= 8; } else cmdHigh = 0; if ((cmd & 0x80) != 0) { - left = _vm->_parse->parseValExpr(); - top = _vm->_parse->parseValExpr(); - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + left = _script->readValExpr(); + top = _script->readValExpr(); + width = _script->readValExpr(); + height = _script->readValExpr(); } else { - left = _vm->_inter->load16(); - top = _vm->_inter->load16(); - width = _vm->_inter->load16(); - height = _vm->_inter->load16(); + left = _script->readUint16(); + top = _script->readUint16(); + width = _script->readUint16(); + height = _script->readUint16(); } cmd &= 0x7F; @@ -680,16 +584,16 @@ void Game_v1::collisionsBlock(void) { _vm->_util->clearKeyBuf(); var_22 = 1; - key = _vm->_parse->parseVarIndex(); - descArray[index].fontIndex = _vm->_inter->load16(); - descArray[index].backColor = *_vm->_global->_inter_execPtr++; - descArray[index].frontColor = *_vm->_global->_inter_execPtr++; + key = _script->readVarIndex(); + descArray[index].fontIndex = _script->readInt16(); + descArray[index].backColor = _script->readByte(); + descArray[index].frontColor = _script->readByte(); if ((cmd < 5) || (cmd > 8)) { descArray[index].ptr = 0; } else { - descArray[index].ptr = _vm->_global->_inter_execPtr + 2; - _vm->_global->_inter_execPtr += _vm->_inter->load16(); + descArray[index].ptr = _script->getData() + _script->pos() + 2; + _script->skip(_script->readInt16()); } if (left == 0xFFFF) @@ -698,12 +602,9 @@ void Game_v1::collisionsBlock(void) { if ((cmd & 1) == 0) { addNewCollision(curCmd + 0x8000, left, top, left + width * _vm->_draw->_fonts[descArray[index].fontIndex]->itemWidth - 1, - top + height - 1, cmd, key, 0, - _vm->_global->_inter_execPtr - _totFileData); + top + height - 1, cmd, key, 0, _script->pos()); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); } else { addNewCollision(curCmd + 0x8000, left, top, left + width * _vm->_draw->_fonts[descArray[index].fontIndex]->itemWidth - 1, @@ -713,18 +614,15 @@ void Game_v1::collisionsBlock(void) { break; case 21: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16() & 3; + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16() & 3; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, - (flags << 4) + cmdHigh + 2, key, - _vm->_global->_inter_execPtr - _totFileData, 0); + (flags << 4) + cmdHigh + 2, key, _script->pos(), 0); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 20: @@ -732,61 +630,48 @@ void Game_v1::collisionsBlock(void) { // Fall through to case 2 case 2: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16() & 3; + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16() & 3; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, - (flags << 4) + cmdHigh + 2, key, 0, - _vm->_global->_inter_execPtr - _totFileData); + (flags << 4) + cmdHigh + 2, key, 0, _script->pos()); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 0: - _vm->_global->_inter_execPtr += 6; - startIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(6); + startPos = _script->pos(); + _script->skip(_script->peekUint16(2) + 2); key = curCmd + 0xA000; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, cmd + cmdHigh, key, - startIP - _totFileData, - _vm->_global->_inter_execPtr - _totFileData); + startPos, _script->pos()); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 1: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16() & 3; - - startIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16() & 3; + + startPos = _script->pos(); + _script->skip(_script->peekUint16(2) + 2); if (key == 0) key = curCmd + 0xA000; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, (flags << 4) + cmd + cmdHigh, key, - startIP - _totFileData, - _vm->_global->_inter_execPtr - _totFileData); + startPos, _script->pos()); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; } } @@ -895,9 +780,11 @@ void Game_v1::collisionsBlock(void) { if (collPtr->funcLeave != 0) { timeKey = _vm->_util->getTimeKey(); - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = - _totFileData + collPtr->funcLeave; + + uint32 savedPos = _script->pos(); + + _script->seek(collPtr->funcLeave); + _shouldPushColls = 1; savedCollStackSize = _collStackSize; _vm->_inter->funcBlock(0); @@ -906,7 +793,8 @@ void Game_v1::collisionsBlock(void) { popCollisions(); _shouldPushColls = 0; - _vm->_global->_inter_execPtr = savedIP; + + _script->seek(savedPos); deltaTime = timeVal - (_vm->_util->getTimeKey() - timeKey); @@ -986,9 +874,9 @@ void Game_v1::collisionsBlock(void) { WRITE_VAR(16, array[(uint16) _activeCollResId & ~0x8000]); if (_collisionAreas[_activeCollIndex].funcEnter != 0) { - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + - _collisionAreas[_activeCollIndex].funcEnter; + uint32 savedPos = _script->pos(); + + _script->seek(_collisionAreas[_activeCollIndex].funcEnter); _shouldPushColls = 1; @@ -997,7 +885,8 @@ void Game_v1::collisionsBlock(void) { if (collStackPos != _collStackSize) popCollisions(); _shouldPushColls = 0; - _vm->_global->_inter_execPtr = savedIP; + + _script->seek(savedPos); } WRITE_VAR(16, 0); @@ -1071,10 +960,8 @@ void Game_v1::collisionsBlock(void) { WRITE_VAR(17, 1); } - savedIP = 0; if (!_vm->_inter->_terminate) { - savedIP = _totFileData + - _collisionAreas[_activeCollIndex].funcLeave; + _script->seek(_collisionAreas[_activeCollIndex].funcLeave); WRITE_VAR(2, _vm->_global->_inter_mouseX); WRITE_VAR(3, _vm->_global->_inter_mouseY); @@ -1082,12 +969,11 @@ void Game_v1::collisionsBlock(void) { if (VAR(16) == 0) WRITE_VAR(16, array[(uint16) _activeCollResId & ~0x8000]); - } + } else + _script->setFinished(true); for (curCmd = 0; curCmd < count; curCmd++) freeCollision(curCmd + 0x8000); - - _vm->_global->_inter_execPtr = savedIP; } int16 Game_v1::multiEdit(int16 time, int16 index, int16 *pCurPos, diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp index e9656efa32..08184e73d0 100644 --- a/engines/gob/game_v2.cpp +++ b/engines/gob/game_v2.cpp @@ -32,11 +32,12 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/dataio.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/draw.h" #include "gob/goblin.h" #include "gob/inter.h" #include "gob/mult.h" -#include "gob/parse.h" #include "gob/scenery.h" #include "gob/video.h" #include "gob/videoplayer.h" @@ -55,15 +56,12 @@ void Game_v2::playTot(int16 skipPlay) { int16 _captureCounter; int16 breakFrom; int16 nestLevel; - int32 totSize; - byte *filePtr; - byte *savedIP; - bool totTextLoc; oldNestLevel = _vm->_inter->_nestLevel; oldBreakFrom = _vm->_inter->_breakFromLevel; oldCaptureCounter = _vm->_scenery->_pCaptureCounter; - savedIP = _vm->_global->_inter_execPtr; + + _script->push(); _vm->_inter->_nestLevel = &nestLevel; _vm->_inter->_breakFromLevel = &breakFrom; @@ -94,125 +92,30 @@ void Game_v2::playTot(int16 skipPlay) { } else _vm->_inter->initControlVars(0); - _totTextData = 0; - _totResourceTable = 0; - _imFileData = 0; - _extTable = 0; - _extHandle = -1; - _vm->_draw->_cursorHotspotXVar = -1; _totToLoad[0] = 0; - if ((_curTotFile[0] == 0) && (_totFileData == 0)) + if ((_curTotFile[0] == 0) && (!_script->isLoaded())) break; - totSize = loadTotFile(_curTotFile); - if (skipPlay == -2) { _vm->_vidPlayer->primaryClose(); skipPlay = 0; } - if (_totFileData == 0) { + if (!_script->load(_curTotFile)) { _vm->_draw->blitCursor(); _vm->_inter->_terminate = 2; break; } - strcpy(_curImaFile, _curTotFile); - strcpy(_curExtFile, _curTotFile); - - _curImaFile[strlen(_curImaFile) - 4] = 0; - strcat(_curImaFile, ".ima"); - - _curExtFile[strlen(_curExtFile) - 4] = 0; - strcat(_curExtFile, ".ext"); - - debugC(4, kDebugFileIO, "IMA: %s", _curImaFile); - debugC(4, kDebugFileIO, "EXT: %s", _curExtFile); - - filePtr = _totFileData + 0x30; - - _totTextData = 0; - totTextLoc = false; - if (READ_LE_UINT32(filePtr) != (uint32) -1) { - _totTextData = new TotTextTable; - - int32 size; - - if (READ_LE_UINT32(filePtr) == 0) { - _totTextData->dataPtr = loadLocTexts(&size); - totTextLoc = true; - } else { - _totTextData->dataPtr = - (_totFileData + READ_LE_UINT32(_totFileData + 0x30)); - size = totSize; - _vm->_global->_language = _vm->_global->_languageWanted; - } - - _totTextData->items = 0; - if (_totTextData->dataPtr != 0) { - Common::MemoryReadStream totTextData(_totTextData->dataPtr, - 4294967295U); - _totTextData->itemsCount = totTextData.readSint16LE() & 0x3FFF; - - _totTextData->items = new TotTextItem[_totTextData->itemsCount]; - for (int i = 0; i < _totTextData->itemsCount; ++i) { - _totTextData->items[i].offset = totTextData.readSint16LE(); - _totTextData->items[i].size = totTextData.readSint16LE(); - } - } - } - - filePtr = _totFileData + 0x34; - _totResourceTable = 0; - int32 resSize; - if (READ_LE_UINT32(filePtr) != (uint32) -1) { - _totResourceTable = new TotResTable; - _totResourceTable->dataPtr = - _totFileData + READ_LE_UINT32(_totFileData + 0x34); - Common::MemoryReadStream totResTable(_totResourceTable->dataPtr, - 4294967295U); - - _totResourceTable->itemsCount = totResTable.readSint16LE(); - resSize = _totResourceTable->itemsCount * szGame_TotResItem + szGame_TotResTable; - if (totSize > (resSize + 0x34)) { - _totResourceTable->unknown = totResTable.readByte(); - - _totResourceTable->items = - new TotResItem[_totResourceTable->itemsCount]; - for (int i = 0; i < _totResourceTable->itemsCount; ++i) { - _totResourceTable->items[i].offset = totResTable.readSint32LE(); - _totResourceTable->items[i].size = totResTable.readSint16LE(); - _totResourceTable->items[i].width = totResTable.readSint16LE(); - _totResourceTable->items[i].height = totResTable.readSint16LE(); - } - } - else { - // WORKAROUND: In the original asm, _totResourceTable is - // only assigned in playTot and evaluated later, right - // before using it. In the Gobliins 2 demo, there is a - // dummy tot that loads another tot, overwriting the dummy - // pointer with the real one. - debugC(1, kDebugFileIO, - "Attempted to load invalid resource table (size = %d, totSize = %d)", - resSize, totSize); - delete _totResourceTable; - _totResourceTable = 0; - } - } - - loadImFile(); - loadExtTable(); + _resources->load(_curTotFile); - _vm->_global->_inter_animDataSize = - READ_LE_UINT16(_totFileData + 0x38); + _vm->_global->_inter_animDataSize = _script->getAnimDataSize(); if (!_vm->_inter->_variables) - _vm->_inter->allocateVars(READ_LE_UINT16(_totFileData + 0x2C)); + _vm->_inter->allocateVars(_script->getVariablesCount() & 0xFFFF); - _vm->_global->_inter_execPtr = _totFileData; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_totFileData + 0x64); + _script->seek(_script->getFunctionOffset(TOTFile::kFunctionStart)); _vm->_inter->renewTimeInVars(); @@ -227,35 +130,10 @@ void Game_v2::playTot(int16 skipPlay) { _vm->_inter->_terminate = 0; _vm->_draw->blitInvalidated(); - delete[] _totFileData; - _totFileData = 0; - - if (_totTextData) { - delete[] _totTextData->items; - if (totTextLoc) - delete[] _totTextData->dataPtr; - delete _totTextData; - } - _totTextData = 0; - if (_totResourceTable) { - delete[] _totResourceTable->items; - delete _totResourceTable; - } - _totResourceTable = 0; - - delete[] _imFileData; - _imFileData = 0; - - if (_extTable) - delete[] _extTable->items; - delete _extTable; - _extTable = 0; - - if (_extHandle >= 0) - _vm->_dataIO->closeData(_extHandle); + _script->unload(); - _extHandle = -1; + _resources->unload(); for (int i = 0; i < *_vm->_scenery->_pCaptureCounter; i++) capturePop(0); @@ -282,9 +160,7 @@ void Game_v2::playTot(int16 skipPlay) { } else { _vm->_inter->initControlVars(0); _vm->_scenery->_pCaptureCounter = oldCaptureCounter; - _vm->_global->_inter_execPtr = _totFileData; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_totFileData + (skipPlay << 1) + 0x66); + _script->seek(_script->getFunctionOffset(skipPlay + 1)); _menuLevel++; _vm->_inter->callSub(2); @@ -299,7 +175,8 @@ void Game_v2::playTot(int16 skipPlay) { _vm->_inter->_nestLevel = oldNestLevel; _vm->_inter->_breakFromLevel = oldBreakFrom; _vm->_scenery->_pCaptureCounter = oldCaptureCounter; - _vm->_global->_inter_execPtr = savedIP; + + _script->pop(); } void Game_v2::clearCollisions() { @@ -337,7 +214,7 @@ int16 Game_v2::addNewCollision(int16 id, uint16 left, uint16 top, ptr->funcEnter = funcEnter; ptr->funcLeave = funcLeave; ptr->funcSub = funcSub; - ptr->totFileData = 0; + ptr->script = 0; return i; } @@ -604,7 +481,6 @@ void Game_v2::collisionsBlock(void) { int16 array[250]; byte count; int16 collResId; - byte *startIP; int16 curCmd; int16 cmd; int16 cmdHigh; @@ -621,7 +497,6 @@ void Game_v2::collisionsBlock(void) { int16 stackPos2; int16 descIndex; int16 timeVal; - int16 offsetIP; char *str; int16 i; int16 counter; @@ -631,8 +506,9 @@ void Game_v2::collisionsBlock(void) { Collision *collPtr; Collision *collArea; int16 timeKey; - byte *savedIP; byte collAreaStart; + uint32 startPos; + uint32 offsetPos; if (_shouldPushColls) pushCollisions(0); @@ -645,21 +521,22 @@ void Game_v2::collisionsBlock(void) { _shouldPushColls = 0; collResId = -1; - _vm->_global->_inter_execPtr++; - count = *_vm->_global->_inter_execPtr++; + _script->skip(1); + count = _script->readByte(); - _handleMouse = _vm->_global->_inter_execPtr[0]; - deltaTime = 1000 * _vm->_global->_inter_execPtr[1]; - stackPos2 = _vm->_global->_inter_execPtr[3]; - descIndex = _vm->_global->_inter_execPtr[4]; + _handleMouse = _script->readByte(); + deltaTime = 1000 * _script->readByte(); + _script->skip(1); + stackPos2 = _script->readByte(); + descIndex = _script->readByte(); if ((stackPos2 != 0) || (descIndex != 0)) deltaTime /= 100; timeVal = deltaTime; - _vm->_global->_inter_execPtr += 6; + _script->skip(1); - startIP = _vm->_global->_inter_execPtr; + startPos = _script->pos(); WRITE_VAR(16, 0); var_1C = 0; @@ -668,28 +545,27 @@ void Game_v2::collisionsBlock(void) { for (curCmd = 0; curCmd < count; curCmd++) { array[curCmd] = 0; - cmd = *_vm->_global->_inter_execPtr++; + cmd = _script->readByte(); if ((cmd & 0x40) != 0) { cmd -= 0x40; - cmdHigh = *_vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr++; + cmdHigh = _script->readByte(); cmdHigh <<= 8; } else cmdHigh = 0; if ((cmd & 0x80) != 0) { - offsetIP = _vm->_global->_inter_execPtr - _totFileData; - left = _vm->_parse->parseValExpr(); - top = _vm->_parse->parseValExpr(); - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + offsetPos = _script->pos(); + left = _script->readValExpr(); + top = _script->readValExpr(); + width = _script->readValExpr(); + height = _script->readValExpr(); } else { - offsetIP = 0; - left = _vm->_inter->load16(); - top = _vm->_inter->load16(); - width = _vm->_inter->load16(); - height = _vm->_inter->load16(); + offsetPos = 0; + left = _script->readUint16(); + top = _script->readUint16(); + width = _script->readUint16(); + height = _script->readUint16(); } if ((_vm->_draw->_renderFlags & RENDERFLAG_CAPTUREPOP) && (left != 0xFFFF)) { @@ -712,46 +588,37 @@ void Game_v2::collisionsBlock(void) { switch (cmd) { case 0: - _vm->_global->_inter_execPtr += 6; - startIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(6); + startPos = _script->pos(); + _script->skip(_script->peekUint16(2) + 2); key = curCmd + 0xA000; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, - cmd + cmdHigh, key, startIP - _totFileData, - _vm->_global->_inter_execPtr - _totFileData, offsetIP); + cmd + cmdHigh, key, startPos, + _script->pos(), offsetPos); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 1: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16(); + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16(); - startIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + startPos = _script->pos(); + _script->skip(_script->peekUint16(2) + 2); if (key == 0) key = curCmd + 0xA000; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, - (flags << 4) + cmd + cmdHigh, key, startIP - _totFileData, - _vm->_global->_inter_execPtr - _totFileData, offsetIP); - - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + (flags << 4) + cmd + cmdHigh, key, startPos, + _script->pos(), offsetPos); + _script->skip(_script->peekUint16(2) + 2); break; case 3: @@ -764,23 +631,20 @@ void Game_v2::collisionsBlock(void) { case 10: _vm->_util->clearKeyBuf(); var_1C = 1; - key = _vm->_parse->parseVarIndex(); - descArray[index].fontIndex = _vm->_inter->load16(); - descArray[index].backColor = *_vm->_global->_inter_execPtr++; - descArray[index].frontColor = *_vm->_global->_inter_execPtr++; + key = _script->readVarIndex(); + descArray[index].fontIndex = _script->readInt16(); + descArray[index].backColor = _script->readByte(); + descArray[index].frontColor = _script->readByte(); if ((cmd >= 5) && (cmd <= 8)) { - descArray[index].ptr = _vm->_global->_inter_execPtr + 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr) + 2; + descArray[index].ptr = _script->getData() + _script->pos() + 2; + _script->skip(_script->peekUint16() + 2); } else descArray[index].ptr = 0; if (left == 0xFFFF) { if ((cmd & 1) == 0) { - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); } break; } @@ -789,11 +653,9 @@ void Game_v2::collisionsBlock(void) { addNewCollision(curCmd + 0x8000, left, top, left + width * _vm->_draw->_fonts[descArray[index].fontIndex]-> itemWidth - 1, top + height - 1, cmd, key, 0, - _vm->_global->_inter_execPtr - _totFileData); + _script->pos()); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); } else addNewCollision(curCmd + 0x8000, left, top, left + width * _vm->_draw->_fonts[descArray[index].fontIndex]-> itemWidth - 1, @@ -803,35 +665,31 @@ void Game_v2::collisionsBlock(void) { break; case 11: - _vm->_global->_inter_execPtr += 6; + _script->skip(6); for (i = 0; i < 150; i++) { if ((_collisionAreas[i].id & 0xF000) == 0xE000) { _collisionAreas[i].id &= 0xBFFF; _collisionAreas[i].funcEnter = - _vm->_global->_inter_execPtr - _totFileData; + _script->pos(); _collisionAreas[i].funcLeave = - _vm->_global->_inter_execPtr - _totFileData; + _script->pos(); } } - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 12: - _vm->_global->_inter_execPtr += 6; + _script->skip(6); for (i = 0; i < 150; i++) { if ((_collisionAreas[i].id & 0xF000) == 0xD000) { _collisionAreas[i].id &= 0xBFFF; _collisionAreas[i].funcEnter = - _vm->_global->_inter_execPtr - _totFileData; + _script->pos(); _collisionAreas[i].funcLeave = - _vm->_global->_inter_execPtr - _totFileData; + _script->pos(); } } - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 20: @@ -839,34 +697,30 @@ void Game_v2::collisionsBlock(void) { // Fall through to case 2 case 2: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16(); + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16(); addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, (flags << 4) + cmdHigh + 2, key, 0, - _vm->_global->_inter_execPtr - _totFileData, offsetIP); + _script->pos(), offsetPos); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 21: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16() & 3; + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16() & 3; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, (flags << 4) + cmdHigh + 2, key, - _vm->_global->_inter_execPtr - _totFileData, 0, offsetIP); + _script->pos(), 0, offsetPos); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; } @@ -1116,10 +970,8 @@ void Game_v2::collisionsBlock(void) { if (_handleMouse == 1) _vm->_draw->blitCursor(); - savedIP = 0; if (!_vm->_inter->_terminate) { - savedIP = _totFileData + - _collisionAreas[_activeCollIndex].funcLeave; + _script->seek(_collisionAreas[_activeCollIndex].funcLeave); _vm->_inter->storeMouse(); if (VAR(16) == 0) { @@ -1128,7 +980,8 @@ void Game_v2::collisionsBlock(void) { else WRITE_VAR(16, _activeCollResId & 0xFFF); } - } + } else + _script->setFinished(true); for (curCmd = 0; curCmd < count; curCmd++) freeCollision(curCmd + 0x8000); @@ -1138,8 +991,6 @@ void Game_v2::collisionsBlock(void) { ((_collisionAreas[i].id & 0xF000) == 0x9000)) _collisionAreas[i].id |= 0x4000; } - - _vm->_global->_inter_execPtr = savedIP; } int16 Game_v2::multiEdit(int16 time, int16 index, int16 *pCurPos, diff --git a/engines/gob/game_v6.cpp b/engines/gob/game_v6.cpp index 9d9bd1faa3..8d40d41acc 100644 --- a/engines/gob/game_v6.cpp +++ b/engines/gob/game_v6.cpp @@ -31,9 +31,10 @@ #include "gob/game.h" #include "gob/helper.h" #include "gob/global.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/inter.h" #include "gob/draw.h" -#include "gob/parse.h" namespace Gob { @@ -48,27 +49,17 @@ void Game_v6::totSub(int8 flags, const char *newTotFile) { if ((flags == 16) || (flags == 17)) warning("Urban Stub: Game_v6::totSub(), flags == %d", flags); - if (_backupedCount >= 5) + if (_numEnvironments >= Environments::kEnvironmentCount) return; - _cursorHotspotXArray[_backupedCount] = _vm->_draw->_cursorHotspotXVar; - _cursorHotspotYArray[_backupedCount] = _vm->_draw->_cursorHotspotYVar; - _totTextDataArray[_backupedCount] = _totTextData; - _totFileDataArray[_backupedCount] = _totFileData; - _totResourceTableArray[_backupedCount] = _totResourceTable; - _extTableArray[_backupedCount] = _extTable; - _extHandleArray[_backupedCount] = _extHandle; - _imFileDataArray[_backupedCount] = _imFileData; - _variablesArray[_backupedCount] = _vm->_inter->_variables; - strcpy(_curTotFileArray[_backupedCount], _curTotFile); - - curBackupPos = _curBackupPos; - _backupedCount++; - _curBackupPos = _backupedCount; - - _totTextData = 0; - _totFileData = 0; - _totResourceTable = 0; + _environments->set(_numEnvironments); + + curBackupPos = _curEnvironment; + _numEnvironments++; + _curEnvironment = _numEnvironments; + + _script = new Script(_vm); + _resources = new Resources(_vm); if (flags & 0x80) warning("Urban Stub: Game_v6::totSub(), flags & 0x80"); @@ -79,8 +70,10 @@ void Game_v6::totSub(int8 flags, const char *newTotFile) { strncpy0(_curTotFile, newTotFile, 9); strcat(_curTotFile, ".TOT"); - if (_vm->_inter->_terminate != 0) + if (_vm->_inter->_terminate != 0) { + clearUnusedEnvironment(); return; + } pushCollisions(0); @@ -99,22 +92,11 @@ void Game_v6::totSub(int8 flags, const char *newTotFile) { _vm->_inter->delocateVars(); } - _backupedCount--; - _curBackupPos = curBackupPos; - - _vm->_draw->_cursorHotspotXVar = _cursorHotspotXArray[_backupedCount]; - _vm->_draw->_cursorHotspotYVar = _cursorHotspotYArray[_backupedCount]; - _totTextData = _totTextDataArray[_backupedCount]; - _totFileData = _totFileDataArray[_backupedCount]; - _totResourceTable = _totResourceTableArray[_backupedCount]; - _extTable = _extTableArray[_backupedCount]; - _extHandle = _extHandleArray[_backupedCount]; - _imFileData = _imFileDataArray[_backupedCount]; - _vm->_inter->_variables = _variablesArray[_backupedCount]; - strcpy(_curTotFile, _curTotFileArray[_backupedCount]); - strcpy(_curExtFile, _curTotFile); - _curExtFile[strlen(_curExtFile) - 4] = '\0'; - strcat(_curExtFile, ".EXT"); + clearUnusedEnvironment(); + + _numEnvironments--; + _curEnvironment = curBackupPos; + _environments->get(_numEnvironments); } int16 Game_v6::addNewCollision(int16 id, uint16 left, uint16 top, @@ -148,7 +130,7 @@ int16 Game_v6::addNewCollision(int16 id, uint16 left, uint16 top, ptr->funcEnter = funcEnter; ptr->funcLeave = funcLeave; ptr->funcSub = funcSub; - ptr->totFileData = _totFileData; + ptr->script = _script; return i; } @@ -383,7 +365,6 @@ void Game_v6::collisionsBlock(void) { int16 array[300]; byte count; int16 collResId; - byte *startIP; int16 curCmd; int16 cmd; int16 cmdHigh; @@ -397,7 +378,6 @@ void Game_v6::collisionsBlock(void) { int16 stackPos2; int16 descIndex; int16 timeVal; - int16 offsetIP; char *str; int16 i; int16 counter; @@ -406,10 +386,11 @@ void Game_v6::collisionsBlock(void) { int16 collStackPos; Collision *collPtr; Collision *collArea; - byte *savedIP; byte collAreaStart; int16 activeCollResId = 0; int16 activeCollIndex = 0; + uint32 startPos; + uint32 offsetPos; if (_shouldPushColls) pushCollisions(0); @@ -422,25 +403,25 @@ void Game_v6::collisionsBlock(void) { _shouldPushColls = 0; collResId = -1; - _vm->_global->_inter_execPtr++; - count = *_vm->_global->_inter_execPtr++; + _script->skip(1); + count = _script->readByte(); - _handleMouse = _vm->_global->_inter_execPtr[0]; - deltaTime = 1000 * _vm->_global->_inter_execPtr[1]; - stackPos2 = _vm->_global->_inter_execPtr[3]; - descIndex = _vm->_global->_inter_execPtr[4]; - byte var_42 = _vm->_global->_inter_execPtr[5]; + _handleMouse = _script->peekByte(0); + deltaTime = 1000 * _script->peekByte(1); + stackPos2 = _script->peekByte(3); + descIndex = _script->peekByte(4); + byte var_42 = _script->peekByte(5); if ((stackPos2 != 0) || (descIndex != 0)) { deltaTime /= 100; - if (_vm->_global->_inter_execPtr[1] == 100) + if (_script->peekByte(1) == 100) deltaTime = 2; } timeVal = deltaTime; - _vm->_global->_inter_execPtr += 6; + _script->skip(6); - startIP = _vm->_global->_inter_execPtr; + startPos = _script->pos(); WRITE_VAR(16, 0); byte var_41 = 0; @@ -452,28 +433,27 @@ void Game_v6::collisionsBlock(void) { for (curCmd = 0; curCmd < count; curCmd++) { array[curCmd] = 0; - cmd = *_vm->_global->_inter_execPtr++; + cmd = _script->readByte(); if ((cmd & 0x40) != 0) { cmd -= 0x40; - cmdHigh = *_vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr++; + cmdHigh = _script->readByte(); cmdHigh <<= 8; } else cmdHigh = 0; if ((cmd & 0x80) != 0) { - offsetIP = _vm->_global->_inter_execPtr - _totFileData; - left = _vm->_parse->parseValExpr(); - top = _vm->_parse->parseValExpr(); - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + offsetPos = _script->pos(); + left = _script->readValExpr(); + top = _script->readValExpr(); + width = _script->readValExpr(); + height = _script->readValExpr(); } else { - offsetIP = 0; - left = _vm->_inter->load16(); - top = _vm->_inter->load16(); - width = _vm->_inter->load16(); - height = _vm->_inter->load16(); + offsetPos = 0; + left = _script->readUint16(); + top = _script->readUint16(); + width = _script->readUint16(); + height = _script->readUint16(); } if ((_vm->_draw->_renderFlags & RENDERFLAG_CAPTUREPOP) && (left != 0xFFFF)) { @@ -496,45 +476,37 @@ void Game_v6::collisionsBlock(void) { switch (cmd) { case 0: - _vm->_global->_inter_execPtr += 6; - startIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(6); + startPos = _script->pos(); + _script->skip(_script->peekUint16(2) + 2); key = curCmd + 0xA000; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, - cmd + cmdHigh, key, startIP - _totFileData, - _vm->_global->_inter_execPtr - _totFileData, offsetIP); + cmd + cmdHigh, key, startPos, + _script->pos(), offsetPos); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 1: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16(); + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16(); - startIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + startPos = _script->pos(); + _script->skip(_script->peekUint16(2) + 2); if (key == 0) key = curCmd + 0xA000; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, - (flags << 4) + cmd + cmdHigh, key, startIP - _totFileData, - _vm->_global->_inter_execPtr - _totFileData, offsetIP); + (flags << 4) + cmd + cmdHigh, key, startPos, + _script->pos(), offsetPos); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; @@ -548,23 +520,20 @@ void Game_v6::collisionsBlock(void) { case 10: _vm->_util->clearKeyBuf(); var_1C = 1; - key = _vm->_parse->parseVarIndex(); - descArray[index].fontIndex = _vm->_inter->load16(); - descArray[index].backColor = *_vm->_global->_inter_execPtr++; - descArray[index].frontColor = *_vm->_global->_inter_execPtr++; + key = _script->readVarIndex(); + descArray[index].fontIndex = _script->readInt16(); + descArray[index].backColor = _script->readByte(); + descArray[index].frontColor = _script->readByte(); if ((cmd >= 5) && (cmd <= 8)) { - descArray[index].ptr = _vm->_global->_inter_execPtr + 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr) + 2; + descArray[index].ptr = _script->getData() + _script->pos() + 2; + _script->skip(_script->peekUint16() + 2); } else descArray[index].ptr = 0; if (left == 0xFFFF) { if ((cmd & 1) == 0) { - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); } break; } @@ -575,50 +544,44 @@ void Game_v6::collisionsBlock(void) { funcLeave = 0; if (!(cmd & 1)) - funcLeave = _vm->_global->_inter_execPtr - _totFileData; + funcLeave = _script->pos(); addNewCollision(curCmd + 0x8000, left, top, right, top + height - 1, cmd, key, 0, funcLeave, 0); if (!(cmd & 1)) { - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); } index++; break; case 11: - _vm->_global->_inter_execPtr += 6; + _script->skip(6); for (i = 0; i < 150; i++) { if ((_collisionAreas[i].id & 0xF000) == 0xE000) { _collisionAreas[i].id &= 0xBFFF; _collisionAreas[i].funcEnter = - _vm->_global->_inter_execPtr - _totFileData; + _script->pos(); _collisionAreas[i].funcLeave = - _vm->_global->_inter_execPtr - _totFileData; + _script->pos(); } } - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 12: - _vm->_global->_inter_execPtr += 6; + _script->skip(6); for (i = 0; i < 150; i++) { if ((_collisionAreas[i].id & 0xF000) == 0xD000) { _collisionAreas[i].id &= 0xBFFF; _collisionAreas[i].funcEnter = - _vm->_global->_inter_execPtr - _totFileData; + _script->pos(); _collisionAreas[i].funcLeave = - _vm->_global->_inter_execPtr - _totFileData; + _script->pos(); } } - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 20: @@ -626,34 +589,30 @@ void Game_v6::collisionsBlock(void) { // Fall through to case 2 case 2: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16(); + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16(); addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, (flags << 4) + cmdHigh + 2, key, 0, - _vm->_global->_inter_execPtr - _totFileData, offsetIP); + _script->pos(), offsetPos); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; case 21: - key = _vm->_inter->load16(); - array[curCmd] = _vm->_inter->load16(); - flags = _vm->_inter->load16() & 3; + key = _script->readInt16(); + array[curCmd] = _script->readInt16(); + flags = _script->readInt16() & 3; addNewCollision(curCmd + 0x8000, left, top, left + width - 1, top + height - 1, (flags << 4) + cmdHigh + 2, key, - _vm->_global->_inter_execPtr - _totFileData, 0, offsetIP); + _script->pos(), 0, offsetPos); - _vm->_global->_inter_execPtr += 2; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _script->skip(_script->peekUint16(2) + 2); break; } @@ -915,10 +874,8 @@ void Game_v6::collisionsBlock(void) { if (_handleMouse == 1) _vm->_draw->blitCursor(); - savedIP = 0; if (!_vm->_inter->_terminate && (var_41 == 0)) { - savedIP = _totFileData + - _collisionAreas[activeCollIndex].funcLeave; + _script->seek(_collisionAreas[activeCollIndex].funcLeave); _vm->_inter->storeMouse(); if (VAR(16) == 0) { @@ -927,7 +884,8 @@ void Game_v6::collisionsBlock(void) { else WRITE_VAR(16, activeCollResId & 0xFFF); } - } + } else + _script->setFinished(true); for (curCmd = 0; curCmd < count; curCmd++) freeCollision(curCmd + 0x8000); @@ -937,8 +895,6 @@ void Game_v6::collisionsBlock(void) { ((_collisionAreas[i].id & 0xF000) == 0x9000)) _collisionAreas[i].id |= 0x4000; } - - _vm->_global->_inter_execPtr = savedIP; } void Game_v6::setCollisions(byte arg_0) { @@ -950,23 +906,22 @@ void Game_v6::setCollisions(byte arg_0) { if (collArea->flags & 0x80) continue; - byte *totFileData = collArea->totFileData; - - if (!totFileData) - totFileData = _totFileData; + Script *curScript = _script; - byte *savedIP = _vm->_global->_inter_execPtr; + _script = collArea->script; + if (!_script) + _script = curScript; - _vm->_global->_inter_execPtr = totFileData + collArea->funcSub; + _script->call(collArea->funcSub); - int16 left = _vm->_parse->parseValExpr(); - int16 top = _vm->_parse->parseValExpr(); - int16 width = _vm->_parse->parseValExpr(); - int16 height = _vm->_parse->parseValExpr(); + int16 left = _script->readValExpr(); + int16 top = _script->readValExpr(); + int16 width = _script->readValExpr(); + int16 height = _script->readValExpr(); uint16 flags = 0; if ((collArea->id & 0xF000) == 0xA000) - flags = _vm->_parse->parseValExpr(); + flags = _script->readValExpr(); if ((_vm->_draw->_renderFlags & RENDERFLAG_CAPTUREPOP) && (left != -1)) { @@ -1001,16 +956,18 @@ void Game_v6::setCollisions(byte arg_0) { if ((collArea->id & 0xF000) == 0xA000) collArea->flags = flags; - _vm->_global->_inter_execPtr = savedIP; + _script->pop(); + + _script = curScript; } } void Game_v6::collSub(uint16 offset) { - byte *savedIP; int16 collStackSize; - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _totFileData + offset; + uint32 savedPos = _script->pos(); + + _script->seek(offset); _shouldPushColls = 1; collStackSize = _collStackSize; @@ -1021,7 +978,8 @@ void Game_v6::collSub(uint16 offset) { popCollisions(); _shouldPushColls = 0; - _vm->_global->_inter_execPtr = savedIP; + + _script->seek(savedPos); if ((_vm->_util->getTimeKey() - _someTimeDly) > 500) setCollisions(0); diff --git a/engines/gob/global.cpp b/engines/gob/global.cpp index 005d65815f..4165938966 100644 --- a/engines/gob/global.cpp +++ b/engines/gob/global.cpp @@ -37,35 +37,36 @@ Global::Global(GobEngine *vm) : _vm(vm) { _presentVGA = UNDEF; _presentHER = UNDEF; - _videoMode = 0; + _videoMode = 0; _fakeVideoMode = 0; - _oldMode = 3; + _oldMode = 3; _soundFlags = 0; - _language = 0x8000; + _language = 0x8000; _languageWanted = 0x8000; + _foundLanguage = false; - _useMouse = UNDEF; + _useMouse = UNDEF; _mousePresent = UNDEF; - _mouseXShift = 3; - _mouseYShift = 3; + _mouseXShift = 3; + _mouseYShift = 3; - _mouseMinX = 0; - _mouseMinY = 0; + _mouseMinX = 0; + _mouseMinY = 0; _mouseMaxX = 320; _mouseMaxY = 200; _useJoystick = 1; - _primaryWidth = 0; + _primaryWidth = 0; _primaryHeight = 0; _colorCount = 16; for (int i = 0; i < 256; i++) { - _redPalette[i] = 0; + _redPalette [i] = 0; _greenPalette[i] = 0; - _bluePalette[i] = 0; + _bluePalette [i] = 0; } _unusedPalette1[ 0] = (int16) 0x0000; @@ -109,15 +110,12 @@ Global::Global(GobEngine *vm) : _vm(vm) { _pPaletteDesc = 0; - _setAllPalette = false; + _setAllPalette = false; _dontSetPalette = false; _debugFlag = 0; _inVM = 0; - _inter_resStr[0] = 0; - _inter_resVal = 0; - _inter_execPtr = 0; _inter_animDataSize = 10; diff --git a/engines/gob/global.h b/engines/gob/global.h index 9f12f4ded6..982ce113cb 100644 --- a/engines/gob/global.h +++ b/engines/gob/global.h @@ -33,37 +33,51 @@ namespace Gob { -#define VIDMODE_CGA 0x05 -#define VIDMODE_EGA 0x0D -#define VIDMODE_VGA 0x13 -#define VIDMODE_HER 7 - -#define PROAUDIO_FLAG 0x10 -#define ADLIB_FLAG 0x08 -#define BLASTER_FLAG 0x04 -#define INTERSOUND_FLAG 0x02 -#define SPEAKER_FLAG 0x01 -#define MIDI_FLAG 0x4000 - -#define NO 0 -#define YES 1 -#define UNDEF 2 - -#define F1_KEY 0x3B00 -#define F2_KEY 0x3C00 -#define F3_KEY 0x3D00 -#define F4_KEY 0x3E00 -#define F5_KEY 0x3F00 -#define F6_KEY 0x4000 -#define ESCAPE 0x001B -#define ENTER 0x000D +#define VIDMODE_CGA 0x05 +#define VIDMODE_EGA 0x0D +#define VIDMODE_VGA 0x13 +#define VIDMODE_HER 0x07 + +#define MIDI_FLAG 0x4000 +#define PROAUDIO_FLAG 0x0010 +#define ADLIB_FLAG 0x0008 +#define BLASTER_FLAG 0x0004 +#define INTERSOUND_FLAG 0x0002 +#define SPEAKER_FLAG 0x0001 + +#define NO 0 +#define YES 1 +#define UNDEF 2 + +#define F1_KEY 0x3B00 +#define F2_KEY 0x3C00 +#define F3_KEY 0x3D00 +#define F4_KEY 0x3E00 +#define F5_KEY 0x3F00 +#define F6_KEY 0x4000 +#define ESCAPE 0x001B +#define ENTER 0x000D /* Video drivers */ -#define UNK_DRIVER 0 -#define VGA_DRIVER 1 -#define EGA_DRIVER 2 -#define CGA_DRIVER 3 -#define HER_DRIVER 4 +#define UNK_DRIVER 0 +#define VGA_DRIVER 1 +#define EGA_DRIVER 2 +#define CGA_DRIVER 3 +#define HER_DRIVER 4 + +enum Language { + kLanguageFrench = 0, + kLanguageGerman = 1, + kLanguageBritish = 2, + kLanguageSpanish = 3, + kLanguageItalian = 4, + kLanguageAmerican = 5, + kLanguageDutch = 6, + kLanguageKorean = 7, + kLanguageHebrew = 8, + kLanguagePortuguese = 9, + kLanguageJapanese = 10 +}; class Global { public: @@ -82,6 +96,7 @@ public: uint16 _language; uint16 _languageWanted; + bool _foundLanguage; char _useMouse; int16 _mousePresent; @@ -117,9 +132,6 @@ public: int16 _debugFlag; int16 _inVM; - char _inter_resStr[200]; - int32 _inter_resVal; - byte *_inter_execPtr; int16 _inter_animDataSize; diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 1de6245297..e534464cce 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -47,7 +47,6 @@ #include "gob/map.h" #include "gob/mult.h" #include "gob/palanim.h" -#include "gob/parse.h" #include "gob/scenery.h" #include "gob/videoplayer.h" #include "gob/save/saveload.h" @@ -102,12 +101,12 @@ void PauseDialog::handleKeyDown(Common::KeyState state) { GobEngine::GobEngine(OSystem *syst) : Engine(syst) { - _sound = 0; _mult = 0; _game = 0; - _global = 0; _dataIO = 0; _goblin = 0; - _vidPlayer = 0; _init = 0; _inter = 0; - _map = 0; _palAnim = 0; _parse = 0; - _scenery = 0; _draw = 0; _util = 0; - _video = 0; _saveLoad = 0; + _sound = 0; _mult = 0; _game = 0; + _global = 0; _dataIO = 0; _goblin = 0; + _vidPlayer = 0; _init = 0; _inter = 0; + _map = 0; _palAnim = 0; _scenery = 0; + _draw = 0; _util = 0; _video = 0; + _saveLoad = 0; _pauseStart = 0; @@ -121,7 +120,7 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) { Common::addDebugChannel(kDebugDrawOp, "DrawOpcodes", "Script DrawOpcodes debug level"); Common::addDebugChannel(kDebugGobOp, "GoblinOpcodes", "Script GoblinOpcodes debug level"); Common::addDebugChannel(kDebugSound, "Sound", "Sound output debug level"); - Common::addDebugChannel(kDebugParser, "Parser", "Parser debug level"); + Common::addDebugChannel(kDebugExpression, "Expression", "Expression parser debug level"); Common::addDebugChannel(kDebugGameFlow, "Gameflow", "Gameflow debug level"); Common::addDebugChannel(kDebugFileIO, "FileIO", "File Input/Output debug level"); Common::addDebugChannel(kDebugSaveLoad, "SaveLoad", "Saving/Loading debug level"); @@ -248,42 +247,42 @@ Common::Error GobEngine::run() { switch (_language) { case Common::FR_FRA: case Common::RU_RUS: - _global->_language = 0; + _global->_language = kLanguageFrench; break; case Common::DE_DEU: - _global->_language = 1; + _global->_language = kLanguageGerman; break; case Common::EN_ANY: case Common::EN_GRB: - _global->_language = 2; + case Common::HU_HUN: + _global->_language = kLanguageBritish; break; case Common::ES_ESP: - _global->_language = 3; + _global->_language = kLanguageSpanish; break; case Common::IT_ITA: - _global->_language = 4; + _global->_language = kLanguageItalian; break; case Common::EN_USA: - _global->_language = 5; + _global->_language = kLanguageAmerican; break; case Common::NL_NLD: - _global->_language = 6; + _global->_language = kLanguageDutch; break; case Common::KO_KOR: - _global->_language = 7; + _global->_language = kLanguageKorean; break; case Common::HB_ISR: - _global->_language = 8; + _global->_language = kLanguageHebrew; break; case Common::PT_BRA: - _global->_language = 9; + _global->_language = kLanguagePortuguese; break; case Common::JA_JPN: - _global->_language = 10; + _global->_language = kLanguageJapanese; break; default: - // Default to English - _global->_language = 2; + _global->_language = kLanguageBritish; break; } _global->_languageWanted = _global->_language; @@ -332,7 +331,6 @@ bool GobEngine::initGameParts() { _palAnim = new PalAnim(this); _vidPlayer = new VideoPlayer(this); _sound = new Sound(this); - _parse = new Parse(this); switch (_gameType) { case kGameTypeGeisha: @@ -465,6 +463,8 @@ bool GobEngine::initGameParts() { break; } + _inter->setupOpcodes(); + if (is640()) { _video->_surfWidth = _width = 640; _video->_surfHeight = _video->_splitHeight1 = _height = 480; @@ -495,7 +495,6 @@ void GobEngine::deinitGameParts() { delete _inter; _inter = 0; delete _map; _map = 0; delete _palAnim; _palAnim = 0; - delete _parse; _parse = 0; delete _scenery; _scenery = 0; delete _draw; _draw = 0; delete _util; _util = 0; diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 43e2270354..5d1cb3ecf2 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -52,7 +52,6 @@ class Inter; class Map; class Mult; class PalAnim; -class Parse; class Scenery; class Util; class SaveLoad; @@ -128,7 +127,7 @@ enum { kDebugDrawOp = 1 << 1, kDebugGobOp = 1 << 2, kDebugSound = 1 << 3, - kDebugParser = 1 << 4, + kDebugExpression = 1 << 4, kDebugGameFlow = 1 << 5, kDebugFileIO = 1 << 6, kDebugSaveLoad = 1 << 7, @@ -197,7 +196,6 @@ public: Map *_map; Mult *_mult; PalAnim *_palAnim; - Parse *_parse; Scenery *_scenery; Inter *_inter; SaveLoad *_saveLoad; diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index 8bf9536286..f9a22f52fb 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -32,6 +32,7 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/script.h" #include "gob/palanim.h" #include "gob/inter.h" #include "gob/video.h" @@ -80,9 +81,6 @@ void Init::doDemo() { } void Init::initGame() { - int16 handle2; - int16 handle; - int16 imdHandle; byte *infBuf; char *infPtr; char *infEnd; @@ -91,11 +89,8 @@ void Init::initGame() { initVideo(); if (!_vm->isDemo()) { - handle2 = _vm->_dataIO->openData(_vm->_startStk.c_str()); - if (handle2 >= 0) { - _vm->_dataIO->closeData(handle2); + if (_vm->_dataIO->existData(_vm->_startStk.c_str())) _vm->_dataIO->openDataFile(_vm->_startStk.c_str()); - } } _vm->_util->initInput(); @@ -104,8 +99,6 @@ void Init::initGame() { _vm->_global->_mouseXShift = 1; _vm->_global->_mouseYShift = 1; - _vm->_game->_totTextData = 0; - _vm->_game->_totFileData = 0; _palDesc = new Video::PalDesc; _vm->validateVideoMode(_vm->_global->_videoMode); @@ -127,19 +120,13 @@ void Init::initGame() { return; } - handle = _vm->_dataIO->openData("intro.inf"); + if (!_vm->_dataIO->existData("intro.inf")) { - if (handle < 0) { - for (int i = 0; i < 4; i++) { - handle2 = _vm->_dataIO->openData(_fontNames[i]); - if (handle2 >= 0) { - _vm->_dataIO->closeData(handle2); + for (int i = 0; i < 4; i++) + if (_vm->_dataIO->existData(_fontNames[i])) _vm->_draw->_fonts[i] = _vm->_util->loadFont(_fontNames[i]); - } - } - } else { - _vm->_dataIO->closeData(handle); + } else { infBuf = _vm->_dataIO->getData("intro.inf"); infPtr = (char *) infBuf; @@ -153,11 +140,8 @@ void Init::initGame() { buffer[j] = 0; strcat(buffer, ".let"); - handle2 = _vm->_dataIO->openData(buffer); - if (handle2 >= 0) { - _vm->_dataIO->closeData(handle2); + if (_vm->_dataIO->existData(buffer)) _vm->_draw->_fonts[i] = _vm->_util->loadFont(buffer); - } if ((infPtr + 1) >= infEnd) break; @@ -167,26 +151,16 @@ void Init::initGame() { delete[] infBuf; } - strcpy(buffer, _vm->_startTot.c_str()); - handle = _vm->_dataIO->openData(buffer); + if (_vm->_dataIO->existData(_vm->_startTot.c_str())) { + _vm->_inter->allocateVars(Script::getVariablesCount(_vm->_startTot.c_str(), _vm)); - if (handle >= 0) { - DataStream *stream = _vm->_dataIO->openAsStream(handle, true); - - stream->seek(0x2C); - _vm->_inter->allocateVars(stream->readUint16LE()); - - delete stream; - - strcpy(_vm->_game->_curTotFile, buffer); + strcpy(_vm->_game->_curTotFile, _vm->_startTot.c_str()); _vm->_sound->cdTest(1, "GOB"); _vm->_sound->cdLoadLIC("gob.lic"); // Search for a Coktel logo animation or image to display - imdHandle = _vm->_dataIO->openData("coktel.imd"); - if (imdHandle >= 0) { - _vm->_dataIO->closeData(imdHandle); + if (_vm->_dataIO->existData("coktel.imd")) { _vm->_draw->initScreen(); _vm->_draw->_cursorIndex = -1; @@ -198,19 +172,17 @@ void Init::initGame() { } _vm->_draw->closeScreen(); - } else if ((imdHandle = _vm->_dataIO->openData("coktel.clt")) >= 0) { + } else if (_vm->_dataIO->existData("coktel.clt")) { _vm->_draw->initScreen(); - - stream = _vm->_dataIO->openAsStream(imdHandle, true); _vm->_util->clearPalette(); + + DataStream *stream = _vm->_dataIO->getDataStream("coktel.clt"); stream->read((byte *) _vm->_draw->_vgaPalette, 768); delete stream; - imdHandle = _vm->_dataIO->openData("coktel.ims"); - if (imdHandle >= 0) { + if (_vm->_dataIO->existData("coktel.ims")) { byte *sprBuf; - _vm->_dataIO->closeData(imdHandle); sprBuf = _vm->_dataIO->getData("coktel.ims"); _vm->_video->drawPackedSprite(sprBuf, 320, 200, 0, 0, 0, *_vm->_draw->_frontSurface); diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index ce7f2ba319..8be07034c6 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -33,7 +33,8 @@ #include "gob/util.h" #include "gob/draw.h" #include "gob/game.h" -#include "gob/parse.h" +#include "gob/expression.h" +#include "gob/script.h" #include "gob/scenery.h" #include "gob/sound/sound.h" @@ -67,65 +68,93 @@ Inter::~Inter() { delocateVars(); } -void Inter::initControlVars(char full) { - *_nestLevel = 0; - *_breakFromLevel = -1; +void Inter::setupOpcodes() { + setupOpcodesDraw(); + setupOpcodesFunc(); + setupOpcodesGob(); +} - *_vm->_scenery->_pCaptureCounter = 0; +void Inter::executeOpcodeDraw(byte i) { + debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", i, i, getDescOpcodeDraw(i)); - _break = false; - _terminate = 0; + if (_opcodesDraw[i].proc && _opcodesDraw[i].proc->isValid()) + (*_opcodesDraw[i].proc)(); + else + warning("unimplemented opcodeDraw: %d [0x%X]", i, i); +} - if (full == 1) { - for (int i = 0; i < 8; i++) - _animPalDir[i] = 0; - _soundEndTimeKey = 0; +bool Inter::executeOpcodeFunc(byte i, byte j, OpFuncParams ¶ms) { + debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s)", + i, j, i, j, getDescOpcodeFunc(i, j)); + + if ((i > 4) || (j > 15)) { + warning("unimplemented opcodeFunc: %d.%d [0x%X.0x%X]", i, j, i, j); + return false; } + + i = i * 16 + j; + if (_opcodesFunc[i].proc && _opcodesFunc[i].proc->isValid()) + return (*_opcodesFunc[i].proc)(params); + else + warning("unimplemented opcodeFunc: %d.%d [0x%X.0x%X]", i, j, i, j); + + return false; } -int16 Inter::load16() { - int16 tmp = (int16) READ_LE_UINT16(_vm->_global->_inter_execPtr); - _vm->_global->_inter_execPtr += 2; - return tmp; +void Inter::executeOpcodeGob(int i, OpGobParams ¶ms) { + debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", + i, i, getDescOpcodeGob(i)); + + OpcodeEntry<OpcodeGob> *op = 0; + + if (_opcodesGob.contains(i)) + op = &_opcodesGob.getVal(i); + + if (op && op->proc && op->proc->isValid()) { + (*op->proc)(params); + return; + } + + _vm->_game->_script->skip(params.paramCount << 1); + warning("unimplemented opcodeGob: %d [0x%X]", i, i); } -char Inter::evalExpr(int16 *pRes) { - byte token; +const char *Inter::getDescOpcodeDraw(byte i) { + const char *desc = _opcodesDraw[i].desc; - _vm->_parse->printExpr(99); + return ((desc) ? desc : ""); +} - _vm->_parse->parseExpr(99, &token); - if (!pRes) - return token; +const char *Inter::getDescOpcodeFunc(byte i, byte j) { + if ((i > 4) || (j > 15)) + return ""; - switch (token) { - case 20: - *pRes = _vm->_global->_inter_resVal; - break; + const char *desc = _opcodesFunc[i * 16 + j].desc; - case 22: - case 23: - *pRes = 0; - break; + return ((desc) ? desc : ""); +} - case 24: - *pRes = 1; - break; - } +const char *Inter::getDescOpcodeGob(int i) { + if (_opcodesGob.contains(i)) + return _opcodesGob.getVal(i).desc; - return token; + return ""; } -bool Inter::evalBoolResult() { - byte token; +void Inter::initControlVars(char full) { + *_nestLevel = 0; + *_breakFromLevel = -1; + + *_vm->_scenery->_pCaptureCounter = 0; - _vm->_parse->printExpr(99); + _break = false; + _terminate = 0; - _vm->_parse->parseExpr(99, &token); - if ((token == 24) || ((token == 20) && _vm->_global->_inter_resVal)) - return true; - else - return false; + if (full == 1) { + for (int i = 0; i < 8; i++) + _animPalDir[i] = 0; + _soundEndTimeKey = 0; + } } void Inter::renewTimeInVars() { @@ -185,14 +214,14 @@ void Inter::storeKey(int16 key) { void Inter::writeVar(uint32 offset, uint16 type, uint32 value) { switch (type) { - case 16: - case 18: + case TYPE_VAR_INT8: + case TYPE_ARRAY_INT8: WRITE_VARO_UINT8(offset, value); break; - case 17: - case 24: - case 27: + case TYPE_VAR_INT16: + case TYPE_VAR_INT32_AS_INT16: + case TYPE_ARRAY_INT16: WRITE_VARO_UINT16(offset, value); break; @@ -209,20 +238,20 @@ void Inter::funcBlock(int16 retFlag) { params.retFlag = retFlag; - if (!_vm->_global->_inter_execPtr) + if (_vm->_game->_script->isFinished()) return; _break = false; - _vm->_global->_inter_execPtr++; - params.cmdCount = *_vm->_global->_inter_execPtr++; - _vm->_global->_inter_execPtr += 2; + _vm->_game->_script->skip(1); + params.cmdCount = _vm->_game->_script->readByte(); + _vm->_game->_script->skip(2); if (params.cmdCount == 0) { - _vm->_global->_inter_execPtr = 0; + _vm->_game->_script->setFinished(true); return; } - int startaddr = _vm->_global->_inter_execPtr - _vm->_game->_totFileData; + int startaddr = _vm->_game->_script->pos(); params.counter = 0; do { @@ -237,7 +266,7 @@ void Inter::funcBlock(int16 retFlag) { (_vm->getPlatform() == Common::kPlatformMacintosh) || (_vm->getPlatform() == Common::kPlatformWindows))) { - int addr = _vm->_global->_inter_execPtr-_vm->_game->_totFileData; + int addr = _vm->_game->_script->pos(); if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie, EGA !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) || @@ -263,20 +292,19 @@ void Inter::funcBlock(int16 retFlag) { } // End of workaround - cmd = *_vm->_global->_inter_execPtr; + cmd = _vm->_game->_script->readByte(); if ((cmd >> 4) >= 12) { cmd2 = 16 - (cmd >> 4); cmd &= 0xF; } else cmd2 = 0; - _vm->_global->_inter_execPtr++; params.counter++; if (cmd2 == 0) cmd >>= 4; - if (executeFuncOpcode(cmd2, cmd, params)) + if (executeOpcodeFunc(cmd2, cmd, params)) return; if (_vm->shouldQuit()) @@ -292,17 +320,17 @@ void Inter::funcBlock(int16 retFlag) { } } while (params.counter != params.cmdCount); - _vm->_global->_inter_execPtr = 0; + _vm->_game->_script->setFinished(true); return; } void Inter::callSub(int16 retFlag) { byte block; - while (!_vm->shouldQuit() && _vm->_global->_inter_execPtr && - (_vm->_global->_inter_execPtr != _vm->_game->_totFileData)) { + while (!_vm->shouldQuit() && !_vm->_game->_script->isFinished() && + (_vm->_game->_script->pos() != 0)) { - block = *_vm->_global->_inter_execPtr; + block = _vm->_game->_script->peekByte(); if (block == 1) funcBlock(retFlag); else if (block == 2) @@ -311,7 +339,7 @@ void Inter::callSub(int16 retFlag) { error("Unknown block type %d in Inter::callSub()", block); } - if (_vm->_global->_inter_execPtr == _vm->_game->_totFileData) + if (!_vm->_game->_script->isFinished() && (_vm->_game->_script->pos() == 0)) _terminate = 1; } diff --git a/engines/gob/inter.h b/engines/gob/inter.h index 412c3f2673..d4ed2d3240 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -26,6 +26,9 @@ #ifndef GOB_INTER_H #define GOB_INTER_H +#include "common/func.h" +#include "common/hashmap.h" + #include "gob/goblin.h" #include "gob/variables.h" @@ -34,11 +37,54 @@ namespace Gob { // This is to help devices with small memory (PDA, smartphones, ...) // to save abit of memory used by opcode names in the Scumm engine. #ifndef REDUCE_MEMORY_USAGE -# define _OPCODE(ver, x) { &ver::x, #x } + #define _OPCODEDRAW(ver, x) setProc(new Common::Functor0Mem<void, ver>(this, &ver::x), #x) + #define _OPCODEFUNC(ver, x) setProc(new Common::Functor1Mem<OpFuncParams &, bool, ver>(this, &ver::x), #x) + #define _OPCODEGOB(ver, x) setProc(new Common::Functor1Mem<OpGobParams &, void, ver>(this, &ver::x), #x) #else -# define _OPCODE(ver, x) { &ver::x, "" } + #define _OPCODEDRAW(ver, x) setProc(new Common::Functor0Mem<void, ver>(this, &ver::x), "") + #define _OPCODEFUNC(ver, x) setProc(new Common::Functor1Mem<OpFuncParams &, bool, ver>(this, &ver::x), "") + #define _OPCODEGOB(ver, x) setProc(new Common::Functor1Mem<OpGobParams &, void, ver>(this, &ver::x), "") #endif +#define CLEAROPCODEDRAW(i) _opcodesDraw[i].setProc(0, 0) +#define CLEAROPCODEFUNC(i) _opcodesFunc[i].setProc(0, 0) +#define CLEAROPCODEGOB(i) _opcodesGob.erase(i) + +typedef Common::Functor0<void> OpcodeDraw; +typedef Common::Functor1<struct OpFuncParams &, bool> OpcodeFunc; +typedef Common::Functor1<struct OpGobParams &, void> OpcodeGob; + +struct OpFuncParams { + byte cmdCount; + byte counter; + int16 retFlag; +}; +struct OpGobParams { + int16 extraData; + int16 paramCount; + VariableReference retVarPtr; + Goblin::Gob_Object *objDesc; +}; + +template<typename T> +struct OpcodeEntry : Common::NonCopyable { + T *proc; + const char *desc; + + OpcodeEntry() : proc(0), desc(0) {} + ~OpcodeEntry() { + setProc(0, 0); + } + + void setProc(T *p, const char *d) { + if (proc != p) { + delete proc; + proc = p; + } + desc = d; + } +}; + class Inter { public: uint8 _terminate; @@ -51,10 +97,9 @@ public: Variables *_variables; + void setupOpcodes(); + void initControlVars(char full); - int16 load16(); - char evalExpr(int16 *pRes); - bool evalBoolResult(); void renewTimeInVars(); void storeMouse(); void storeKey(int16 key); @@ -74,16 +119,9 @@ public: virtual ~Inter(); protected: - struct OpFuncParams { - byte cmdCount; - byte counter; - int16 retFlag; - }; - struct OpGobParams { - int16 extraData; - VariableReference retVarPtr; - Goblin::Gob_Object *objDesc; - }; + OpcodeEntry<OpcodeDraw> _opcodesDraw[256]; + OpcodeEntry<OpcodeFunc> _opcodesFunc[256]; + Common::HashMap<int, OpcodeEntry<OpcodeGob> > _opcodesGob; bool _break; @@ -99,15 +137,19 @@ protected: GobEngine *_vm; - virtual void setupOpcodes() = 0; - virtual void executeDrawOpcode(byte i) = 0; - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) = 0; - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms) = 0; - virtual const char *getOpcodeDrawDesc(byte i) = 0; - virtual const char *getOpcodeFuncDesc(byte i, byte j) = 0; - virtual const char *getOpcodeGoblinDesc(int i) = 0; + void executeOpcodeDraw(byte i); + bool executeOpcodeFunc(byte i, byte j, OpFuncParams ¶ms); + void executeOpcodeGob(int i, OpGobParams ¶ms); + + const char *getDescOpcodeDraw(byte i); + const char *getDescOpcodeFunc(byte i, byte j); + const char *getDescOpcodeGob(int i); - virtual void checkSwitchTable(byte **ppExec) = 0; + virtual void setupOpcodesDraw() = 0; + virtual void setupOpcodesFunc() = 0; + virtual void setupOpcodesGob() = 0; + + virtual void checkSwitchTable(uint32 &offset) = 0; void o_drawNOP() {} bool o_funcNOP(OpFuncParams ¶ms) { return false; } @@ -123,35 +165,11 @@ public: virtual void animPalette(); protected: - typedef void (Inter_v1::*OpcodeDrawProcV1)(); - typedef bool (Inter_v1::*OpcodeFuncProcV1)(OpFuncParams &); - typedef void (Inter_v1::*OpcodeGoblinProcV1)(OpGobParams &); - struct OpcodeDrawEntryV1 { - OpcodeDrawProcV1 proc; - const char *desc; - }; - struct OpcodeFuncEntryV1 { - OpcodeFuncProcV1 proc; - const char *desc; - }; - struct OpcodeGoblinEntryV1 { - OpcodeGoblinProcV1 proc; - const char *desc; - }; - const OpcodeDrawEntryV1 *_opcodesDrawV1; - const OpcodeFuncEntryV1 *_opcodesFuncV1; - const OpcodeGoblinEntryV1 *_opcodesGoblinV1; - static const int _goblinFuncLookUp[][2]; - - virtual void setupOpcodes(); - virtual void executeDrawOpcode(byte i); - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); - virtual const char *getOpcodeDrawDesc(byte i); - virtual const char *getOpcodeFuncDesc(byte i, byte j); - virtual const char *getOpcodeGoblinDesc(int i); - - virtual void checkSwitchTable(byte **ppExec); + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); + + virtual void checkSwitchTable(uint32 &offset); void o1_loadMult(); void o1_playMult(); @@ -318,35 +336,11 @@ public: virtual void animPalette(); protected: - typedef void (Inter_v2::*OpcodeDrawProcV2)(); - typedef bool (Inter_v2::*OpcodeFuncProcV2)(OpFuncParams &); - typedef void (Inter_v2::*OpcodeGoblinProcV2)(OpGobParams &); - struct OpcodeDrawEntryV2 { - OpcodeDrawProcV2 proc; - const char *desc; - }; - struct OpcodeFuncEntryV2 { - OpcodeFuncProcV2 proc; - const char *desc; - }; - struct OpcodeGoblinEntryV2 { - OpcodeGoblinProcV2 proc; - const char *desc; - }; - const OpcodeDrawEntryV2 *_opcodesDrawV2; - const OpcodeFuncEntryV2 *_opcodesFuncV2; - const OpcodeGoblinEntryV2 *_opcodesGoblinV2; - static const int _goblinFuncLookUp[][2]; - - virtual void setupOpcodes(); - virtual void executeDrawOpcode(byte i); - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); - virtual const char *getOpcodeDrawDesc(byte i); - virtual const char *getOpcodeFuncDesc(byte i, byte j); - virtual const char *getOpcodeGoblinDesc(int i); - - virtual void checkSwitchTable(byte **ppExec); + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); + + virtual void checkSwitchTable(uint32 &offset); void o2_playMult(); void o2_freeMultKeys(); @@ -410,33 +404,9 @@ public: virtual ~Inter_Bargon() {} protected: - typedef void (Inter_Bargon::*OpcodeDrawProcBargon)(); - typedef bool (Inter_Bargon::*OpcodeFuncProcBargon)(OpFuncParams &); - typedef void (Inter_Bargon::*OpcodeGoblinProcBargon)(OpGobParams &); - struct OpcodeDrawEntryBargon { - OpcodeDrawProcBargon proc; - const char *desc; - }; - struct OpcodeFuncEntryBargon { - OpcodeFuncProcBargon proc; - const char *desc; - }; - struct OpcodeGoblinEntryBargon { - OpcodeGoblinProcBargon proc; - const char *desc; - }; - const OpcodeDrawEntryBargon *_opcodesDrawBargon; - const OpcodeFuncEntryBargon *_opcodesFuncBargon; - const OpcodeGoblinEntryBargon *_opcodesGoblinBargon; - static const int _goblinFuncLookUp[][2]; - - virtual void setupOpcodes(); - virtual void executeDrawOpcode(byte i); - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); - virtual const char *getOpcodeDrawDesc(byte i); - virtual const char *getOpcodeFuncDesc(byte i, byte j); - virtual const char *getOpcodeGoblinDesc(int i); + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); void oBargon_intro0(OpGobParams ¶ms); void oBargon_intro1(OpGobParams ¶ms); @@ -456,33 +426,9 @@ public: virtual ~Inter_Fascination() {} protected: - typedef void (Inter_Fascination::*OpcodeDrawProcFascination)(); - typedef bool (Inter_Fascination::*OpcodeFuncProcFascination)(OpFuncParams &); - typedef void (Inter_Fascination::*OpcodeGoblinProcFascination)(OpGobParams &); - struct OpcodeDrawEntryFascination { - OpcodeDrawProcFascination proc; - const char *desc; - }; - struct OpcodeFuncEntryFascination { - OpcodeFuncProcFascination proc; - const char *desc; - }; - struct OpcodeGoblinEntryFascination { - OpcodeGoblinProcFascination proc; - const char *desc; - }; - const OpcodeDrawEntryFascination *_opcodesDrawFascination; - const OpcodeFuncEntryFascination *_opcodesFuncFascination; - const OpcodeGoblinEntryFascination *_opcodesGoblinFascination; - static const int _goblinFuncLookUp[][2]; - - virtual void setupOpcodes(); - virtual void executeDrawOpcode(byte i); - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); - virtual const char *getOpcodeDrawDesc(byte i); - virtual const char *getOpcodeFuncDesc(byte i, byte j); - virtual const char *getOpcodeGoblinDesc(int i); + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); void oFascin_playProtracker(OpGobParams ¶ms); @@ -517,39 +463,12 @@ public: virtual ~Inter_v3() {} protected: - typedef void (Inter_v3::*OpcodeDrawProcV3)(); - typedef bool (Inter_v3::*OpcodeFuncProcV3)(OpFuncParams &); - typedef void (Inter_v3::*OpcodeGoblinProcV3)(OpGobParams &); - struct OpcodeDrawEntryV3 { - OpcodeDrawProcV3 proc; - const char *desc; - }; - struct OpcodeFuncEntryV3 { - OpcodeFuncProcV3 proc; - const char *desc; - }; - struct OpcodeGoblinEntryV3 { - OpcodeGoblinProcV3 proc; - const char *desc; - }; - const OpcodeDrawEntryV3 *_opcodesDrawV3; - const OpcodeFuncEntryV3 *_opcodesFuncV3; - const OpcodeGoblinEntryV3 *_opcodesGoblinV3; - static const int _goblinFuncLookUp[][2]; - - virtual void setupOpcodes(); - virtual void executeDrawOpcode(byte i); - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); - virtual const char *getOpcodeDrawDesc(byte i); - virtual const char *getOpcodeFuncDesc(byte i, byte j); - virtual const char *getOpcodeGoblinDesc(int i); + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); bool o3_getTotTextItemPart(OpFuncParams ¶ms); bool o3_copySprite(OpFuncParams ¶ms); - bool o3_checkData(OpFuncParams ¶ms); - bool o3_readData(OpFuncParams ¶ms); - bool o3_writeData(OpFuncParams ¶ms); void o3_wobble(OpGobParams ¶ms); }; @@ -560,33 +479,9 @@ public: virtual ~Inter_v4() {} protected: - typedef void (Inter_v4::*OpcodeDrawProcV4)(); - typedef bool (Inter_v4::*OpcodeFuncProcV4)(OpFuncParams &); - typedef void (Inter_v4::*OpcodeGoblinProcV4)(OpGobParams &); - struct OpcodeDrawEntryV4 { - OpcodeDrawProcV4 proc; - const char *desc; - }; - struct OpcodeFuncEntryV4 { - OpcodeFuncProcV4 proc; - const char *desc; - }; - struct OpcodeGoblinEntryV4 { - OpcodeGoblinProcV4 proc; - const char *desc; - }; - const OpcodeDrawEntryV4 *_opcodesDrawV4; - const OpcodeFuncEntryV4 *_opcodesFuncV4; - const OpcodeGoblinEntryV4 *_opcodesGoblinV4; - static const int _goblinFuncLookUp[][2]; - - virtual void setupOpcodes(); - virtual void executeDrawOpcode(byte i); - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); - virtual const char *getOpcodeDrawDesc(byte i); - virtual const char *getOpcodeFuncDesc(byte i, byte j); - virtual const char *getOpcodeGoblinDesc(int i); + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); void o4_initScreen(); void o4_playVmdOrMusic(); @@ -598,36 +493,12 @@ public: virtual ~Inter_v5() {} protected: - typedef void (Inter_v5::*OpcodeDrawProcV5)(); - typedef bool (Inter_v5::*OpcodeFuncProcV5)(OpFuncParams &); - typedef void (Inter_v5::*OpcodeGoblinProcV5)(OpGobParams &); - struct OpcodeDrawEntryV5 { - OpcodeDrawProcV5 proc; - const char *desc; - }; - struct OpcodeFuncEntryV5 { - OpcodeFuncProcV5 proc; - const char *desc; - }; - struct OpcodeGoblinEntryV5 { - OpcodeGoblinProcV5 proc; - const char *desc; - }; - const OpcodeDrawEntryV5 *_opcodesDrawV5; - const OpcodeFuncEntryV5 *_opcodesFuncV5; - const OpcodeGoblinEntryV5 *_opcodesGoblinV5; - static const int _goblinFuncLookUp[][2]; - - virtual void setupOpcodes(); - virtual void executeDrawOpcode(byte i); - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); - virtual const char *getOpcodeDrawDesc(byte i); - virtual const char *getOpcodeFuncDesc(byte i, byte j); - virtual const char *getOpcodeGoblinDesc(int i); - byte _gob_97_98_val; + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); + void o5_deleteFile(); void o5_initScreen(); @@ -657,35 +528,11 @@ public: virtual ~Inter_v6() {} protected: - typedef void (Inter_v6::*OpcodeDrawProcV6)(); - typedef bool (Inter_v6::*OpcodeFuncProcV6)(OpFuncParams &); - typedef void (Inter_v6::*OpcodeGoblinProcV6)(OpGobParams &); - struct OpcodeDrawEntryV6 { - OpcodeDrawProcV6 proc; - const char *desc; - }; - struct OpcodeFuncEntryV6 { - OpcodeFuncProcV6 proc; - const char *desc; - }; - struct OpcodeGoblinEntryV6 { - OpcodeGoblinProcV6 proc; - const char *desc; - }; - const OpcodeDrawEntryV6 *_opcodesDrawV6; - const OpcodeFuncEntryV6 *_opcodesFuncV6; - const OpcodeGoblinEntryV6 *_opcodesGoblinV6; - static const int _goblinFuncLookUp[][2]; - bool _gotFirstPalette; - virtual void setupOpcodes(); - virtual void executeDrawOpcode(byte i); - virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); - virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); - virtual const char *getOpcodeDrawDesc(byte i); - virtual const char *getOpcodeFuncDesc(byte i, byte j); - virtual const char *getOpcodeGoblinDesc(int i); + virtual void setupOpcodesDraw(); + virtual void setupOpcodesFunc(); + virtual void setupOpcodesGob(); void o6_totSub(); void o6_playVmdOrMusic(); diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index 54ca32fa9e..12079600c0 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -39,680 +39,36 @@ namespace Gob { -#define OPCODE(x) _OPCODE(Inter_Bargon, x) - -const int Inter_Bargon::_goblinFuncLookUp[][2] = { - {1, 0}, - {2, 1}, - {3, 2}, - {4, 3}, - {5, 4}, - {6, 5}, - {7, 6}, - {8, 7}, - {9, 8}, - {10, 9}, - {11, 10}, - {13, 11}, - {14, 12}, - {15, 13}, - {16, 14}, - {21, 15}, - {22, 16}, - {23, 17}, - {24, 18}, - {25, 19}, - {26, 20}, - {27, 21}, - {28, 22}, - {29, 23}, - {30, 24}, - {32, 25}, - {33, 26}, - {34, 27}, - {35, 28}, - {36, 29}, - {37, 30}, - {40, 31}, - {41, 32}, - {42, 33}, - {43, 34}, - {44, 35}, - {50, 36}, - {52, 37}, - {53, 38}, - {100, 39}, - {152, 40}, - {200, 41}, - {201, 42}, - {202, 43}, - {203, 44}, - {204, 45}, - {250, 46}, - {251, 47}, - {252, 48}, - {500, 49}, - {502, 50}, - {503, 51}, - {600, 52}, - {601, 53}, - {602, 54}, - {603, 55}, - {604, 56}, - {605, 57}, - {1000, 58}, - {1001, 59}, - {1002, 60}, - {1003, 61}, - {1004, 62}, - {1005, 63}, - {1006, 64}, - {1008, 65}, - {1009, 66}, - {1010, 67}, - {1011, 68}, - {1015, 69}, - {2005, 70} -}; +#define OPCODEVER Inter_Bargon +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) Inter_Bargon::Inter_Bargon(GobEngine *vm) : Inter_v2(vm) { - setupOpcodes(); -} - -void Inter_Bargon::setupOpcodes() { - static const OpcodeDrawEntryBargon opcodesDraw[256] = { - /* 00 */ - OPCODE(o1_loadMult), - OPCODE(o2_playMult), - OPCODE(o1_freeMultKeys), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o1_initCursor), - /* 08 */ - OPCODE(o1_initCursorAnim), - OPCODE(o1_clearCursorAnim), - OPCODE(o2_setRenderFlags), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - OPCODE(o1_loadAnim), - OPCODE(o1_freeAnim), - OPCODE(o1_updateAnim), - OPCODE(o2_multSub), - /* 14 */ - OPCODE(o2_initMult), - OPCODE(o1_freeMult), - OPCODE(o1_animate), - OPCODE(o2_loadMultObject), - /* 18 */ - OPCODE(o1_getAnimLayerInfo), - OPCODE(o1_getObjAnimSize), - OPCODE(o1_loadStatic), - OPCODE(o1_freeStatic), - /* 1C */ - OPCODE(o2_renderStatic), - OPCODE(o2_loadCurLayer), - {0, ""}, - {0, ""}, - /* 20 */ - OPCODE(o2_playCDTrack), - OPCODE(o2_waitCDTrackEnd), - OPCODE(o2_stopCD), - OPCODE(o2_readLIC), - /* 24 */ - OPCODE(o2_freeLIC), - OPCODE(o2_getCDTrackPos), - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o2_loadFontToSprite), - OPCODE(o1_freeFontToSprite), - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - OPCODE(o2_totSub), - OPCODE(o2_switchTotSub), - OPCODE(o2_pushVars), - OPCODE(o2_popVars), - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 48 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 4C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 50 */ - OPCODE(o2_loadMapObjects), - OPCODE(o2_freeGoblins), - OPCODE(o2_moveGoblin), - OPCODE(o2_writeGoblinPos), - /* 54 */ - OPCODE(o2_stopGoblin), - OPCODE(o2_setGoblinState), - OPCODE(o2_placeGoblin), - {0, ""}, - /* 58 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 5C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 60 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 64 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 68 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 6C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 70 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 74 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 78 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 7C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 80 */ - OPCODE(o2_initScreen), - OPCODE(o2_scroll), - OPCODE(o2_setScrollOffset), - OPCODE(o2_playImd), - /* 84 */ - OPCODE(o2_getImdInfo), - OPCODE(o2_openItk), - OPCODE(o2_closeItk), - OPCODE(o2_setImdFrontSurf), - /* 88 */ - OPCODE(o2_resetImdFrontSurf), - {0, ""}, - {0, ""}, - {0, ""}, - /* 8C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 90 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 94 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 98 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 9C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* AC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* BC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* CC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* DC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* EC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* FC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""} - }; - - static const OpcodeFuncEntryBargon opcodesFunc[80] = { - /* 00 */ - OPCODE(o1_callSub), - OPCODE(o1_callSub), - OPCODE(o1_printTotText), - OPCODE(o1_loadCursor), - /* 04 */ - {0, ""}, - OPCODE(o1_switch), - OPCODE(o1_repeatUntil), - OPCODE(o1_whileDo), - /* 08 */ - OPCODE(o1_if), - OPCODE(o2_assign), - OPCODE(o1_loadSpriteToPos), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - OPCODE(o2_printText), - OPCODE(o1_loadTot), - OPCODE(o1_palLoad), - /* 14 */ - OPCODE(o1_keyFunc), - OPCODE(o1_capturePush), - OPCODE(o1_capturePop), - OPCODE(o2_animPalInit), - /* 18 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - OPCODE(o1_drawOperations), - OPCODE(o1_setcmdCount), - /* 20 */ - OPCODE(o1_return), - OPCODE(o1_renewTimeInVars), - OPCODE(o1_speakerOn), - OPCODE(o1_speakerOff), - /* 24 */ - OPCODE(o1_putPixel), - OPCODE(o2_goblinFunc), - OPCODE(o1_createSprite), - OPCODE(o1_freeSprite), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_returnTo), - OPCODE(o1_loadSpriteContent), - OPCODE(o1_copySprite), - OPCODE(o1_fillRect), - /* 34 */ - OPCODE(o1_drawLine), - OPCODE(o1_strToLong), - OPCODE(o1_invalidate), - OPCODE(o1_setBackDelta), - /* 38 */ - OPCODE(o1_playSound), - OPCODE(o2_stopSound), - OPCODE(o2_loadSound), - OPCODE(o1_freeSoundSlot), - /* 3C */ - OPCODE(o1_waitEndPlay), - OPCODE(o1_playComposition), - OPCODE(o2_getFreeMem), - OPCODE(o2_checkData), - /* 40 */ - {0, ""}, - OPCODE(o1_prepareStr), - OPCODE(o1_insertStr), - OPCODE(o1_cutStr), - /* 44 */ - OPCODE(o1_strstr), - OPCODE(o1_istrlen), - OPCODE(o1_setMousePos), - OPCODE(o1_setFrameRate), - /* 48 */ - OPCODE(o1_animatePalette), - OPCODE(o1_animateCursor), - OPCODE(o1_blitCursor), - OPCODE(o1_loadFont), - /* 4C */ - OPCODE(o1_freeFont), - OPCODE(o2_readData), - OPCODE(o2_writeData), - OPCODE(o1_manageDataFile), - }; - - static const OpcodeGoblinEntryBargon opcodesGoblin[71] = { - /* 00 */ - OPCODE(oBargon_intro0), - OPCODE(oBargon_intro1), - OPCODE(oBargon_intro2), - OPCODE(oBargon_intro3), - /* 04 */ - OPCODE(oBargon_intro4), - OPCODE(oBargon_intro5), - OPCODE(oBargon_intro6), - OPCODE(oBargon_intro7), - /* 08 */ - OPCODE(oBargon_intro8), - OPCODE(oBargon_intro9), - OPCODE(o_gobNOP), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 14 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 18 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 20 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 24 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - }; - - _opcodesDrawBargon = opcodesDraw; - _opcodesFuncBargon = opcodesFunc; - _opcodesGoblinBargon = opcodesGoblin; -} - -void Inter_Bargon::executeDrawOpcode(byte i) { - debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); - - OpcodeDrawProcBargon op = _opcodesDrawBargon[i].proc; - - if (op == 0) - warning("unimplemented opcodeDraw: %d", i); - else - (this->*op) (); -} - -bool Inter_Bargon::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s)", - i, j, i, j, getOpcodeFuncDesc(i, j)); - - if ((i > 4) || (j > 15)) { - warning("unimplemented opcodeFunc: %d.%d", i, j); - return false; - } - - OpcodeFuncProcBargon op = _opcodesFuncBargon[i*16 + j].proc; - - if (op == 0) - warning("unimplemented opcodeFunc: %d.%d", i, j); - else - return (this->*op) (params); - - return false; } -void Inter_Bargon::executeGoblinOpcode(int i, OpGobParams ¶ms) { - debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); - - OpcodeGoblinProcBargon op = 0; - - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) { - op = _opcodesGoblinBargon[_goblinFuncLookUp[j][1]].proc; - break; - } - - if (op == 0) { - int16 val; - - _vm->_global->_inter_execPtr -= 2; - val = load16(); - _vm->_global->_inter_execPtr += val << 1; - warning("unimplemented opcodeGob: %d", i); - } else - (this->*op) (params); +void Inter_Bargon::setupOpcodesDraw() { + Inter_v2::setupOpcodesDraw(); } -const char *Inter_Bargon::getOpcodeDrawDesc(byte i) { - return _opcodesDrawBargon[i].desc; +void Inter_Bargon::setupOpcodesFunc() { + Inter_v2::setupOpcodesFunc(); } -const char *Inter_Bargon::getOpcodeFuncDesc(byte i, byte j) { - if ((i > 4) || (j > 15)) - return ""; +void Inter_Bargon::setupOpcodesGob() { + OPCODEGOB( 1, oBargon_intro0); + OPCODEGOB( 2, oBargon_intro1); + OPCODEGOB( 3, oBargon_intro2); + OPCODEGOB( 4, oBargon_intro3); - return _opcodesFuncBargon[i*16 + j].desc; -} + OPCODEGOB( 5, oBargon_intro4); + OPCODEGOB( 6, oBargon_intro5); + OPCODEGOB( 7, oBargon_intro6); + OPCODEGOB( 8, oBargon_intro7); -const char *Inter_Bargon::getOpcodeGoblinDesc(int i) { - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) - return _opcodesGoblinBargon[_goblinFuncLookUp[j][1]].desc; - return ""; + OPCODEGOB( 9, oBargon_intro8); + OPCODEGOB(10, oBargon_intro9); + OPCODEGOB(11, o_gobNOP); } void Inter_Bargon::oBargon_intro0(OpGobParams ¶ms) { diff --git a/engines/gob/inter_fascin.cpp b/engines/gob/inter_fascin.cpp index bd0b0a94c6..3c4713f9eb 100644 --- a/engines/gob/inter_fascin.cpp +++ b/engines/gob/inter_fascin.cpp @@ -31,8 +31,8 @@ #include "gob/util.h" #include "gob/dataio.h" #include "gob/draw.h" -#include "gob/parse.h" #include "gob/game.h" +#include "gob/script.h" #include "gob/palanim.h" #include "gob/video.h" #include "gob/videoplayer.h" @@ -40,494 +40,73 @@ namespace Gob { -#define OPCODE(x) _OPCODE(Inter_Fascination, x) - -const int Inter_Fascination::_goblinFuncLookUp[][2] = { - {1, 0}, - {2, 1}, - {3, 2}, - {4, 3}, - {5, 4}, - {6, 5}, - {7, 6}, - {8, 7}, - {9, 8}, - {10, 9}, - {11, 10}, - {12, 11}, - {1000, 12}, - {1001, 13}, - {1002, 14} -}; +#define OPCODEVER Inter_Fascination +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) Inter_Fascination::Inter_Fascination(GobEngine *vm) : Inter_v2(vm) { - setupOpcodes(); } -void Inter_Fascination::setupOpcodes() { - static const OpcodeDrawEntryFascination opcodesDraw[256] = { - /* 00 */ - OPCODE(o1_loadMult), - OPCODE(o2_playMult), - OPCODE(o1_freeMultKeys), - OPCODE(oFascin_cdUnknown3), - /* 04 */ - OPCODE(oFascin_cdUnknown4), - OPCODE(oFascin_cdUnknown5), - OPCODE(oFascin_cdUnknown6), - OPCODE(o1_initCursor), - /* 08 */ - OPCODE(o1_initCursorAnim), - OPCODE(o1_clearCursorAnim), - OPCODE(oFascin_setRenderFlags), - OPCODE(oFascin_cdUnknown11), - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - OPCODE(o1_loadAnim), - OPCODE(o1_freeAnim), - OPCODE(o1_updateAnim), - OPCODE(o2_multSub), - /* 14 */ - OPCODE(o2_initMult), - OPCODE(o1_freeMult), - OPCODE(o1_animate), - OPCODE(o2_loadMultObject), - /* 18 */ - OPCODE(o1_getAnimLayerInfo), - OPCODE(o1_getObjAnimSize), - OPCODE(o1_loadStatic), - OPCODE(o1_freeStatic), - /* 1C */ - OPCODE(o2_renderStatic), - OPCODE(o2_loadCurLayer), - {0, ""}, - {0, ""}, - /* 20 */ - OPCODE(o2_playCDTrack), - OPCODE(o2_waitCDTrackEnd), - OPCODE(o2_stopCD), - OPCODE(o2_readLIC), - /* 24 */ - OPCODE(o2_freeLIC), - OPCODE(o2_getCDTrackPos), - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o2_loadFontToSprite), - OPCODE(o1_freeFontToSprite), - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - OPCODE(o2_totSub), - OPCODE(o2_switchTotSub), - OPCODE(o2_pushVars), - OPCODE(o2_popVars), - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 48 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 4C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 50 */ - {0, ""},//OPCODE(o2_loadMapObjects), - {0, ""},//OPCODE(o2_freeGoblins), - {0, ""},//OPCODE(o2_moveGoblin), - {0, ""},//OPCODE(o2_writeGoblinPos), - /* 54 */ - {0, ""},//OPCODE(o2_stopGoblin), - {0, ""},//OPCODE(o2_setGoblinState), - {0, ""},//OPCODE(o2_placeGoblin), - {0, ""}, - /* 58 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 5C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 60 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 64 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 68 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 6C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 70 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 74 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 78 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 7C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 80 */ - {0, ""},//OPCODE(o2_initScreen), - {0, ""},//OPCODE(o2_scroll), - {0, ""},//OPCODE(o2_setScrollOffset), - {0, ""},//OPCODE(o2_playImd), - /* 84 */ - {0, ""},//OPCODE(o2_getImdInfo), - {0, ""},//OPCODE(o2_openItk), - {0, ""},//OPCODE(o2_closeItk), - {0, ""},//OPCODE(o2_setImdFrontSurf), - /* 88 */ - {0, ""},//OPCODE(o2_resetImdFrontSurf), - {0, ""}, - {0, ""}, - {0, ""}, - /* 8C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 90 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 94 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 98 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 9C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* AC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* BC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* CC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* DC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* EC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* FC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""} - }; - - static const OpcodeFuncEntryFascination opcodesFunc[80] = { - /* 00 */ - OPCODE(o1_callSub), - OPCODE(o1_callSub), - OPCODE(o1_printTotText), - OPCODE(o1_loadCursor), - /* 04 */ - {0, ""}, - OPCODE(o1_switch), - OPCODE(o1_repeatUntil), - OPCODE(o1_whileDo), - /* 08 */ - OPCODE(o1_if), - OPCODE(o1_assign), - OPCODE(o1_loadSpriteToPos), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - OPCODE(o2_printText), - OPCODE(o1_loadTot), - OPCODE(o1_palLoad), - /* 14 */ - OPCODE(o1_keyFunc), - OPCODE(o1_capturePush), - OPCODE(o1_capturePop), - OPCODE(o1_animPalInit), - /* 18 */ - OPCODE(o2_addCollision), - OPCODE(o2_freeCollision), - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - OPCODE(o1_drawOperations), - OPCODE(o1_setcmdCount), - /* 20 */ - OPCODE(o1_return), - OPCODE(o1_renewTimeInVars), - OPCODE(o1_speakerOn), - OPCODE(o1_speakerOff), - /* 24 */ - OPCODE(o1_putPixel), - OPCODE(o2_goblinFunc), - OPCODE(o1_createSprite), - OPCODE(o1_freeSprite), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_returnTo), - OPCODE(o1_loadSpriteContent), - OPCODE(o1_copySprite), - OPCODE(o1_fillRect), - /* 34 */ - OPCODE(o1_drawLine), - OPCODE(o1_strToLong), - OPCODE(o1_invalidate), - OPCODE(o1_setBackDelta), - /* 38 */ - OPCODE(o1_playSound), - OPCODE(o2_stopSound), - OPCODE(o2_loadSound), - OPCODE(o1_freeSoundSlot), - /* 3C */ - OPCODE(o1_waitEndPlay), - OPCODE(o1_playComposition), - OPCODE(o2_getFreeMem), - OPCODE(o2_checkData), - /* 40 */ - {0, ""}, - OPCODE(o1_prepareStr), - OPCODE(o1_insertStr), - OPCODE(o1_cutStr), - /* 44 */ - OPCODE(o1_strstr), - OPCODE(o1_istrlen), - OPCODE(o1_setMousePos), - OPCODE(o1_setFrameRate), - /* 48 */ - OPCODE(o1_animatePalette), - OPCODE(o1_animateCursor), - OPCODE(o1_blitCursor), - OPCODE(o1_loadFont), - /* 4C */ - OPCODE(o1_freeFont), - OPCODE(o2_readData), - OPCODE(o2_writeData), - OPCODE(o1_manageDataFile), - }; - - static const OpcodeGoblinEntryFascination opcodesGoblin[15] = { - /* 00 */ - OPCODE(oFascin_geUnknown0), - OPCODE(oFascin_geUnknown1), - OPCODE(oFascin_geUnknown2), - OPCODE(oFascin_geUnknown3), - /* 04 */ - OPCODE(oFascin_geUnknown4), - OPCODE(oFascin_geUnknown5), - OPCODE(oFascin_geUnknown6), - OPCODE(oFascin_geUnknown7), - /* 08 */ - OPCODE(oFascin_geUnknown8), - OPCODE(oFascin_geUnknown9), - OPCODE(oFascin_geUnknown10), - OPCODE(oFascin_geUnknown11), - /* 0C */ - OPCODE(oFascin_geUnknown1000), - OPCODE(oFascin_geUnknown1001), //protrackerPlay doesn't play correctly "mod.extasy" - OPCODE(oFascin_geUnknown1002), //to be replaced by o2_stopProtracker when protrackerPlay is fixed - }; - - _opcodesDrawFascination = opcodesDraw; - _opcodesFuncFascination = opcodesFunc; - _opcodesGoblinFascination = opcodesGoblin; +void Inter_Fascination::setupOpcodesDraw() { + Inter_v2::setupOpcodesDraw(); + + OPCODEDRAW(0x03, oFascin_cdUnknown3); + + OPCODEDRAW(0x04, oFascin_cdUnknown4); + OPCODEDRAW(0x05, oFascin_cdUnknown5); + OPCODEDRAW(0x06, oFascin_cdUnknown6); + + OPCODEDRAW(0x0A, oFascin_setRenderFlags); + OPCODEDRAW(0x0B, oFascin_cdUnknown11); + + CLEAROPCODEDRAW(0x50); + CLEAROPCODEDRAW(0x51); + CLEAROPCODEDRAW(0x52); + CLEAROPCODEDRAW(0x53); + + CLEAROPCODEDRAW(0x54); + CLEAROPCODEDRAW(0x55); + CLEAROPCODEDRAW(0x56); + + CLEAROPCODEDRAW(0x80); + CLEAROPCODEDRAW(0x81); + CLEAROPCODEDRAW(0x82); + CLEAROPCODEDRAW(0x83); + + CLEAROPCODEDRAW(0x84); + CLEAROPCODEDRAW(0x85); + CLEAROPCODEDRAW(0x86); + CLEAROPCODEDRAW(0x87); + + CLEAROPCODEDRAW(0x88); } -void Inter_Fascination::executeDrawOpcode(byte i) { - debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); +void Inter_Fascination::setupOpcodesFunc() { + Inter_v2::setupOpcodesFunc(); - OpcodeDrawProcFascination op = _opcodesDrawFascination[i].proc; + OPCODEFUNC(0x09, o1_assign); +} + +void Inter_Fascination::setupOpcodesGob() { + OPCODEGOB( 1, oFascin_geUnknown0); + OPCODEGOB( 2, oFascin_geUnknown1); + OPCODEGOB( 3, oFascin_geUnknown2); + OPCODEGOB( 4, oFascin_geUnknown3); + + OPCODEGOB( 5, oFascin_geUnknown4); + OPCODEGOB( 6, oFascin_geUnknown5); + OPCODEGOB( 7, oFascin_geUnknown6); + OPCODEGOB( 8, oFascin_geUnknown7); + + OPCODEGOB( 9, oFascin_geUnknown8); + OPCODEGOB( 10, oFascin_geUnknown9); + OPCODEGOB( 11, oFascin_geUnknown10); + OPCODEGOB( 12, oFascin_geUnknown11); - if (op == 0) - warning("Not yet implemented Fascination opcodeDraw: %d", i); - else - (this->*op) (); + OPCODEGOB(1000, oFascin_geUnknown1000); + OPCODEGOB(1001, oFascin_geUnknown1001); //protrackerPlay doesn't play correctly "mod.extasy" + OPCODEGOB(1002, oFascin_geUnknown1002); //to be replaced by o2_stopProtracker when protrackerPlay is fixed } void Inter_Fascination::oFascin_geUnknown0(OpGobParams ¶ms) { @@ -552,70 +131,58 @@ void Inter_Fascination::oFascin_geUnknown1(OpGobParams ¶ms) { } void Inter_Fascination::oFascin_geUnknown2(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 2"); - warning("funcLoadInstruments with parameter : 'extasy.tbr'. (Guess)"); - warning("funcLoadMusic with parameter : 'extasy.mdy'. (Guess)"); + _vm->_sound->adlibLoadTBR("extasy.tbr"); + _vm->_sound->adlibLoadMDY("extasy.mdy"); } void Inter_Fascination::oFascin_geUnknown3(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 3"); - warning("Verify if 'Guess music' is loaded. If yes, call funcPlayMusic. (Guess)"); + _vm->_sound->adlibPlay(); } void Inter_Fascination::oFascin_geUnknown4(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 4"); - warning("Verify if 'Guess music' is loaded. If yes, call funcStopMusic. (Guess)"); + _vm->_sound->adlibStop(); } void Inter_Fascination::oFascin_geUnknown5(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 5"); - warning("Verify if 'instruments' are loaded, If so, call mem_free"); - warning("Verify if 'Guess music' is loaded. If yes, call _cleanupMdy"); - warning("Then set _ptrTbr and _ptrMdy to 0"); + _vm->_sound->adlibUnload(); } void Inter_Fascination::oFascin_geUnknown6(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 6"); - warning("funcLoadInstruments with parameter : 'music1.tbr'. (Guess)"); - warning("funcLoadMusic with parameter : 'music1.mdy'. (Guess)"); + _vm->_sound->adlibLoadTBR("music1.tbr"); + _vm->_sound->adlibLoadMDY("music1.mdy"); } void Inter_Fascination::oFascin_geUnknown7(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 7"); - warning("funcLoadInstruments with parameter : 'music2.tbr'. (Guess)"); - warning("funcLoadMusic with parameter : 'music2.mdy'. (Guess)"); + _vm->_sound->adlibLoadTBR("music2.tbr"); + _vm->_sound->adlibLoadMDY("music2.mdy"); } void Inter_Fascination::oFascin_geUnknown8(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 8"); - warning("funcLoadInstruments with parameter : 'music3.tbr'. (Guess)"); - warning("funcLoadMusic with parameter : 'music3.mdy'. (Guess)"); + _vm->_sound->adlibLoadTBR("music3.tbr"); + _vm->_sound->adlibLoadMDY("music3.mdy"); } void Inter_Fascination::oFascin_geUnknown9(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 9"); - warning("funcLoadInstruments with parameter : 'batt1.tbr'. (Guess)"); - warning("funcLoadMusic with parameter : 'batt1.mdy'. (Guess)"); + _vm->_sound->adlibLoadTBR("batt1.tbr"); + _vm->_sound->adlibLoadMDY("batt1.mdy"); } void Inter_Fascination::oFascin_geUnknown10(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 10"); - warning("funcLoadInstruments with parameter : 'batt2.tbr'. (Guess)"); - warning("funcLoadMusic with parameter : 'batt2.mdy'. (Guess)"); + _vm->_sound->adlibLoadTBR("batt2.tbr"); + _vm->_sound->adlibLoadMDY("batt2.mdy"); } void Inter_Fascination::oFascin_geUnknown11(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 11"); - warning("funcLoadInstruments with parameter : 'batt3.tbr'. (Guess)"); - warning("funcLoadMusic with parameter : 'batt3.mdy'. (Guess)"); + _vm->_sound->adlibLoadTBR("batt3.tbr"); + _vm->_sound->adlibLoadMDY("batt3.mdy"); } void Inter_Fascination::oFascin_geUnknown1000(OpGobParams ¶ms) { - warning("Fascination Unknown GE Function 1000 - Load music ?"); + warning("Fascination Unknown GE Function 1000 - Load MOD music"); } void Inter_Fascination::oFascin_geUnknown1001(OpGobParams ¶ms) { - warning("Fascination oFascin_playProtracker - MOD not compatible, ToBeFixed"); + warning("Fascination oFascin_playProtracker - MOD not compatible (sample > 32768), To Be Fixed"); } void Inter_Fascination::oFascin_geUnknown1002(OpGobParams ¶ms) { @@ -638,15 +205,15 @@ void Inter_Fascination::oFascin_cdUnknown3() { warning("Fascination oFascin_cdUnknown3 - Variables initialisations"); - resVar = (uint16) load16(); - resVar2 = (uint16) load16(); - retVal1 = _vm->_parse->parseVarIndex(); - retVal2 = _vm->_parse->parseVarIndex(); - retVal3 = _vm->_parse->parseVarIndex(); - retVal4 = _vm->_parse->parseVarIndex(); - retVal5 = _vm->_parse->parseVarIndex(); - retVal6 = _vm->_parse->parseVarIndex(); - retVal7 = _vm->_parse->parseVarIndex(); + resVar = _vm->_game->_script->readUint16(); + resVar2 = _vm->_game->_script->readUint16(); + retVal1 = _vm->_game->_script->readVarIndex(); + retVal2 = _vm->_game->_script->readVarIndex(); + retVal3 = _vm->_game->_script->readVarIndex(); + retVal4 = _vm->_game->_script->readVarIndex(); + retVal5 = _vm->_game->_script->readVarIndex(); + retVal6 = _vm->_game->_script->readVarIndex(); + retVal7 = _vm->_game->_script->readVarIndex(); warning ("Width? :%d Height? :%d",resVar, resVar2); warning ("Fetched variables 1:%d 2:%d 3:%d 4:%d 5:%d 6:%d 7:%d", retVal1, retVal2, retVal3, retVal4, retVal5, retVal6, retVal7); } @@ -654,98 +221,37 @@ void Inter_Fascination::oFascin_cdUnknown3() { void Inter_Fascination::oFascin_cdUnknown4() { int16 expr; warning("Fascination oFascin_cdUnknown4"); - evalExpr(&expr); - warning ("evalExpr: %d, the rest is not yet implemented",expr); + _vm->_game->_script->evalExpr(&expr); + warning ("_vm->_game->_script->evalExpr: %d, the rest is not yet implemented",expr); } void Inter_Fascination::oFascin_cdUnknown5() { int16 retVal1,expr; warning("Fascination oFascin_cdUnknown5"); - evalExpr(&expr); - retVal1 = _vm->_parse->parseVarIndex(); - warning ("evalExpr: %d Variable index %d, the rest is not yet implemented",expr, retVal1); + _vm->_game->_script->evalExpr(&expr); + retVal1 = _vm->_game->_script->readVarIndex(); + warning ("_vm->_game->_script->evalExpr: %d Variable index %d, the rest is not yet implemented",expr, retVal1); } void Inter_Fascination::oFascin_cdUnknown6() { int16 retVal1,expr; warning("Fascination oFascin_cdUnknown6"); - evalExpr(&expr); - retVal1 = _vm->_parse->parseVarIndex(); - warning ("evalExpr: %d Variable index %d, the rest is not yet implemented",expr, retVal1); + _vm->_game->_script->evalExpr(&expr); + retVal1 = _vm->_game->_script->readVarIndex(); + warning ("_vm->_game->_script->evalExpr: %d Variable index %d, the rest is not yet implemented",expr, retVal1); } void Inter_Fascination::oFascin_setRenderFlags() { int16 expr; // warning("Fascination oFascin_cdUnknown10 (set render flags)"); - evalExpr(&expr); + _vm->_game->_script->evalExpr(&expr); warning("_draw_renderFlags <- %d",expr); _vm->_draw->_renderFlags = expr; } void Inter_Fascination::oFascin_cdUnknown11() { // warning("Fascination oFascin_cdUnknown11 (set variable)"); - evalExpr(0); -} - -bool Inter_Fascination::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s)", - i, j, i, j, getOpcodeFuncDesc(i, j)); - - if ((i > 4) || (j > 16)) { - warning("Invalid opcodeFunc: %d.%d", i, j); - return false; - } - - OpcodeFuncProcFascination op = _opcodesFuncFascination[i*16 + j].proc; - - if (op == 0) - warning("unimplemented opcodeFunc: %d.%d", i, j); - else - return (this->*op) (params); - - return false; -} - -void Inter_Fascination::executeGoblinOpcode(int i, OpGobParams ¶ms) { - debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); - - OpcodeGoblinProcFascination op = 0; - - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) { - op = _opcodesGoblinFascination[_goblinFuncLookUp[j][1]].proc; - break; - } - - if (op == 0) { - int16 val; - - _vm->_global->_inter_execPtr -= 2; - val = load16(); - _vm->_global->_inter_execPtr += val << 1; - warning("unimplemented opcodeGob: %d", i); - } else - (this->*op) (params); -} - -const char *Inter_Fascination::getOpcodeDrawDesc(byte i) { - return _opcodesDrawFascination[i].desc; -} - -const char *Inter_Fascination::getOpcodeFuncDesc(byte i, byte j) { - if ((i > 4) || (j > 15)) - return ""; - - return _opcodesFuncFascination[i*16 + j].desc; -} - -const char *Inter_Fascination::getOpcodeGoblinDesc(int i) { - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) - return _opcodesGoblinFascination[_goblinFuncLookUp[j][1]].desc; - warning("Error in getOpcodeGoblinDesc %d",i); - return ""; + _vm->_game->_script->evalExpr(0); } void Inter_Fascination::oFascin_playProtracker(OpGobParams ¶ms) { diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index ace5a7a3be..d5d5fcad9a 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -34,692 +34,214 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/expression.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/goblin.h" #include "gob/inter.h" #include "gob/map.h" #include "gob/mult.h" #include "gob/palanim.h" -#include "gob/parse.h" #include "gob/scenery.h" #include "gob/video.h" #include "gob/sound/sound.h" namespace Gob { -#define OPCODE(x) _OPCODE(Inter_v1, x) - -const int Inter_v1::_goblinFuncLookUp[][2] = { - {1, 0}, - {2, 1}, - {3, 2}, - {4, 3}, - {5, 4}, - {6, 5}, - {7, 6}, - {8, 7}, - {9, 8}, - {10, 9}, - {12, 10}, - {13, 11}, - {14, 12}, - {15, 13}, - {16, 14}, - {21, 15}, - {22, 16}, - {23, 17}, - {24, 18}, - {25, 19}, - {26, 20}, - {27, 21}, - {28, 22}, - {29, 23}, - {30, 24}, - {32, 25}, - {33, 26}, - {34, 27}, - {35, 28}, - {36, 29}, - {37, 30}, - {40, 31}, - {41, 32}, - {42, 33}, - {43, 34}, - {44, 35}, - {50, 36}, - {52, 37}, - {53, 38}, - {150, 39}, - {152, 40}, - {200, 41}, - {201, 42}, - {202, 43}, - {203, 44}, - {204, 45}, - {250, 46}, - {251, 47}, - {252, 48}, - {500, 49}, - {502, 50}, - {503, 51}, - {600, 52}, - {601, 53}, - {602, 54}, - {603, 55}, - {604, 56}, - {605, 57}, - {1000, 58}, - {1001, 59}, - {1002, 60}, - {1003, 61}, - {1004, 62}, - {1005, 63}, - {1006, 64}, - {1008, 65}, - {1009, 66}, - {1010, 67}, - {1011, 68}, - {1015, 69}, - {2005, 70} -}; +#define OPCODEVER Inter_v1 +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) Inter_v1::Inter_v1(GobEngine *vm) : Inter(vm) { - setupOpcodes(); -} - -void Inter_v1::setupOpcodes() { - static const OpcodeDrawEntryV1 opcodesDraw[256] = { - /* 00 */ - OPCODE(o1_loadMult), - OPCODE(o1_playMult), - OPCODE(o1_freeMultKeys), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o1_initCursor), - /* 08 */ - OPCODE(o1_initCursorAnim), - OPCODE(o1_clearCursorAnim), - OPCODE(o1_setRenderFlags), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - OPCODE(o1_loadAnim), - OPCODE(o1_freeAnim), - OPCODE(o1_updateAnim), - {0, ""}, - /* 14 */ - OPCODE(o1_initMult), - OPCODE(o1_freeMult), - OPCODE(o1_animate), - OPCODE(o1_loadMultObject), - /* 18 */ - OPCODE(o1_getAnimLayerInfo), - OPCODE(o1_getObjAnimSize), - OPCODE(o1_loadStatic), - OPCODE(o1_freeStatic), - /* 1C */ - OPCODE(o1_renderStatic), - OPCODE(o1_loadCurLayer), - {0, ""}, - {0, ""}, - /* 20 */ - OPCODE(o1_playCDTrack), - OPCODE(o1_getCDTrackPos), - OPCODE(o1_stopCD), - {0, ""}, - /* 24 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_loadFontToSprite), - OPCODE(o1_freeFontToSprite), - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 48 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 4C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 50 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 54 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 58 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 5C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 60 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 64 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 68 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 6C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 70 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 74 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 78 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 7C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 80 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 84 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 88 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 8C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 90 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 94 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 98 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 9C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* AC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* BC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* CC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* DC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* EC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* FC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""} - }; - - static const OpcodeFuncEntryV1 opcodesFunc[80] = { - /* 00 */ - OPCODE(o1_callSub), - OPCODE(o1_callSub), - OPCODE(o1_printTotText), - OPCODE(o1_loadCursor), - /* 04 */ - {0, ""}, - OPCODE(o1_switch), - OPCODE(o1_repeatUntil), - OPCODE(o1_whileDo), - /* 08 */ - OPCODE(o1_if), - OPCODE(o1_assign), - OPCODE(o1_loadSpriteToPos), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - OPCODE(o1_printText), - OPCODE(o1_loadTot), - OPCODE(o1_palLoad), - /* 14 */ - OPCODE(o1_keyFunc), - OPCODE(o1_capturePush), - OPCODE(o1_capturePop), - OPCODE(o1_animPalInit), - /* 18 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - OPCODE(o1_drawOperations), - OPCODE(o1_setcmdCount), - /* 20 */ - OPCODE(o1_return), - OPCODE(o1_renewTimeInVars), - OPCODE(o1_speakerOn), - OPCODE(o1_speakerOff), - /* 24 */ - OPCODE(o1_putPixel), - OPCODE(o1_goblinFunc), - OPCODE(o1_createSprite), - OPCODE(o1_freeSprite), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_returnTo), - OPCODE(o1_loadSpriteContent), - OPCODE(o1_copySprite), - OPCODE(o1_fillRect), - /* 34 */ - OPCODE(o1_drawLine), - OPCODE(o1_strToLong), - OPCODE(o1_invalidate), - OPCODE(o1_setBackDelta), - /* 38 */ - OPCODE(o1_playSound), - OPCODE(o1_stopSound), - OPCODE(o1_loadSound), - OPCODE(o1_freeSoundSlot), - /* 3C */ - OPCODE(o1_waitEndPlay), - OPCODE(o1_playComposition), - OPCODE(o1_getFreeMem), - OPCODE(o1_checkData), - /* 40 */ - {0, ""}, - OPCODE(o1_prepareStr), - OPCODE(o1_insertStr), - OPCODE(o1_cutStr), - /* 44 */ - OPCODE(o1_strstr), - OPCODE(o1_istrlen), - OPCODE(o1_setMousePos), - OPCODE(o1_setFrameRate), - /* 48 */ - OPCODE(o1_animatePalette), - OPCODE(o1_animateCursor), - OPCODE(o1_blitCursor), - OPCODE(o1_loadFont), - /* 4C */ - OPCODE(o1_freeFont), - OPCODE(o1_readData), - OPCODE(o1_writeData), - OPCODE(o1_manageDataFile), - }; - - static const OpcodeGoblinEntryV1 opcodesGoblin[71] = { - /* 00 */ - OPCODE(o1_setState), - OPCODE(o1_setCurFrame), - OPCODE(o1_setNextState), - OPCODE(o1_setMultState), - /* 04 */ - OPCODE(o1_setOrder), - OPCODE(o1_setActionStartState), - OPCODE(o1_setCurLookDir), - OPCODE(o1_setType), - /* 08 */ - OPCODE(o1_setNoTick), - OPCODE(o1_setPickable), - OPCODE(o1_setXPos), - OPCODE(o1_setYPos), - /* 0C */ - OPCODE(o1_setDoAnim), - OPCODE(o1_setRelaxTime), - OPCODE(o1_setMaxTick), - OPCODE(o1_getState), - /* 10 */ - OPCODE(o1_getCurFrame), - OPCODE(o1_getNextState), - OPCODE(o1_getMultState), - OPCODE(o1_getOrder), - /* 14 */ - OPCODE(o1_getActionStartState), - OPCODE(o1_getCurLookDir), - OPCODE(o1_getType), - OPCODE(o1_getNoTick), - /* 18 */ - OPCODE(o1_getPickable), - OPCODE(o1_getObjMaxFrame), - OPCODE(o1_getXPos), - OPCODE(o1_getYPos), - /* 1C */ - OPCODE(o1_getDoAnim), - OPCODE(o1_getRelaxTime), - OPCODE(o1_getMaxTick), - OPCODE(o1_manipulateMap), - /* 20 */ - OPCODE(o1_getItem), - OPCODE(o1_manipulateMapIndirect), - OPCODE(o1_getItemIndirect), - OPCODE(o1_setPassMap), - /* 24 */ - OPCODE(o1_setGoblinPosH), - OPCODE(o1_getGoblinPosXH), - OPCODE(o1_getGoblinPosYH), - OPCODE(o1_setGoblinMultState), - /* 28 */ - OPCODE(o1_setGoblinUnk14), - OPCODE(o1_setItemIdInPocket), - OPCODE(o1_setItemIndInPocket), - OPCODE(o1_getItemIdInPocket), - /* 2C */ - OPCODE(o1_getItemIndInPocket), - OPCODE(o1_setItemPos), - OPCODE(o1_setGoblinPos), - OPCODE(o1_setGoblinState), - /* 30 */ - OPCODE(o1_setGoblinStateRedraw), - OPCODE(o1_decRelaxTime), - OPCODE(o1_getGoblinPosX), - OPCODE(o1_getGoblinPosY), - /* 34 */ - OPCODE(o1_clearPathExistence), - OPCODE(o1_setGoblinVisible), - OPCODE(o1_setGoblinInvisible), - OPCODE(o1_getObjectIntersect), - /* 38 */ - OPCODE(o1_getGoblinIntersect), - OPCODE(o1_setItemPos), - OPCODE(o1_loadObjects), - OPCODE(o1_freeObjects), - /* 3C */ - OPCODE(o1_animateObjects), - OPCODE(o1_drawObjects), - OPCODE(o1_loadMap), - OPCODE(o1_moveGoblin), - /* 40 */ - OPCODE(o1_switchGoblin), - OPCODE(o1_loadGoblin), - OPCODE(o1_writeTreatItem), - OPCODE(o1_moveGoblin0), - /* 44 */ - OPCODE(o1_setGoblinTarget), - OPCODE(o1_setGoblinObjectsPos), - OPCODE(o1_initGoblin) - }; - - _opcodesDrawV1 = opcodesDraw; - _opcodesFuncV1 = opcodesFunc; - _opcodesGoblinV1 = opcodesGoblin; -} - -void Inter_v1::executeDrawOpcode(byte i) { - debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); - - OpcodeDrawProcV1 op = _opcodesDrawV1[i].proc; - - if (op == 0) - warning("unimplemented opcodeDraw: %d", i); - else - (this->*op) (); -} - -bool Inter_v1::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s)", - i, j, i, j, getOpcodeFuncDesc(i, j)); - - if ((i > 4) || (j > 15)) { - warning("unimplemented opcodeFunc: %d.%d", i, j); - return false; - } - - OpcodeFuncProcV1 op = _opcodesFuncV1[i*16 + j].proc; - - if (op == 0) - warning("unimplemented opcodeFunc: %d.%d", i, j); - else - return (this->*op) (params); - return false; } -void Inter_v1::executeGoblinOpcode(int i, OpGobParams ¶ms) { - debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); +void Inter_v1::setupOpcodesDraw() { + OPCODEDRAW(0x00, o1_loadMult); + OPCODEDRAW(0x01, o1_playMult); + OPCODEDRAW(0x02, o1_freeMultKeys); - OpcodeGoblinProcV1 op = 0; + OPCODEDRAW(0x07, o1_initCursor); + + OPCODEDRAW(0x08, o1_initCursorAnim); + OPCODEDRAW(0x09, o1_clearCursorAnim); + OPCODEDRAW(0x0A, o1_setRenderFlags); - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) { - op = _opcodesGoblinV1[_goblinFuncLookUp[j][1]].proc; - break; - } - - if (op == 0) { - warning("unimplemented opcodeGoblin: %d", i); - _vm->_global->_inter_execPtr -= 2; - int16 cmd = load16(); - _vm->_global->_inter_execPtr += cmd * 2; - } else - (this->*op) (params); -} - -const char *Inter_v1::getOpcodeDrawDesc(byte i) { - return _opcodesDrawV1[i].desc; -} - -const char *Inter_v1::getOpcodeFuncDesc(byte i, byte j) { - if ((i > 4) || (j > 15)) - return ""; - - return _opcodesFuncV1[i*16 + j].desc; -} - -const char *Inter_v1::getOpcodeGoblinDesc(int i) { - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) - return _opcodesGoblinV1[_goblinFuncLookUp[j][1]].desc; - return ""; -} - -void Inter_v1::checkSwitchTable(byte **ppExec) { + OPCODEDRAW(0x10, o1_loadAnim); + OPCODEDRAW(0x11, o1_freeAnim); + OPCODEDRAW(0x12, o1_updateAnim); + + OPCODEDRAW(0x14, o1_initMult); + OPCODEDRAW(0x15, o1_freeMult); + OPCODEDRAW(0x16, o1_animate); + OPCODEDRAW(0x17, o1_loadMultObject); + + OPCODEDRAW(0x18, o1_getAnimLayerInfo); + OPCODEDRAW(0x19, o1_getObjAnimSize); + OPCODEDRAW(0x1A, o1_loadStatic); + OPCODEDRAW(0x1B, o1_freeStatic); + + OPCODEDRAW(0x1C, o1_renderStatic); + OPCODEDRAW(0x1D, o1_loadCurLayer); + + OPCODEDRAW(0x20, o1_playCDTrack); + OPCODEDRAW(0x21, o1_getCDTrackPos); + OPCODEDRAW(0x22, o1_stopCD); + + OPCODEDRAW(0x30, o1_loadFontToSprite); + OPCODEDRAW(0x31, o1_freeFontToSprite); +} + +void Inter_v1::setupOpcodesFunc() { + OPCODEFUNC(0x00, o1_callSub); + OPCODEFUNC(0x01, o1_callSub); + OPCODEFUNC(0x02, o1_printTotText); + OPCODEFUNC(0x03, o1_loadCursor); + + OPCODEFUNC(0x05, o1_switch); + OPCODEFUNC(0x06, o1_repeatUntil); + OPCODEFUNC(0x07, o1_whileDo); + + OPCODEFUNC(0x08, o1_if); + OPCODEFUNC(0x09, o1_assign); + OPCODEFUNC(0x0A, o1_loadSpriteToPos); + OPCODEFUNC(0x11, o1_printText); + OPCODEFUNC(0x12, o1_loadTot); + OPCODEFUNC(0x13, o1_palLoad); + + OPCODEFUNC(0x14, o1_keyFunc); + OPCODEFUNC(0x15, o1_capturePush); + OPCODEFUNC(0x16, o1_capturePop); + OPCODEFUNC(0x17, o1_animPalInit); + + OPCODEFUNC(0x1E, o1_drawOperations); + OPCODEFUNC(0x1F, o1_setcmdCount); + + OPCODEFUNC(0x20, o1_return); + OPCODEFUNC(0x21, o1_renewTimeInVars); + OPCODEFUNC(0x22, o1_speakerOn); + OPCODEFUNC(0x23, o1_speakerOff); + + OPCODEFUNC(0x24, o1_putPixel); + OPCODEFUNC(0x25, o1_goblinFunc); + OPCODEFUNC(0x26, o1_createSprite); + OPCODEFUNC(0x27, o1_freeSprite); + + OPCODEFUNC(0x30, o1_returnTo); + OPCODEFUNC(0x31, o1_loadSpriteContent); + OPCODEFUNC(0x32, o1_copySprite); + OPCODEFUNC(0x33, o1_fillRect); + + OPCODEFUNC(0x34, o1_drawLine); + OPCODEFUNC(0x35, o1_strToLong); + OPCODEFUNC(0x36, o1_invalidate); + OPCODEFUNC(0x37, o1_setBackDelta); + + OPCODEFUNC(0x38, o1_playSound); + OPCODEFUNC(0x39, o1_stopSound); + OPCODEFUNC(0x3A, o1_loadSound); + OPCODEFUNC(0x3B, o1_freeSoundSlot); + + OPCODEFUNC(0x3C, o1_waitEndPlay); + OPCODEFUNC(0x3D, o1_playComposition); + OPCODEFUNC(0x3E, o1_getFreeMem); + OPCODEFUNC(0x3F, o1_checkData); + + OPCODEFUNC(0x41, o1_prepareStr); + OPCODEFUNC(0x42, o1_insertStr); + OPCODEFUNC(0x43, o1_cutStr); + + OPCODEFUNC(0x44, o1_strstr); + OPCODEFUNC(0x45, o1_istrlen); + OPCODEFUNC(0x46, o1_setMousePos); + OPCODEFUNC(0x47, o1_setFrameRate); + + OPCODEFUNC(0x48, o1_animatePalette); + OPCODEFUNC(0x49, o1_animateCursor); + OPCODEFUNC(0x4A, o1_blitCursor); + OPCODEFUNC(0x4B, o1_loadFont); + + OPCODEFUNC(0x4C, o1_freeFont); + OPCODEFUNC(0x4D, o1_readData); + OPCODEFUNC(0x4E, o1_writeData); + OPCODEFUNC(0x4F, o1_manageDataFile); +} + +void Inter_v1::setupOpcodesGob() { + OPCODEGOB( 1, o1_setState); + OPCODEGOB( 2, o1_setCurFrame); + OPCODEGOB( 3, o1_setNextState); + OPCODEGOB( 4, o1_setMultState); + OPCODEGOB( 5, o1_setOrder); + OPCODEGOB( 6, o1_setActionStartState); + OPCODEGOB( 7, o1_setCurLookDir); + OPCODEGOB( 8, o1_setType); + OPCODEGOB( 9, o1_setNoTick); + OPCODEGOB( 10, o1_setPickable); + OPCODEGOB( 12, o1_setXPos); + OPCODEGOB( 13, o1_setYPos); + OPCODEGOB( 14, o1_setDoAnim); + OPCODEGOB( 15, o1_setRelaxTime); + OPCODEGOB( 16, o1_setMaxTick); + OPCODEGOB( 21, o1_getState); + OPCODEGOB( 22, o1_getCurFrame); + OPCODEGOB( 23, o1_getNextState); + OPCODEGOB( 24, o1_getMultState); + OPCODEGOB( 25, o1_getOrder); + OPCODEGOB( 26, o1_getActionStartState); + OPCODEGOB( 27, o1_getCurLookDir); + OPCODEGOB( 28, o1_getType); + OPCODEGOB( 29, o1_getNoTick); + OPCODEGOB( 30, o1_getPickable); + OPCODEGOB( 32, o1_getObjMaxFrame); + OPCODEGOB( 33, o1_getXPos); + OPCODEGOB( 34, o1_getYPos); + OPCODEGOB( 35, o1_getDoAnim); + OPCODEGOB( 36, o1_getRelaxTime); + OPCODEGOB( 37, o1_getMaxTick); + OPCODEGOB( 40, o1_manipulateMap); + OPCODEGOB( 41, o1_getItem); + OPCODEGOB( 42, o1_manipulateMapIndirect); + OPCODEGOB( 43, o1_getItemIndirect); + OPCODEGOB( 44, o1_setPassMap); + OPCODEGOB( 50, o1_setGoblinPosH); + OPCODEGOB( 52, o1_getGoblinPosXH); + OPCODEGOB( 53, o1_getGoblinPosYH); + OPCODEGOB( 150, o1_setGoblinMultState); + OPCODEGOB( 152, o1_setGoblinUnk14); + OPCODEGOB( 200, o1_setItemIdInPocket); + OPCODEGOB( 201, o1_setItemIndInPocket); + OPCODEGOB( 202, o1_getItemIdInPocket); + OPCODEGOB( 203, o1_getItemIndInPocket); + OPCODEGOB( 204, o1_setItemPos); + OPCODEGOB( 250, o1_setGoblinPos); + OPCODEGOB( 251, o1_setGoblinState); + OPCODEGOB( 252, o1_setGoblinStateRedraw); + OPCODEGOB( 500, o1_decRelaxTime); + OPCODEGOB( 502, o1_getGoblinPosX); + OPCODEGOB( 503, o1_getGoblinPosY); + OPCODEGOB( 600, o1_clearPathExistence); + OPCODEGOB( 601, o1_setGoblinVisible); + OPCODEGOB( 602, o1_setGoblinInvisible); + OPCODEGOB( 603, o1_getObjectIntersect); + OPCODEGOB( 604, o1_getGoblinIntersect); + OPCODEGOB( 605, o1_setItemPos); + OPCODEGOB(1000, o1_loadObjects); + OPCODEGOB(1001, o1_freeObjects); + OPCODEGOB(1002, o1_animateObjects); + OPCODEGOB(1003, o1_drawObjects); + OPCODEGOB(1004, o1_loadMap); + OPCODEGOB(1005, o1_moveGoblin); + OPCODEGOB(1006, o1_switchGoblin); + OPCODEGOB(1008, o1_loadGoblin); + OPCODEGOB(1009, o1_writeTreatItem); + OPCODEGOB(1010, o1_moveGoblin0); + OPCODEGOB(1011, o1_setGoblinTarget); + OPCODEGOB(1015, o1_setGoblinObjectsPos); + OPCODEGOB(2005, o1_initGoblin); +} + +void Inter_v1::checkSwitchTable(uint32 &offset) { int16 len; int32 value; bool found; @@ -727,56 +249,54 @@ void Inter_v1::checkSwitchTable(byte **ppExec) { found = false; notFound = true; - *ppExec = 0; - value = VAR_OFFSET(_vm->_parse->parseVarIndex()); + offset = 0; + value = VAR_OFFSET(_vm->_game->_script->readVarIndex()); - len = (int8) *_vm->_global->_inter_execPtr++; + len = _vm->_game->_script->readInt8(); while (len != -5) { for (int i = 0; i < len; i++) { - evalExpr(0); + _vm->_game->_script->evalExpr(0); if (_terminate) return; - if (_vm->_global->_inter_resVal == value) { + if (_vm->_game->_script->getResultInt() == value) { found = true; notFound = false; } } if (found) - *ppExec = _vm->_global->_inter_execPtr; + offset = _vm->_game->_script->pos(); - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + _vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2); found = false; - len = (int8) *_vm->_global->_inter_execPtr++; + len = _vm->_game->_script->readInt8(); } - if ((*_vm->_global->_inter_execPtr >> 4) != 4) + if ((_vm->_game->_script->peekByte() >> 4) != 4) return; - _vm->_global->_inter_execPtr++; + _vm->_game->_script->skip(1); if (notFound) - *ppExec = _vm->_global->_inter_execPtr; + offset = _vm->_game->_script->pos(); - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + _vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2); } void Inter_v1::o1_loadMult() { - _vm->_mult->loadMult(load16()); + _vm->_mult->loadMult(_vm->_game->_script->readInt16()); } void Inter_v1::o1_playMult() { int16 checkEscape; - checkEscape = load16(); + checkEscape = _vm->_game->_script->readInt16(); _vm->_mult->playMult(VAR(57), -1, checkEscape, 0); } void Inter_v1::o1_freeMultKeys() { - load16(); + _vm->_game->_script->readInt16(); _vm->_mult->freeMultKeys(); } @@ -785,20 +305,20 @@ void Inter_v1::o1_initCursor() { int16 height; int16 count; - _vm->_draw->_cursorHotspotXVar = _vm->_parse->parseVarIndex() / 4; - _vm->_draw->_cursorHotspotYVar = _vm->_parse->parseVarIndex() / 4; + _vm->_draw->_cursorHotspotXVar = _vm->_game->_script->readVarIndex() / 4; + _vm->_draw->_cursorHotspotYVar = _vm->_game->_script->readVarIndex() / 4; - width = load16(); + width = _vm->_game->_script->readInt16(); if (width < 16) width = 16; - height = load16(); + height = _vm->_game->_script->readInt16(); if (height < 16) height = 16; _vm->_draw->adjustCoords(0, &width, &height); - count = load16(); + count = _vm->_game->_script->readInt16(); if (count < 2) count = 2; @@ -846,24 +366,24 @@ void Inter_v1::o1_initCursorAnim() { int16 ind; _vm->_draw->_showCursor = 3; - ind = _vm->_parse->parseValExpr(); - _vm->_draw->_cursorAnimLow[ind] = load16(); - _vm->_draw->_cursorAnimHigh[ind] = load16(); - _vm->_draw->_cursorAnimDelays[ind] = load16(); + ind = _vm->_game->_script->readValExpr(); + _vm->_draw->_cursorAnimLow[ind] = _vm->_game->_script->readInt16(); + _vm->_draw->_cursorAnimHigh[ind] = _vm->_game->_script->readInt16(); + _vm->_draw->_cursorAnimDelays[ind] = _vm->_game->_script->readInt16(); } void Inter_v1::o1_clearCursorAnim() { int16 ind; _vm->_draw->_showCursor = 0; - ind = _vm->_parse->parseValExpr(); + ind = _vm->_game->_script->readValExpr(); _vm->_draw->_cursorAnimLow[ind] = -1; _vm->_draw->_cursorAnimHigh[ind] = 0; _vm->_draw->_cursorAnimDelays[ind] = 0; } void Inter_v1::o1_setRenderFlags() { - _vm->_draw->_renderFlags = _vm->_parse->parseValExpr(); + _vm->_draw->_renderFlags = _vm->_game->_script->readValExpr(); } void Inter_v1::o1_loadAnim() { @@ -882,12 +402,12 @@ void Inter_v1::o1_updateAnim() { int16 layer; int16 animation; - evalExpr(&deltaX); - evalExpr(&deltaY); - evalExpr(&animation); - evalExpr(&layer); - evalExpr(&frame); - flags = load16(); + _vm->_game->_script->evalExpr(&deltaX); + _vm->_game->_script->evalExpr(&deltaY); + _vm->_game->_script->evalExpr(&animation); + _vm->_game->_script->evalExpr(&layer); + _vm->_game->_script->evalExpr(&frame); + flags = _vm->_game->_script->readInt16(); _vm->_scenery->updateAnim(layer, frame, animation, flags, deltaX, deltaY, 1); } @@ -904,14 +424,14 @@ void Inter_v1::o1_initMult() { oldAnimHeight = _vm->_mult->_animHeight; oldObjCount = _vm->_mult->_objCount; - _vm->_mult->_animLeft = load16(); - _vm->_mult->_animTop = load16(); - _vm->_mult->_animWidth = load16(); - _vm->_mult->_animHeight = load16(); - _vm->_mult->_objCount = load16(); - posXVar = _vm->_parse->parseVarIndex(); - posYVar = _vm->_parse->parseVarIndex(); - animDataVar = _vm->_parse->parseVarIndex(); + _vm->_mult->_animLeft = _vm->_game->_script->readInt16(); + _vm->_mult->_animTop = _vm->_game->_script->readInt16(); + _vm->_mult->_animWidth = _vm->_game->_script->readInt16(); + _vm->_mult->_animHeight = _vm->_game->_script->readInt16(); + _vm->_mult->_objCount = _vm->_game->_script->readInt16(); + posXVar = _vm->_game->_script->readVarIndex(); + posYVar = _vm->_game->_script->readVarIndex(); + animDataVar = _vm->_game->_script->readVarIndex(); if (_vm->_mult->_objects && (oldObjCount != _vm->_mult->_objCount)) { @@ -944,8 +464,8 @@ void Inter_v1::o1_initMult() { uint32 offPosY = i * 4 + (posYVar / 4) * 4; uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize; - _vm->_mult->_objects[i].pPosX = new VariableReference(*_vm->_inter->_variables, offPosX); - _vm->_mult->_objects[i].pPosY = new VariableReference(*_vm->_inter->_variables, offPosY); + _vm->_mult->_objects[i].pPosX = new VariableReference(*_variables, offPosX); + _vm->_mult->_objects[i].pPosY = new VariableReference(*_variables, offPosY); _vm->_mult->_objects[i].pAnimData = (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim); @@ -998,21 +518,21 @@ void Inter_v1::o1_loadMultObject() { int16 objIndex; byte *multData; - evalExpr(&objIndex); - evalExpr(&val); + _vm->_game->_script->evalExpr(&objIndex); + _vm->_game->_script->evalExpr(&val); *_vm->_mult->_objects[objIndex].pPosX = val; - evalExpr(&val); + _vm->_game->_script->evalExpr(&val); *_vm->_mult->_objects[objIndex].pPosY = val; debugC(4, kDebugGameFlow, "Loading mult object %d", objIndex); multData = (byte *) _vm->_mult->_objects[objIndex].pAnimData; for (int i = 0; i < 11; i++) { - if (READ_LE_UINT16(_vm->_global->_inter_execPtr) != 99) { - evalExpr(&val); + if (_vm->_game->_script->peekUint16() != 99) { + _vm->_game->_script->evalExpr(&val); multData[i] = val; } else - _vm->_global->_inter_execPtr++; + _vm->_game->_script->skip(1); } } @@ -1023,13 +543,13 @@ void Inter_v1::o1_getAnimLayerInfo() { int16 varUnk0; int16 varFrames; - evalExpr(&anim); - evalExpr(&layer); + _vm->_game->_script->evalExpr(&anim); + _vm->_game->_script->evalExpr(&layer); - varDX = _vm->_parse->parseVarIndex(); - varDY = _vm->_parse->parseVarIndex(); - varUnk0 = _vm->_parse->parseVarIndex(); - varFrames = _vm->_parse->parseVarIndex(); + varDX = _vm->_game->_script->readVarIndex(); + varDY = _vm->_game->_script->readVarIndex(); + varUnk0 = _vm->_game->_script->readVarIndex(); + varFrames = _vm->_game->_script->readVarIndex(); _vm->_scenery->writeAnimLayerInfo(anim, layer, varDX, varDY, varUnk0, varFrames); @@ -1038,7 +558,7 @@ void Inter_v1::o1_getAnimLayerInfo() { void Inter_v1::o1_getObjAnimSize() { int16 objIndex; - evalExpr(&objIndex); + _vm->_game->_script->evalExpr(&objIndex); Mult::Mult_AnimData &animData = *(_vm->_mult->_objects[objIndex].pAnimData); if (animData.isStatic == 0) @@ -1048,10 +568,10 @@ void Inter_v1::o1_getObjAnimSize() { _vm->_scenery->_toRedrawLeft = MAX(_vm->_scenery->_toRedrawLeft, (int16) 0); _vm->_scenery->_toRedrawTop = MAX(_vm->_scenery->_toRedrawTop, (int16) 0); - WRITE_VAR_OFFSET(_vm->_parse->parseVarIndex(), _vm->_scenery->_toRedrawLeft); - WRITE_VAR_OFFSET(_vm->_parse->parseVarIndex(), _vm->_scenery->_toRedrawTop); - WRITE_VAR_OFFSET(_vm->_parse->parseVarIndex(), _vm->_scenery->_toRedrawRight); - WRITE_VAR_OFFSET(_vm->_parse->parseVarIndex(), _vm->_scenery->_toRedrawBottom); + WRITE_VAR_OFFSET(_vm->_game->_script->readVarIndex(), _vm->_scenery->_toRedrawLeft); + WRITE_VAR_OFFSET(_vm->_game->_script->readVarIndex(), _vm->_scenery->_toRedrawTop); + WRITE_VAR_OFFSET(_vm->_game->_script->readVarIndex(), _vm->_scenery->_toRedrawRight); + WRITE_VAR_OFFSET(_vm->_game->_script->readVarIndex(), _vm->_scenery->_toRedrawBottom); } void Inter_v1::o1_loadStatic() { @@ -1066,20 +586,20 @@ void Inter_v1::o1_renderStatic() { int16 layer; int16 index; - _vm->_inter->evalExpr(&index); - _vm->_inter->evalExpr(&layer); + _vm->_game->_script->evalExpr(&index); + _vm->_game->_script->evalExpr(&layer); _vm->_scenery->renderStatic(index, layer); } void Inter_v1::o1_loadCurLayer() { - evalExpr(&_vm->_scenery->_curStatic); - evalExpr(&_vm->_scenery->_curStaticLayer); + _vm->_game->_script->evalExpr(&_vm->_scenery->_curStatic); + _vm->_game->_script->evalExpr(&_vm->_scenery->_curStaticLayer); } void Inter_v1::o1_playCDTrack() { - evalExpr(0); + _vm->_game->_script->evalExpr(0); _vm->_sound->adlibPlayBgMusic(); // Mac version - _vm->_sound->cdPlay(_vm->_global->_inter_resStr); // PC CD version + _vm->_sound->cdPlay(_vm->_game->_script->getResultStr()); // PC CD version } void Inter_v1::o1_getCDTrackPos() { @@ -1103,15 +623,15 @@ void Inter_v1::o1_stopCD() { } void Inter_v1::o1_loadFontToSprite() { - int16 i = load16(); - _vm->_draw->_fontToSprite[i].sprite = load16(); - _vm->_draw->_fontToSprite[i].base = load16(); - _vm->_draw->_fontToSprite[i].width = load16(); - _vm->_draw->_fontToSprite[i].height = load16(); + int16 i = _vm->_game->_script->readInt16(); + _vm->_draw->_fontToSprite[i].sprite = _vm->_game->_script->readInt16(); + _vm->_draw->_fontToSprite[i].base = _vm->_game->_script->readInt16(); + _vm->_draw->_fontToSprite[i].width = _vm->_game->_script->readInt16(); + _vm->_draw->_fontToSprite[i].height = _vm->_game->_script->readInt16(); } void Inter_v1::o1_freeFontToSprite() { - int16 i = load16(); + int16 i = _vm->_game->_script->readInt16(); _vm->_draw->_fontToSprite[i].sprite = -1; _vm->_draw->_fontToSprite[i].base = -1; _vm->_draw->_fontToSprite[i].width = -1; @@ -1119,11 +639,7 @@ void Inter_v1::o1_freeFontToSprite() { } bool Inter_v1::o1_callSub(OpFuncParams ¶ms) { - byte *storedIP; - uint16 offset; - - offset = load16(); - storedIP = _vm->_global->_inter_execPtr; + uint16 offset = _vm->_game->_script->readUint16(); debugC(5, kDebugGameFlow, "tot = \"%s\", offset = %d", _vm->_game->_curTotFile, offset); @@ -1147,79 +663,89 @@ bool Inter_v1::o1_callSub(OpFuncParams ¶ms) { return false; } - _vm->_global->_inter_execPtr = _vm->_game->_totFileData + offset; + _vm->_game->_script->call(offset); - if ((params.counter == params.cmdCount) && (params.retFlag == 2)) + if ((params.counter == params.cmdCount) && (params.retFlag == 2)) { + _vm->_game->_script->pop(false); return true; + } callSub(2); - _vm->_global->_inter_execPtr = storedIP; + + _vm->_game->_script->pop(); return false; } bool Inter_v1::o1_printTotText(OpFuncParams ¶ms) { - _vm->_draw->printTotText(load16()); + _vm->_draw->printTotText(_vm->_game->_script->readInt16()); return false; } bool Inter_v1::o1_loadCursor(OpFuncParams ¶ms) { - int16 width, height; - byte *dataBuf; - int16 id; - int8 index; - - id = load16(); - index = (int8) *_vm->_global->_inter_execPtr++; + int16 id = _vm->_game->_script->readInt16(); + int8 index = _vm->_game->_script->readInt8(); if ((index * _vm->_draw->_cursorWidth) >= _vm->_draw->_cursorSprites->getWidth()) return false; - dataBuf = _vm->_game->loadTotResource(id, 0, &width, &height); + Resource *resource = _vm->_game->_resources->getResource(id); + if (!resource) + return false; _vm->_video->fillRect(*_vm->_draw->_cursorSprites, index * _vm->_draw->_cursorWidth, 0, index * _vm->_draw->_cursorWidth + _vm->_draw->_cursorWidth - 1, _vm->_draw->_cursorHeight - 1, 0); - _vm->_video->drawPackedSprite(dataBuf, width, height, + _vm->_video->drawPackedSprite(resource->getData(), + resource->getWidth(), resource->getHeight(), index * _vm->_draw->_cursorWidth, 0, 0, *_vm->_draw->_cursorSprites); _vm->_draw->_cursorAnimLow[index] = 0; + delete resource; return false; } bool Inter_v1::o1_switch(OpFuncParams ¶ms) { - byte *callAddr; + uint32 offset; + + checkSwitchTable(offset); - checkSwitchTable(&callAddr); - byte *storedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = callAddr; + _vm->_game->_script->call(offset); - if ((params.counter == params.cmdCount) && (params.retFlag == 2)) + if (offset == 0) + _vm->_game->_script->setFinished(true); + + if ((params.counter == params.cmdCount) && (params.retFlag == 2)) { + _vm->_game->_script->pop(false); return true; + } funcBlock(0); - _vm->_global->_inter_execPtr = storedIP; + + _vm->_game->_script->pop(); return false; } bool Inter_v1::o1_repeatUntil(OpFuncParams ¶ms) { - byte *blockPtr; int16 size; bool flag; _nestLevel[0]++; - blockPtr = _vm->_global->_inter_execPtr; + + uint32 blockPos = _vm->_game->_script->pos(); do { - _vm->_global->_inter_execPtr = blockPtr; - size = READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + _vm->_game->_script->seek(blockPos); + size = _vm->_game->_script->peekUint16(2) + 2; funcBlock(1); - _vm->_global->_inter_execPtr = blockPtr + size + 1; - flag = evalBoolResult(); + + _vm->_game->_script->seek(blockPos + size + 1); + + flag = _vm->_game->_script->evalBoolResult(); } while (!flag && !_break && !_terminate && !_vm->shouldQuit()); _nestLevel[0]--; @@ -1232,32 +758,31 @@ bool Inter_v1::o1_repeatUntil(OpFuncParams ¶ms) { } bool Inter_v1::o1_whileDo(OpFuncParams ¶ms) { - byte *blockPtr; - byte *savedIP; bool flag; int16 size; _nestLevel[0]++; do { - savedIP = _vm->_global->_inter_execPtr; - flag = evalBoolResult(); + uint32 startPos = _vm->_game->_script->pos(); + + flag = _vm->_game->_script->evalBoolResult(); if (_terminate) return false; - blockPtr = _vm->_global->_inter_execPtr; + uint32 blockPos = _vm->_game->_script->pos(); - size = READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + size = _vm->_game->_script->peekUint16(2) + 2; if (flag) { funcBlock(1); - _vm->_global->_inter_execPtr = savedIP; + _vm->_game->_script->seek(startPos); } else - _vm->_global->_inter_execPtr += size; + _vm->_game->_script->skip(size); if (_break || _terminate || _vm->shouldQuit()) { - _vm->_global->_inter_execPtr = blockPtr; - _vm->_global->_inter_execPtr += size; + _vm->_game->_script->seek(blockPos); + _vm->_game->_script->skip(size); break; } } while (flag); @@ -1273,76 +798,65 @@ bool Inter_v1::o1_whileDo(OpFuncParams ¶ms) { bool Inter_v1::o1_if(OpFuncParams ¶ms) { byte cmd; bool boolRes; - byte *storedIP; - boolRes = evalBoolResult(); + boolRes = _vm->_game->_script->evalBoolResult(); if (boolRes) { if ((params.counter == params.cmdCount) && (params.retFlag == 2)) return true; - storedIP = _vm->_global->_inter_execPtr; + _vm->_game->_script->push(); funcBlock(0); - _vm->_global->_inter_execPtr = storedIP; + _vm->_game->_script->pop(); - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + _vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2); - debugC(5, kDebugGameFlow, "cmd = %d", - (int16) *_vm->_global->_inter_execPtr); + debugC(5, kDebugGameFlow, "cmd = %d", (int16) _vm->_game->_script->peekByte()); - cmd = *_vm->_global->_inter_execPtr >> 4; - _vm->_global->_inter_execPtr++; + cmd = _vm->_game->_script->readByte() >> 4; if (cmd != 12) return false; - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + _vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2); } else { - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + _vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2); - debugC(5, kDebugGameFlow, "cmd = %d", - (int16) *_vm->_global->_inter_execPtr); + debugC(5, kDebugGameFlow, "cmd = %d", (int16) _vm->_game->_script->peekByte()); - cmd = *_vm->_global->_inter_execPtr >> 4; - _vm->_global->_inter_execPtr++; + cmd = _vm->_game->_script->readByte() >> 4; if (cmd != 12) return false; if ((params.counter == params.cmdCount) && (params.retFlag == 2)) return true; - storedIP = _vm->_global->_inter_execPtr; + _vm->_game->_script->push(); funcBlock(0); - _vm->_global->_inter_execPtr = storedIP; + _vm->_game->_script->pop(); - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + _vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2); } return false; } bool Inter_v1::o1_assign(OpFuncParams ¶ms) { - byte *savedPos; - int16 token; + byte destType = _vm->_game->_script->peekByte(); + int16 dest = _vm->_game->_script->readVarIndex(); + int16 result; - int16 varOff; + int16 srcType = _vm->_game->_script->evalExpr(&result); - savedPos = _vm->_global->_inter_execPtr; - varOff = _vm->_parse->parseVarIndex(); - token = evalExpr(&result); - switch (savedPos[0]) { - case 23: - case 26: - WRITE_VAR_OFFSET(varOff, _vm->_global->_inter_resVal); + switch (destType) { + case TYPE_VAR_INT32: + case TYPE_ARRAY_INT32: + WRITE_VAR_OFFSET(dest, _vm->_game->_script->getResultInt()); break; - case 25: - case 28: - if (token == 20) - WRITE_VARO_UINT8(varOff, result); + case TYPE_VAR_STR: + case TYPE_ARRAY_STR: + if (srcType == TYPE_IMM_INT16) + WRITE_VARO_UINT8(dest, result); else - WRITE_VARO_STR(varOff, _vm->_global->_inter_resStr); + WRITE_VARO_STR(dest, _vm->_game->_script->getResultStr()); break; } @@ -1350,17 +864,17 @@ bool Inter_v1::o1_assign(OpFuncParams ¶ms) { } bool Inter_v1::o1_loadSpriteToPos(OpFuncParams ¶ms) { - _vm->_draw->_spriteLeft = load16(); + _vm->_draw->_spriteLeft = _vm->_game->_script->readInt16(); - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); - _vm->_draw->_transparency = *_vm->_global->_inter_execPtr & 1; - _vm->_draw->_destSurface = ((int16) (*_vm->_global->_inter_execPtr >> 1)) - 1; + _vm->_draw->_transparency = _vm->_game->_script->peekByte() & 1; + _vm->_draw->_destSurface = ((int16) (_vm->_game->_script->peekByte() >> 1)) - 1; if (_vm->_draw->_destSurface < 0) _vm->_draw->_destSurface = 101; - _vm->_global->_inter_execPtr += 2; + _vm->_game->_script->skip(2); _vm->_draw->spriteOperation(DRAW_LOADSPRITE); @@ -1371,12 +885,12 @@ bool Inter_v1::o1_printText(OpFuncParams ¶ms) { char buf[60]; int i; - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); - _vm->_draw->_backColor = _vm->_parse->parseValExpr(); - _vm->_draw->_frontColor = _vm->_parse->parseValExpr(); - _vm->_draw->_fontIndex = _vm->_parse->parseValExpr(); + _vm->_draw->_backColor = _vm->_game->_script->readValExpr(); + _vm->_draw->_frontColor = _vm->_game->_script->readValExpr(); + _vm->_draw->_fontIndex = _vm->_game->_script->readValExpr(); _vm->_draw->_destSurface = 21; _vm->_draw->_textToPrint = buf; _vm->_draw->_transparency = 0; @@ -1387,35 +901,35 @@ bool Inter_v1::o1_printText(OpFuncParams ¶ms) { } do { - for (i = 0; (((char) *_vm->_global->_inter_execPtr) != '.') && - (*_vm->_global->_inter_execPtr != 200); - i++, _vm->_global->_inter_execPtr++) { - buf[i] = (char) *_vm->_global->_inter_execPtr; + for (i = 0; ((_vm->_game->_script->peekChar()) != '.') && + (_vm->_game->_script->peekByte() != 200); + i++, _vm->_game->_script->skip(1)) { + buf[i] = _vm->_game->_script->peekChar(); } - if (*_vm->_global->_inter_execPtr != 200) { - _vm->_global->_inter_execPtr++; - switch (*_vm->_global->_inter_execPtr) { - case 23: - case 26: + if (_vm->_game->_script->peekByte() != 200) { + _vm->_game->_script->skip(1); + switch (_vm->_game->_script->peekByte()) { + case TYPE_VAR_INT32: + case TYPE_ARRAY_INT32: sprintf(buf + i, "%d", - VAR_OFFSET(_vm->_parse->parseVarIndex())); + VAR_OFFSET(_vm->_game->_script->readVarIndex())); break; - case 25: - case 28: + case TYPE_VAR_STR: + case TYPE_ARRAY_STR: sprintf(buf + i, "%s", - GET_VARO_STR(_vm->_parse->parseVarIndex())); + GET_VARO_STR(_vm->_game->_script->readVarIndex())); break; } - _vm->_global->_inter_execPtr++; + _vm->_game->_script->skip(1); } else buf[i] = 0; _vm->_draw->spriteOperation(DRAW_PRINTTEXT); - } while (*_vm->_global->_inter_execPtr != 200); + } while (_vm->_game->_script->peekByte() != 200); - _vm->_global->_inter_execPtr++; + _vm->_game->_script->skip(1); return false; } @@ -1424,16 +938,14 @@ bool Inter_v1::o1_loadTot(OpFuncParams ¶ms) { char buf[20]; int8 size; - if ((*_vm->_global->_inter_execPtr & 0x80) != 0) { - _vm->_global->_inter_execPtr++; - evalExpr(0); - strncpy0(buf, _vm->_global->_inter_resStr, 15); + if ((_vm->_game->_script->peekByte() & 0x80) != 0) { + _vm->_game->_script->skip(1); + _vm->_game->_script->evalExpr(0); + strncpy0(buf, _vm->_game->_script->getResultStr(), 15); } else { - size = (int8) *_vm->_global->_inter_execPtr++; - for (int i = 0; i < size; i++) - buf[i] = *_vm->_global->_inter_execPtr++; - - buf[size] = 0; + size = _vm->_game->_script->readInt8(); + memcpy(buf, _vm->_game->_script->readString(size), size); + buf[size] = '\0'; } // if (_vm->getGameType() == kGameTypeGeisha) @@ -1450,15 +962,15 @@ bool Inter_v1::o1_loadTot(OpFuncParams ¶ms) { bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { int index1, index2; - byte *palPtr; byte cmd; + Resource *resource; - cmd = *_vm->_global->_inter_execPtr++; + cmd = _vm->_game->_script->readByte(); switch (cmd & 0x7F) { case 48: if ((_vm->_global->_fakeVideoMode < 0x32) || (_vm->_global->_fakeVideoMode > 0x63)) { - _vm->_global->_inter_execPtr += 48; + _vm->_game->_script->skip(48); return false; } break; @@ -1466,35 +978,35 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { case 49: if ((_vm->_global->_fakeVideoMode != 5) && (_vm->_global->_fakeVideoMode != 7)) { - _vm->_global->_inter_execPtr += 18; + _vm->_game->_script->skip(18); return false; } break; case 50: if (_vm->_global->_colorCount == 256) { - _vm->_global->_inter_execPtr += 16; + _vm->_game->_script->skip(16); return false; } break; case 51: if (_vm->_global->_fakeVideoMode < 0x64) { - _vm->_global->_inter_execPtr += 2; + _vm->_game->_script->skip(2); return false; } break; case 52: if (_vm->_global->_colorCount == 256) { - _vm->_global->_inter_execPtr += 48; + _vm->_game->_script->skip(48); return false; } break; case 53: if (_vm->_global->_colorCount != 256) { - _vm->_global->_inter_execPtr += 2; + _vm->_game->_script->skip(2); return false; } break; @@ -1507,14 +1019,14 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { case 61: if (_vm->_global->_fakeVideoMode < 0x13) { - _vm->_global->_inter_execPtr += 4; + _vm->_game->_script->skip(4); return false; } break; } if ((cmd & 0x7F) == 0x30) { - _vm->_global->_inter_execPtr += 48; + _vm->_game->_script->skip(48); return false; } @@ -1525,7 +1037,7 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { bool allZero = true; for (int i = 2; i < 18; i++) { - if (_vm->_global->_inter_execPtr[i] != 0) { + if (_vm->_game->_script->peekByte(i) != 0) { allZero = false; break; } @@ -1533,28 +1045,30 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { if (!allZero) { _vm->_video->clearSurf(*_vm->_draw->_frontSurface); _vm->_draw->_noInvalidated57 = true; - _vm->_global->_inter_execPtr += 18; + _vm->_game->_script->skip(48); return false; } _vm->_draw->_noInvalidated57 = false; - for (int i = 0; i < 18; i++, _vm->_global->_inter_execPtr++) { + for (int i = 0; i < 18; i++) { if (i < 2) { if (!_vm->_draw->_applyPal) continue; - _vm->_draw->_unusedPalette1[i] = *_vm->_global->_inter_execPtr; + _vm->_draw->_unusedPalette1[i] = _vm->_game->_script->peekByte(); continue; } - index1 = *_vm->_global->_inter_execPtr >> 4; - index2 = (*_vm->_global->_inter_execPtr & 0xF); + index1 = _vm->_game->_script->peekByte() >> 4; + index2 = _vm->_game->_script->peekByte() & 0xF; _vm->_draw->_unusedPalette1[i] = ((_vm->_draw->_palLoadData1[index1] + _vm->_draw->_palLoadData2[index2]) << 8) + (_vm->_draw->_palLoadData2[index1] + _vm->_draw->_palLoadData1[index2]); + + _vm->_game->_script->skip(1); } _vm->_global->_pPaletteDesc->unused1 = _vm->_draw->_unusedPalette1; @@ -1564,21 +1078,25 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { switch (cmd) { case 50: - for (int i = 0; i < 16; i++, _vm->_global->_inter_execPtr++) - _vm->_draw->_unusedPalette2[i] = *_vm->_global->_inter_execPtr; + for (int i = 0; i < 16; i++) + _vm->_draw->_unusedPalette2[i] = _vm->_game->_script->readByte(); break; case 52: - for (int i = 0; i < 16; i++, _vm->_global->_inter_execPtr += 3) { - _vm->_draw->_vgaPalette[i].red = _vm->_global->_inter_execPtr[0]; - _vm->_draw->_vgaPalette[i].green = _vm->_global->_inter_execPtr[1]; - _vm->_draw->_vgaPalette[i].blue = _vm->_global->_inter_execPtr[2]; + for (int i = 0; i < 16; i++) { + _vm->_draw->_vgaPalette[i].red = _vm->_game->_script->readByte(); + _vm->_draw->_vgaPalette[i].green = _vm->_game->_script->readByte(); + _vm->_draw->_vgaPalette[i].blue = _vm->_game->_script->readByte(); } break; case 53: - palPtr = _vm->_game->loadTotResource(_vm->_inter->load16()); - memcpy((char *) _vm->_draw->_vgaPalette, palPtr, 768); + resource = _vm->_game->_resources->getResource(_vm->_game->_script->readInt16()); + if (!resource) + break; + + memcpy((char *) _vm->_draw->_vgaPalette, resource->getData(), MIN(768, resource->getSize())); + delete resource; break; case 54: @@ -1586,11 +1104,15 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { break; case 61: - index1 = *_vm->_global->_inter_execPtr++; - index2 = (*_vm->_global->_inter_execPtr++ - index1 + 1) * 3; - palPtr = _vm->_game->loadTotResource(_vm->_inter->load16()); + index1 = _vm->_game->_script->readByte(); + index2 = (_vm->_game->_script->readByte() - index1 + 1) * 3; + resource = _vm->_game->_resources->getResource(_vm->_game->_script->readInt16()); + if (!resource) + break; + memcpy((char *) _vm->_draw->_vgaPalette + index1 * 3, - palPtr + index1 * 3, index2); + resource->getData() + index1 * 3, index2); + delete resource; if (_vm->_draw->_applyPal) { _vm->_draw->_applyPal = false; @@ -1628,7 +1150,7 @@ bool Inter_v1::o1_keyFunc(OpFuncParams ¶ms) { int16 key; uint32 now; - cmd = load16(); + cmd = _vm->_game->_script->readInt16(); animPalette(); _vm->_draw->blitInvalidated(); @@ -1643,7 +1165,7 @@ bool Inter_v1::o1_keyFunc(OpFuncParams ¶ms) { // to become 5000. We deliberately slow down busy-waiting, so we shorten // the counting, too. if ((_vm->getGameType() == kGameTypeWeen) && (VAR(59) < 4000) && - ((_vm->_global->_inter_execPtr - _vm->_game->_totFileData) == 729) && + (_vm->_game->_script->pos() == 729) && !scumm_stricmp(_vm->_game->_curTotFile, "intro5.tot")) WRITE_VAR(59, 4000); @@ -1689,10 +1211,10 @@ bool Inter_v1::o1_capturePush(OpFuncParams ¶ms) { int16 left, top; int16 width, height; - left = _vm->_parse->parseValExpr(); - top = _vm->_parse->parseValExpr(); - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + left = _vm->_game->_script->readValExpr(); + top = _vm->_game->_script->readValExpr(); + width = _vm->_game->_script->readValExpr(); + height = _vm->_game->_script->readValExpr(); if ((width < 0) || (height < 0)) return false; @@ -1711,24 +1233,24 @@ bool Inter_v1::o1_capturePop(OpFuncParams ¶ms) { } bool Inter_v1::o1_animPalInit(OpFuncParams ¶ms) { - _animPalDir[0] = load16(); - _animPalLowIndex[0] = _vm->_parse->parseValExpr(); - _animPalHighIndex[0] = _vm->_parse->parseValExpr(); + _animPalDir[0] = _vm->_game->_script->readInt16(); + _animPalLowIndex[0] = _vm->_game->_script->readValExpr(); + _animPalHighIndex[0] = _vm->_game->_script->readValExpr(); return false; } bool Inter_v1::o1_drawOperations(OpFuncParams ¶ms) { byte cmd; - cmd = *_vm->_global->_inter_execPtr++; + cmd = _vm->_game->_script->readByte(); - executeDrawOpcode(cmd); + executeOpcodeDraw(cmd); return false; } bool Inter_v1::o1_setcmdCount(OpFuncParams ¶ms) { - params.cmdCount = *_vm->_global->_inter_execPtr++; + params.cmdCount = _vm->_game->_script->readByte(); params.counter = 0; return false; } @@ -1737,7 +1259,7 @@ bool Inter_v1::o1_return(OpFuncParams ¶ms) { if (params.retFlag != 2) _break = true; - _vm->_global->_inter_execPtr = 0; + _vm->_game->_script->setFinished(true); return true; } @@ -1747,7 +1269,7 @@ bool Inter_v1::o1_renewTimeInVars(OpFuncParams ¶ms) { } bool Inter_v1::o1_speakerOn(OpFuncParams ¶ms) { - _vm->_sound->speakerOn(_vm->_parse->parseValExpr(), -1); + _vm->_sound->speakerOn(_vm->_game->_script->readValExpr(), -1); return false; } @@ -1757,11 +1279,11 @@ bool Inter_v1::o1_speakerOff(OpFuncParams ¶ms) { } bool Inter_v1::o1_putPixel(OpFuncParams ¶ms) { - _vm->_draw->_destSurface = load16(); + _vm->_draw->_destSurface = _vm->_game->_script->readInt16(); - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); - _vm->_draw->_frontColor = _vm->_parse->parseValExpr(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); + _vm->_draw->_frontColor = _vm->_game->_script->readValExpr(); _vm->_draw->spriteOperation(DRAW_PUTPIXEL); return false; } @@ -1773,33 +1295,33 @@ bool Inter_v1::o1_goblinFunc(OpFuncParams ¶ms) { gobParams.extraData = 0; gobParams.objDesc = 0; - gobParams.retVarPtr.set(*_vm->_inter->_variables, 236); + gobParams.retVarPtr.set(*_variables, 236); - cmd = load16(); - _vm->_global->_inter_execPtr += 2; + cmd = _vm->_game->_script->readInt16(); + _vm->_game->_script->skip(2); if ((cmd > 0) && (cmd < 17)) { objDescSet = true; - gobParams.extraData = load16(); + gobParams.extraData = _vm->_game->_script->readInt16(); gobParams.objDesc = _vm->_goblin->_objects[gobParams.extraData]; - gobParams.extraData = load16(); + gobParams.extraData = _vm->_game->_script->readInt16(); } if ((cmd > 90) && (cmd < 107)) { objDescSet = true; - gobParams.extraData = load16(); + gobParams.extraData = _vm->_game->_script->readInt16(); gobParams.objDesc = _vm->_goblin->_goblins[gobParams.extraData]; - gobParams.extraData = load16(); + gobParams.extraData = _vm->_game->_script->readInt16(); cmd -= 90; } if ((cmd > 110) && (cmd < 128)) { objDescSet = true; - gobParams.extraData = load16(); + gobParams.extraData = _vm->_game->_script->readInt16(); gobParams.objDesc = _vm->_goblin->_goblins[gobParams.extraData]; cmd -= 90; } else if ((cmd > 20) && (cmd < 38)) { objDescSet = true; - gobParams.extraData = load16(); + gobParams.extraData = _vm->_game->_script->readInt16(); gobParams.objDesc = _vm->_goblin->_objects[gobParams.extraData]; } @@ -1815,7 +1337,7 @@ bool Inter_v1::o1_goblinFunc(OpFuncParams ¶ms) { if ((cmd < 40) && objDescSet && !gobParams.objDesc) return false; - executeGoblinOpcode(cmd, gobParams); + executeOpcodeGob(cmd, gobParams); return false; } @@ -1825,31 +1347,31 @@ bool Inter_v1::o1_createSprite(OpFuncParams ¶ms) { int16 width, height; int16 flag; - if (_vm->_global->_inter_execPtr[1] == 0) { - index = load16(); - width = load16(); - height = load16(); + if (_vm->_game->_script->peekByte(1) == 0) { + index = _vm->_game->_script->readInt16(); + width = _vm->_game->_script->readInt16(); + height = _vm->_game->_script->readInt16(); } else { - index = _vm->_parse->parseValExpr(); - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + index = _vm->_game->_script->readValExpr(); + width = _vm->_game->_script->readValExpr(); + height = _vm->_game->_script->readValExpr(); } - flag = load16(); + flag = _vm->_game->_script->readInt16(); _vm->_draw->initSpriteSurf(index, width, height, flag ? 2 : 0); return false; } bool Inter_v1::o1_freeSprite(OpFuncParams ¶ms) { - _vm->_draw->freeSprite(load16()); + _vm->_draw->freeSprite(_vm->_game->_script->readInt16()); return false; } bool Inter_v1::o1_returnTo(OpFuncParams ¶ms) { if (params.retFlag == 1) { _break = true; - _vm->_global->_inter_execPtr = 0; + _vm->_game->_script->setFinished(true); return true; } @@ -1858,14 +1380,14 @@ bool Inter_v1::o1_returnTo(OpFuncParams ¶ms) { *_breakFromLevel = *_nestLevel; _break = true; - _vm->_global->_inter_execPtr = 0; + _vm->_game->_script->setFinished(true); return true; } bool Inter_v1::o1_loadSpriteContent(OpFuncParams ¶ms) { - _vm->_draw->_spriteLeft = load16(); - _vm->_draw->_destSurface = load16(); - _vm->_draw->_transparency = load16(); + _vm->_draw->_spriteLeft = _vm->_game->_script->readInt16(); + _vm->_draw->_destSurface = _vm->_game->_script->readInt16(); + _vm->_draw->_transparency = _vm->_game->_script->readInt16(); _vm->_draw->_destSpriteX = 0; _vm->_draw->_destSpriteY = 0; @@ -1874,25 +1396,25 @@ bool Inter_v1::o1_loadSpriteContent(OpFuncParams ¶ms) { } bool Inter_v1::o1_copySprite(OpFuncParams ¶ms) { - if (_vm->_global->_inter_execPtr[1] == 0) - _vm->_draw->_sourceSurface = load16(); + if (_vm->_game->_script->peekByte(1) == 0) + _vm->_draw->_sourceSurface = _vm->_game->_script->readInt16(); else - _vm->_draw->_sourceSurface = _vm->_parse->parseValExpr(); + _vm->_draw->_sourceSurface = _vm->_game->_script->readValExpr(); - if (_vm->_global->_inter_execPtr[1] == 0) - _vm->_draw->_destSurface = load16(); + if (_vm->_game->_script->peekByte(1) == 0) + _vm->_draw->_destSurface = _vm->_game->_script->readInt16(); else - _vm->_draw->_destSurface = _vm->_parse->parseValExpr(); + _vm->_draw->_destSurface = _vm->_game->_script->readValExpr(); - _vm->_draw->_spriteLeft = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteTop = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteRight = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteBottom = _vm->_parse->parseValExpr(); + _vm->_draw->_spriteLeft = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteTop = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteRight = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteBottom = _vm->_game->_script->readValExpr(); - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); - _vm->_draw->_transparency = load16(); + _vm->_draw->_transparency = _vm->_game->_script->readInt16(); _vm->_draw->spriteOperation(DRAW_BLITSURF); return false; @@ -1901,14 +1423,14 @@ bool Inter_v1::o1_copySprite(OpFuncParams ¶ms) { bool Inter_v1::o1_fillRect(OpFuncParams ¶ms) { int16 destSurf; - _vm->_draw->_destSurface = destSurf = load16(); + _vm->_draw->_destSurface = destSurf = _vm->_game->_script->readInt16(); - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteRight = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteBottom = _vm->_parse->parseValExpr(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteRight = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteBottom = _vm->_game->_script->readValExpr(); - _vm->_draw->_backColor = _vm->_parse->parseValExpr(); + _vm->_draw->_backColor = _vm->_game->_script->readValExpr(); if (!_vm->_draw->_spritesArray[(destSurf >= 100) ? (destSurf - 80) : destSurf]) return false; @@ -1927,14 +1449,14 @@ bool Inter_v1::o1_fillRect(OpFuncParams ¶ms) { } bool Inter_v1::o1_drawLine(OpFuncParams ¶ms) { - _vm->_draw->_destSurface = load16(); + _vm->_draw->_destSurface = _vm->_game->_script->readInt16(); - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteRight = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteBottom = _vm->_parse->parseValExpr(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteRight = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteBottom = _vm->_game->_script->readValExpr(); - _vm->_draw->_frontColor = _vm->_parse->parseValExpr(); + _vm->_draw->_frontColor = _vm->_game->_script->readValExpr(); _vm->_draw->spriteOperation(DRAW_DRAWLINE); return false; } @@ -1945,28 +1467,28 @@ bool Inter_v1::o1_strToLong(OpFuncParams ¶ms) { int16 destVar; int32 res; - strVar = _vm->_parse->parseVarIndex(); + strVar = _vm->_game->_script->readVarIndex(); strncpy0(str, GET_VARO_STR(strVar), 19); res = atoi(str); - destVar = _vm->_parse->parseVarIndex(); + destVar = _vm->_game->_script->readVarIndex(); WRITE_VAR_OFFSET(destVar, res); return false; } bool Inter_v1::o1_invalidate(OpFuncParams ¶ms) { - _vm->_draw->_destSurface = load16(); - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteRight = _vm->_parse->parseValExpr(); - _vm->_draw->_frontColor = _vm->_parse->parseValExpr(); + _vm->_draw->_destSurface = _vm->_game->_script->readInt16(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteRight = _vm->_game->_script->readValExpr(); + _vm->_draw->_frontColor = _vm->_game->_script->readValExpr(); _vm->_draw->spriteOperation(DRAW_INVALIDATE); return false; } bool Inter_v1::o1_setBackDelta(OpFuncParams ¶ms) { - _vm->_draw->_backDeltaX = _vm->_parse->parseValExpr(); - _vm->_draw->_backDeltaY = _vm->_parse->parseValExpr(); + _vm->_draw->_backDeltaX = _vm->_game->_script->readValExpr(); + _vm->_draw->_backDeltaY = _vm->_game->_script->readValExpr(); return false; } @@ -1977,9 +1499,9 @@ bool Inter_v1::o1_playSound(OpFuncParams ¶ms) { int16 index; int16 endRep; - index = _vm->_parse->parseValExpr(); - repCount = _vm->_parse->parseValExpr(); - frequency = _vm->_parse->parseValExpr(); + index = _vm->_game->_script->readValExpr(); + repCount = _vm->_game->_script->readValExpr(); + frequency = _vm->_game->_script->readValExpr(); SoundDesc *sample = _vm->_sound->sampleGetBySlot(index); @@ -2002,7 +1524,7 @@ bool Inter_v1::o1_playSound(OpFuncParams ¶ms) { } if (sample->getType() == SOUND_ADL) { - _vm->_sound->adlibLoad(sample->getData(), sample->size(), index); + _vm->_sound->adlibLoadADL(sample->getData(), sample->size(), index); _vm->_sound->adlibSetRepeating(repCount - 1); _vm->_sound->adlibPlay(); } else { @@ -2015,7 +1537,7 @@ bool Inter_v1::o1_playSound(OpFuncParams ¶ms) { bool Inter_v1::o1_stopSound(OpFuncParams ¶ms) { _vm->_sound->adlibStop(); - _vm->_sound->blasterStop(_vm->_parse->parseValExpr()); + _vm->_sound->blasterStop(_vm->_game->_script->readValExpr()); _soundEndTimeKey = 0; return false; @@ -2041,8 +1563,8 @@ bool Inter_v1::o1_playComposition(OpFuncParams ¶ms) { int16 dataVar; int16 freqVal; - dataVar = _vm->_parse->parseVarIndex(); - freqVal = _vm->_parse->parseValExpr(); + dataVar = _vm->_game->_script->readVarIndex(); + freqVal = _vm->_game->_script->readValExpr(); for (int i = 0; i < 50; i++) composition[i] = (int16) VAR_OFFSET(dataVar + i * 4); @@ -2054,8 +1576,8 @@ bool Inter_v1::o1_getFreeMem(OpFuncParams ¶ms) { int16 freeVar; int16 maxFreeVar; - freeVar = _vm->_parse->parseVarIndex(); - maxFreeVar = _vm->_parse->parseVarIndex(); + freeVar = _vm->_game->_script->readVarIndex(); + maxFreeVar = _vm->_game->_script->readVarIndex(); // HACK WRITE_VAR_OFFSET(freeVar, 1000000); @@ -2067,22 +1589,22 @@ bool Inter_v1::o1_checkData(OpFuncParams ¶ms) { int16 handle; int16 varOff; - evalExpr(0); - varOff = _vm->_parse->parseVarIndex(); - handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr); + _vm->_game->_script->evalExpr(0); + varOff = _vm->_game->_script->readVarIndex(); + handle = _vm->_dataIO->openData(_vm->_game->_script->getResultStr()); WRITE_VAR_OFFSET(varOff, handle); if (handle >= 0) _vm->_dataIO->closeData(handle); else - warning("File \"%s\" not found", _vm->_global->_inter_resStr); + warning("File \"%s\" not found", _vm->_game->_script->getResultStr()); return false; } bool Inter_v1::o1_prepareStr(OpFuncParams ¶ms) { int16 strVar; - strVar = _vm->_parse->parseVarIndex(); + strVar = _vm->_game->_script->readVarIndex(); _vm->_util->prepareStr(GET_VARO_FSTR(strVar)); return false; } @@ -2091,12 +1613,12 @@ bool Inter_v1::o1_insertStr(OpFuncParams ¶ms) { int16 pos; int16 strVar; - strVar = _vm->_parse->parseVarIndex(); - evalExpr(0); - pos = _vm->_parse->parseValExpr(); + strVar = _vm->_game->_script->readVarIndex(); + _vm->_game->_script->evalExpr(0); + pos = _vm->_game->_script->readValExpr(); char *str = GET_VARO_FSTR(strVar); - _vm->_util->insertStr(_vm->_global->_inter_resStr, str, pos); + _vm->_util->insertStr(_vm->_game->_script->getResultStr(), str, pos); return false; } @@ -2105,9 +1627,9 @@ bool Inter_v1::o1_cutStr(OpFuncParams ¶ms) { int16 pos; int16 size; - strVar = _vm->_parse->parseVarIndex(); - pos = _vm->_parse->parseValExpr(); - size = _vm->_parse->parseValExpr(); + strVar = _vm->_game->_script->readVarIndex(); + pos = _vm->_game->_script->readValExpr(); + size = _vm->_game->_script->readValExpr(); _vm->_util->cutFromStr(GET_VARO_STR(strVar), pos, size); return false; } @@ -2117,11 +1639,11 @@ bool Inter_v1::o1_strstr(OpFuncParams ¶ms) { int16 resVar; int16 pos; - strVar = _vm->_parse->parseVarIndex(); - evalExpr(0); - resVar = _vm->_parse->parseVarIndex(); + strVar = _vm->_game->_script->readVarIndex(); + _vm->_game->_script->evalExpr(0); + resVar = _vm->_game->_script->readVarIndex(); - char *res = strstr(GET_VARO_STR(strVar), _vm->_global->_inter_resStr); + char *res = strstr(GET_VARO_STR(strVar), _vm->_game->_script->getResultStr()); pos = res ? (res - (GET_VARO_STR(strVar))) : -1; WRITE_VAR_OFFSET(resVar, pos); return false; @@ -2131,17 +1653,17 @@ bool Inter_v1::o1_istrlen(OpFuncParams ¶ms) { int16 len; int16 strVar; - strVar = _vm->_parse->parseVarIndex(); + strVar = _vm->_game->_script->readVarIndex(); len = strlen(GET_VARO_STR(strVar)); - strVar = _vm->_parse->parseVarIndex(); + strVar = _vm->_game->_script->readVarIndex(); WRITE_VAR_OFFSET(strVar, len); return false; } bool Inter_v1::o1_setMousePos(OpFuncParams ¶ms) { - _vm->_global->_inter_mouseX = _vm->_parse->parseValExpr(); - _vm->_global->_inter_mouseY = _vm->_parse->parseValExpr(); + _vm->_global->_inter_mouseX = _vm->_game->_script->readValExpr(); + _vm->_global->_inter_mouseY = _vm->_game->_script->readValExpr(); _vm->_global->_inter_mouseX -= _vm->_video->_scrollOffsetX; _vm->_global->_inter_mouseY -= _vm->_video->_scrollOffsetY; if (_vm->_global->_useMouse != 0) @@ -2151,7 +1673,7 @@ bool Inter_v1::o1_setMousePos(OpFuncParams ¶ms) { } bool Inter_v1::o1_setFrameRate(OpFuncParams ¶ms) { - _vm->_util->setFrameRate(_vm->_parse->parseValExpr()); + _vm->_util->setFrameRate(_vm->_game->_script->readValExpr()); return false; } @@ -2177,27 +1699,23 @@ bool Inter_v1::o1_blitCursor(OpFuncParams ¶ms) { bool Inter_v1::o1_loadFont(OpFuncParams ¶ms) { int16 index; - evalExpr(0); - index = load16(); + _vm->_game->_script->evalExpr(0); + index = _vm->_game->_script->readInt16(); delete _vm->_draw->_fonts[index]; _vm->_draw->animateCursor(4); - if (_vm->_game->_extHandle >= 0) - _vm->_dataIO->closeData(_vm->_game->_extHandle); _vm->_draw->_fonts[index] = - _vm->_util->loadFont(_vm->_global->_inter_resStr); + _vm->_util->loadFont(_vm->_game->_script->getResultStr()); - if (_vm->_game->_extHandle >= 0) - _vm->_game->_extHandle = _vm->_dataIO->openData(_vm->_game->_curExtFile); return false; } bool Inter_v1::o1_freeFont(OpFuncParams ¶ms) { int16 index; - index = load16(); + index = _vm->_game->_script->readInt16(); delete _vm->_draw->_fonts[index]; _vm->_draw->_fonts[index] = 0; return false; @@ -2210,17 +1728,14 @@ bool Inter_v1::o1_readData(OpFuncParams ¶ms) { int16 offset; int16 handle; - evalExpr(0); - dataVar = _vm->_parse->parseVarIndex(); - size = _vm->_parse->parseValExpr(); - offset = _vm->_parse->parseValExpr(); + _vm->_game->_script->evalExpr(0); + dataVar = _vm->_game->_script->readVarIndex(); + size = _vm->_game->_script->readValExpr(); + offset = _vm->_game->_script->readValExpr(); retSize = 0; - if (_vm->_game->_extHandle >= 0) - _vm->_dataIO->closeData(_vm->_game->_extHandle); - WRITE_VAR(1, 1); - handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr); + handle = _vm->_dataIO->openData(_vm->_game->_script->getResultStr()); if (handle >= 0) { DataStream *stream = _vm->_dataIO->openAsStream(handle, true); @@ -2241,8 +1756,6 @@ bool Inter_v1::o1_readData(OpFuncParams ¶ms) { delete stream; } - if (_vm->_game->_extHandle >= 0) - _vm->_game->_extHandle = _vm->_dataIO->openData(_vm->_game->_curExtFile); return false; } @@ -2255,22 +1768,22 @@ bool Inter_v1::o1_writeData(OpFuncParams ¶ms) { // (Gobliiins 1 doesn't use save file), so we just warn should it be // called regardless. - evalExpr(0); - dataVar = _vm->_parse->parseVarIndex(); - size = _vm->_parse->parseValExpr(); - offset = _vm->_parse->parseValExpr(); + _vm->_game->_script->evalExpr(0); + dataVar = _vm->_game->_script->readVarIndex(); + size = _vm->_game->_script->readValExpr(); + offset = _vm->_game->_script->readValExpr(); - warning("Attempted to write to file \"%s\"", _vm->_global->_inter_resStr); + warning("Attempted to write to file \"%s\"", _vm->_game->_script->getResultStr()); WRITE_VAR(1, 0); return false; } bool Inter_v1::o1_manageDataFile(OpFuncParams ¶ms) { - evalExpr(0); + _vm->_game->_script->evalExpr(0); - if (_vm->_global->_inter_resStr[0] != 0) - _vm->_dataIO->openDataFile(_vm->_global->_inter_resStr); + if (_vm->_game->_script->getResultStr()[0] != 0) + _vm->_dataIO->openDataFile(_vm->_game->_script->getResultStr()); else _vm->_dataIO->closeDataFile(); return false; @@ -2434,16 +1947,16 @@ void Inter_v1::o1_getMaxTick(OpGobParams ¶ms) { } void Inter_v1::o1_manipulateMap(OpGobParams ¶ms) { - int16 xPos = load16(); - int16 yPos = load16(); - int16 item = load16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); + int16 item = _vm->_game->_script->readInt16(); manipulateMap(xPos, yPos, item); } void Inter_v1::o1_getItem(OpGobParams ¶ms) { - int16 xPos = load16(); - int16 yPos = load16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); if ((_vm->_map->getItem(xPos, yPos) & 0xFF00) != 0) params.retVarPtr = (uint32) ((_vm->_map->getItem(xPos, yPos) & 0xFF00) >> 8); @@ -2452,9 +1965,9 @@ void Inter_v1::o1_getItem(OpGobParams ¶ms) { } void Inter_v1::o1_manipulateMapIndirect(OpGobParams ¶ms) { - int16 xPos = load16(); - int16 yPos = load16(); - int16 item = load16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); + int16 item = _vm->_game->_script->readInt16(); xPos = VAR(xPos); yPos = VAR(yPos); @@ -2464,8 +1977,8 @@ void Inter_v1::o1_manipulateMapIndirect(OpGobParams ¶ms) { } void Inter_v1::o1_getItemIndirect(OpGobParams ¶ms) { - int16 xPos = load16(); - int16 yPos = load16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); xPos = VAR(xPos); yPos = VAR(yPos); @@ -2477,17 +1990,17 @@ void Inter_v1::o1_getItemIndirect(OpGobParams ¶ms) { } void Inter_v1::o1_setPassMap(OpGobParams ¶ms) { - int16 xPos = load16(); - int16 yPos = load16(); - int16 val = load16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); + int16 val = _vm->_game->_script->readInt16(); _vm->_map->setPass(xPos, yPos, val); } void Inter_v1::o1_setGoblinPosH(OpGobParams ¶ms) { int16 layer; - int16 item = load16(); - int16 xPos = load16(); - int16 yPos = load16(); + int16 item = _vm->_game->_script->readInt16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); _vm->_goblin->_gobPositions[item].x = xPos * 2; _vm->_goblin->_gobPositions[item].y = yPos * 2; @@ -2522,20 +2035,20 @@ void Inter_v1::o1_setGoblinPosH(OpGobParams ¶ms) { } void Inter_v1::o1_getGoblinPosXH(OpGobParams ¶ms) { - int16 item = load16(); + int16 item = _vm->_game->_script->readInt16(); params.retVarPtr = (uint32) (_vm->_goblin->_gobPositions[item].x >> 1); } void Inter_v1::o1_getGoblinPosYH(OpGobParams ¶ms) { - int16 item = load16(); + int16 item = _vm->_game->_script->readInt16(); params.retVarPtr = (uint32) (_vm->_goblin->_gobPositions[item].y >> 1); } void Inter_v1::o1_setGoblinMultState(OpGobParams ¶ms) { int16 layer; - int16 item = load16(); - int16 xPos = load16(); - int16 yPos = load16(); + int16 item = _vm->_game->_script->readInt16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); params.objDesc = _vm->_goblin->_goblins[item]; if (yPos == 0) { @@ -2594,18 +2107,18 @@ void Inter_v1::o1_setGoblinMultState(OpGobParams ¶ms) { } void Inter_v1::o1_setGoblinUnk14(OpGobParams ¶ms) { - int16 item = load16(); - int16 val = load16(); + int16 item = _vm->_game->_script->readInt16(); + int16 val = _vm->_game->_script->readInt16(); params.objDesc = _vm->_goblin->_objects[item]; params.objDesc->unk14 = val; } void Inter_v1::o1_setItemIdInPocket(OpGobParams ¶ms) { - _vm->_goblin->_itemIdInPocket = load16(); + _vm->_goblin->_itemIdInPocket = _vm->_game->_script->readInt16(); } void Inter_v1::o1_setItemIndInPocket(OpGobParams ¶ms) { - _vm->_goblin->_itemIndInPocket = load16(); + _vm->_goblin->_itemIndInPocket = _vm->_game->_script->readInt16(); } void Inter_v1::o1_getItemIdInPocket(OpGobParams ¶ms) { @@ -2618,9 +2131,9 @@ void Inter_v1::o1_getItemIndInPocket(OpGobParams ¶ms) { void Inter_v1::o1_setGoblinPos(OpGobParams ¶ms) { int16 layer; - int16 item = load16(); - int16 xPos = load16(); - int16 yPos = load16(); + int16 item = _vm->_game->_script->readInt16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); _vm->_goblin->_gobPositions[item].x = xPos; _vm->_goblin->_gobPositions[item].y = yPos; @@ -2655,8 +2168,8 @@ void Inter_v1::o1_setGoblinPos(OpGobParams ¶ms) { void Inter_v1::o1_setGoblinState(OpGobParams ¶ms) { int16 layer; - int16 item = load16(); - int16 state = load16(); + int16 item = _vm->_game->_script->readInt16(); + int16 state = _vm->_game->_script->readInt16(); params.objDesc = _vm->_goblin->_goblins[item]; params.objDesc->nextState = state; @@ -2680,8 +2193,8 @@ void Inter_v1::o1_setGoblinState(OpGobParams ¶ms) { void Inter_v1::o1_setGoblinStateRedraw(OpGobParams ¶ms) { int16 layer; - int16 item = load16(); - int16 state = load16(); + int16 item = _vm->_game->_script->readInt16(); + int16 state = _vm->_game->_script->readInt16(); params.objDesc = _vm->_goblin->_objects[item]; params.objDesc->nextState = state; @@ -2708,7 +2221,7 @@ void Inter_v1::o1_setGoblinStateRedraw(OpGobParams ¶ms) { } void Inter_v1::o1_decRelaxTime(OpGobParams ¶ms) { - params.extraData = load16(); + params.extraData = _vm->_game->_script->readInt16(); params.objDesc = _vm->_goblin->_objects[params.extraData]; params.objDesc->relaxTime--; @@ -2722,12 +2235,12 @@ void Inter_v1::o1_decRelaxTime(OpGobParams ¶ms) { } void Inter_v1::o1_getGoblinPosX(OpGobParams ¶ms) { - int16 item = load16(); + int16 item = _vm->_game->_script->readInt16(); params.retVarPtr = (uint32) _vm->_goblin->_gobPositions[item].x; } void Inter_v1::o1_getGoblinPosY(OpGobParams ¶ms) { - int16 item = load16(); + int16 item = _vm->_game->_script->readInt16(); params.retVarPtr = (uint32) _vm->_goblin->_gobPositions[item].y; } @@ -2736,18 +2249,18 @@ void Inter_v1::o1_clearPathExistence(OpGobParams ¶ms) { } void Inter_v1::o1_setGoblinVisible(OpGobParams ¶ms) { - params.extraData = load16(); + params.extraData = _vm->_game->_script->readInt16(); _vm->_goblin->_goblins[params.extraData]->visible = 1; } void Inter_v1::o1_setGoblinInvisible(OpGobParams ¶ms) { - params.extraData = load16(); + params.extraData = _vm->_game->_script->readInt16(); _vm->_goblin->_goblins[params.extraData]->visible = 0; } void Inter_v1::o1_getObjectIntersect(OpGobParams ¶ms) { - params.extraData = load16(); - int16 item = load16(); + params.extraData = _vm->_game->_script->readInt16(); + int16 item = _vm->_game->_script->readInt16(); params.objDesc = _vm->_goblin->_objects[params.extraData]; if (_vm->_goblin->objIntersected(params.objDesc, @@ -2758,8 +2271,8 @@ void Inter_v1::o1_getObjectIntersect(OpGobParams ¶ms) { } void Inter_v1::o1_getGoblinIntersect(OpGobParams ¶ms) { - params.extraData = load16(); - int16 item = load16(); + params.extraData = _vm->_game->_script->readInt16(); + int16 item = _vm->_game->_script->readInt16(); params.objDesc = _vm->_goblin->_goblins[params.extraData]; if (_vm->_goblin->objIntersected(params.objDesc, @@ -2770,10 +2283,10 @@ void Inter_v1::o1_getGoblinIntersect(OpGobParams ¶ms) { } void Inter_v1::o1_setItemPos(OpGobParams ¶ms) { - int16 item = load16(); - int16 xPos = load16(); - int16 yPos = load16(); - int16 val = load16(); + int16 item = _vm->_game->_script->readInt16(); + int16 xPos = _vm->_game->_script->readInt16(); + int16 yPos = _vm->_game->_script->readInt16(); + int16 val = _vm->_game->_script->readInt16(); _vm->_map->_itemPoses[item].x = xPos; _vm->_map->_itemPoses[item].y = yPos; @@ -2781,12 +2294,9 @@ void Inter_v1::o1_setItemPos(OpGobParams ¶ms) { } void Inter_v1::o1_loadObjects(OpGobParams ¶ms) { - params.extraData = load16(); - if (_vm->_game->_extHandle >= 0) - _vm->_dataIO->closeData(_vm->_game->_extHandle); + params.extraData = _vm->_game->_script->readInt16(); _vm->_goblin->loadObjects((char *) VAR_ADDRESS(params.extraData)); - _vm->_game->_extHandle = _vm->_dataIO->openData(_vm->_game->_curExtFile); } void Inter_v1::o1_freeObjects(OpGobParams ¶ms) { @@ -2811,8 +2321,8 @@ void Inter_v1::o1_loadMap(OpGobParams ¶ms) { void Inter_v1::o1_moveGoblin(OpGobParams ¶ms) { int16 item; - params.extraData = load16(); - int16 xPos = load16(); + params.extraData = _vm->_game->_script->readInt16(); + int16 xPos = _vm->_game->_script->readInt16(); if ((uint16) VAR(xPos) == 0) { item = @@ -2837,9 +2347,9 @@ void Inter_v1::o1_loadGoblin(OpGobParams ¶ms) { } void Inter_v1::o1_writeTreatItem(OpGobParams ¶ms) { - params.extraData = load16(); - int16 cmd = load16(); - int16 xPos = load16(); + params.extraData = _vm->_game->_script->readInt16(); + int16 cmd = _vm->_game->_script->readInt16(); + int16 xPos = _vm->_game->_script->readInt16(); if ((uint16) VAR(xPos) == 0) { WRITE_VAR(cmd, _vm->_goblin->treatItem((uint16) VAR(params.extraData))); @@ -2855,7 +2365,7 @@ void Inter_v1::o1_moveGoblin0(OpGobParams ¶ms) { } void Inter_v1::o1_setGoblinTarget(OpGobParams ¶ms) { - params.extraData = load16(); + params.extraData = _vm->_game->_script->readInt16(); if (VAR(params.extraData) != 0) _vm->_goblin->_goesAtTarget = 1; else @@ -2863,11 +2373,11 @@ void Inter_v1::o1_setGoblinTarget(OpGobParams ¶ms) { } void Inter_v1::o1_setGoblinObjectsPos(OpGobParams ¶ms) { - params.extraData = load16(); + params.extraData = _vm->_game->_script->readInt16(); params.extraData = VAR(params.extraData); _vm->_goblin->_objects[10]->xPos = params.extraData; - params.extraData = load16(); + params.extraData = _vm->_game->_script->readInt16(); params.extraData = VAR(params.extraData); _vm->_goblin->_objects[10]->yPos = params.extraData; } @@ -2961,38 +2471,24 @@ void Inter_v1::o1_initGoblin(OpGobParams ¶ms) { } int16 Inter_v1::loadSound(int16 slot) { - byte *dataPtr; - int16 id; - uint32 dataSize; - SoundSource source; - if (slot == -1) - slot = _vm->_parse->parseValExpr(); + slot = _vm->_game->_script->readValExpr(); - id = load16(); - if (id == -1) { - _vm->_global->_inter_execPtr += 9; + uint16 id = _vm->_game->_script->readUint16(); + if (id == 0xFFFF) { + _vm->_game->_script->skip(9); return 0; } - if (id >= 30000) { - source = SOUND_EXT; - - dataPtr = (byte *) _vm->_game->loadExtData(id, 0, 0, &dataSize); - } else { - int16 totSize; - - source = SOUND_TOT; + Resource *resource = _vm->_game->_resources->getResource(id); + if (!resource) + return 0; - dataPtr = (byte *) _vm->_game->loadTotResource(id, &totSize); - dataSize = (uint32) ((int32) totSize); - } + SoundDesc *sample = _vm->_sound->sampleGetBySlot(slot); + if (!sample) + return 0; - if (dataPtr) { - SoundDesc *sample = _vm->_sound->sampleGetBySlot(slot); - if (sample) - sample->load(SOUND_SND, source, dataPtr, dataSize); - } + sample->load(SOUND_SND, resource); return 0; } diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index 3107fcf9bc..82822330b1 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -36,10 +36,12 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/expression.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/goblin.h" #include "gob/map.h" #include "gob/mult.h" -#include "gob/parse.h" #include "gob/scenery.h" #include "gob/video.h" #include "gob/save/saveload.h" @@ -48,673 +50,126 @@ namespace Gob { -#define OPCODE(x) _OPCODE(Inter_v2, x) - -const int Inter_v2::_goblinFuncLookUp[][2] = { - {0, 0}, - {1, 1}, - {2, 2}, - {4, 3}, - {5, 4}, - {6, 5}, - {7, 6}, - {8, 7}, - {9, 8}, - {10, 9}, - {12, 10}, - {13, 11}, - {14, 12}, - {15, 13}, - {16, 14}, - {21, 15}, - {22, 16}, - {23, 17}, - {24, 18}, - {25, 19}, - {26, 20}, - {27, 21}, - {28, 22}, - {29, 23}, - {30, 24}, - {32, 25}, - {33, 26}, - {34, 27}, - {35, 28}, - {36, 29}, - {37, 30}, - {40, 31}, - {41, 32}, - {42, 33}, - {43, 34}, - {44, 35}, - {50, 36}, - {52, 37}, - {53, 38}, - {100, 39}, - {500, 40}, - {501, 41} -}; +#define OPCODEVER Inter_v2 +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) Inter_v2::Inter_v2(GobEngine *vm) : Inter_v1(vm) { - setupOpcodes(); } -void Inter_v2::setupOpcodes() { - static const OpcodeDrawEntryV2 opcodesDraw[256] = { - /* 00 */ - OPCODE(o1_loadMult), - OPCODE(o2_playMult), - OPCODE(o2_freeMultKeys), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o1_initCursor), - /* 08 */ - OPCODE(o1_initCursorAnim), - OPCODE(o1_clearCursorAnim), - OPCODE(o2_setRenderFlags), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - OPCODE(o1_loadAnim), - OPCODE(o1_freeAnim), - OPCODE(o1_updateAnim), - OPCODE(o2_multSub), - /* 14 */ - OPCODE(o2_initMult), - OPCODE(o1_freeMult), - OPCODE(o1_animate), - OPCODE(o2_loadMultObject), - /* 18 */ - OPCODE(o1_getAnimLayerInfo), - OPCODE(o1_getObjAnimSize), - OPCODE(o1_loadStatic), - OPCODE(o1_freeStatic), - /* 1C */ - OPCODE(o2_renderStatic), - OPCODE(o2_loadCurLayer), - {0, ""}, - {0, ""}, - /* 20 */ - OPCODE(o2_playCDTrack), - OPCODE(o2_waitCDTrackEnd), - OPCODE(o2_stopCD), - OPCODE(o2_readLIC), - /* 24 */ - OPCODE(o2_freeLIC), - OPCODE(o2_getCDTrackPos), - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o2_loadFontToSprite), - OPCODE(o1_freeFontToSprite), - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - OPCODE(o2_totSub), - OPCODE(o2_switchTotSub), - OPCODE(o2_pushVars), - OPCODE(o2_popVars), - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 48 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 4C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 50 */ - OPCODE(o2_loadMapObjects), - OPCODE(o2_freeGoblins), - OPCODE(o2_moveGoblin), - OPCODE(o2_writeGoblinPos), - /* 54 */ - OPCODE(o2_stopGoblin), - OPCODE(o2_setGoblinState), - OPCODE(o2_placeGoblin), - {0, ""}, - /* 58 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 5C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 60 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 64 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 68 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 6C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 70 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 74 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 78 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 7C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 80 */ - OPCODE(o2_initScreen), - OPCODE(o2_scroll), - OPCODE(o2_setScrollOffset), - OPCODE(o2_playImd), - /* 84 */ - OPCODE(o2_getImdInfo), - OPCODE(o2_openItk), - OPCODE(o2_closeItk), - OPCODE(o2_setImdFrontSurf), - /* 88 */ - OPCODE(o2_resetImdFrontSurf), - {0, ""}, - {0, ""}, - {0, ""}, - /* 8C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 90 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 94 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 98 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 9C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* AC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* BC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* CC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* DC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* EC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* FC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""} - }; - - static const OpcodeFuncEntryV2 opcodesFunc[80] = { - /* 00 */ - OPCODE(o1_callSub), - OPCODE(o1_callSub), - OPCODE(o1_printTotText), - OPCODE(o1_loadCursor), - /* 04 */ - {0, ""}, - OPCODE(o1_switch), - OPCODE(o1_repeatUntil), - OPCODE(o1_whileDo), - /* 08 */ - OPCODE(o1_if), - OPCODE(o2_assign), - OPCODE(o1_loadSpriteToPos), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - OPCODE(o2_printText), - OPCODE(o1_loadTot), - OPCODE(o1_palLoad), - /* 14 */ - OPCODE(o1_keyFunc), - OPCODE(o1_capturePush), - OPCODE(o1_capturePop), - OPCODE(o2_animPalInit), - /* 18 */ - OPCODE(o2_addCollision), - OPCODE(o2_freeCollision), - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - OPCODE(o1_drawOperations), - OPCODE(o1_setcmdCount), - /* 20 */ - OPCODE(o1_return), - OPCODE(o1_renewTimeInVars), - OPCODE(o1_speakerOn), - OPCODE(o1_speakerOff), - /* 24 */ - OPCODE(o1_putPixel), - OPCODE(o2_goblinFunc), - OPCODE(o1_createSprite), - OPCODE(o1_freeSprite), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_returnTo), - OPCODE(o1_loadSpriteContent), - OPCODE(o1_copySprite), - OPCODE(o1_fillRect), - /* 34 */ - OPCODE(o1_drawLine), - OPCODE(o1_strToLong), - OPCODE(o1_invalidate), - OPCODE(o1_setBackDelta), - /* 38 */ - OPCODE(o1_playSound), - OPCODE(o2_stopSound), - OPCODE(o2_loadSound), - OPCODE(o1_freeSoundSlot), - /* 3C */ - OPCODE(o1_waitEndPlay), - OPCODE(o1_playComposition), - OPCODE(o2_getFreeMem), - OPCODE(o2_checkData), - /* 40 */ - {0, ""}, - OPCODE(o1_prepareStr), - OPCODE(o1_insertStr), - OPCODE(o1_cutStr), - /* 44 */ - OPCODE(o1_strstr), - OPCODE(o1_istrlen), - OPCODE(o1_setMousePos), - OPCODE(o1_setFrameRate), - /* 48 */ - OPCODE(o1_animatePalette), - OPCODE(o1_animateCursor), - OPCODE(o1_blitCursor), - OPCODE(o1_loadFont), - /* 4C */ - OPCODE(o1_freeFont), - OPCODE(o2_readData), - OPCODE(o2_writeData), - OPCODE(o1_manageDataFile), - }; - - static const OpcodeGoblinEntryV2 opcodesGoblin[71] = { - /* 00 */ - OPCODE(o2_loadInfogramesIns), - OPCODE(o2_startInfogrames), - OPCODE(o2_stopInfogrames), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 08 */ - {0, ""}, - OPCODE(o2_playInfogrames), - {0, ""}, - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 14 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 18 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 20 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 24 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o2_handleGoblins), - /* 28 */ - OPCODE(o2_playProtracker), - OPCODE(o2_stopProtracker), - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - }; - - _opcodesDrawV2 = opcodesDraw; - _opcodesFuncV2 = opcodesFunc; - _opcodesGoblinV2 = opcodesGoblin; -} +void Inter_v2::setupOpcodesDraw() { + Inter_v1::setupOpcodesDraw(); -void Inter_v2::executeDrawOpcode(byte i) { - debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); + OPCODEDRAW(0x01, o2_playMult); + OPCODEDRAW(0x02, o2_freeMultKeys); - OpcodeDrawProcV2 op = _opcodesDrawV2[i].proc; + OPCODEDRAW(0x0A, o2_setRenderFlags); - if (op == 0) - warning("unimplemented opcodeDraw: %d", i); - else - (this->*op) (); -} + OPCODEDRAW(0x13, o2_multSub); -bool Inter_v2::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s)", - i, j, i, j, getOpcodeFuncDesc(i, j)); + OPCODEDRAW(0x14, o2_initMult); - if ((i > 4) || (j > 15)) { - warning("unimplemented opcodeFunc: %d.%d", i, j); - return false; - } + OPCODEDRAW(0x17, o2_loadMultObject); - OpcodeFuncProcV2 op = _opcodesFuncV2[i*16 + j].proc; + OPCODEDRAW(0x1C, o2_renderStatic); + OPCODEDRAW(0x1D, o2_loadCurLayer); - if (op == 0) - warning("unimplemented opcodeFunc: %d.%d", i, j); - else - return (this->*op) (params); + OPCODEDRAW(0x20, o2_playCDTrack); + OPCODEDRAW(0x21, o2_waitCDTrackEnd); + OPCODEDRAW(0x22, o2_stopCD); + OPCODEDRAW(0x23, o2_readLIC); - return false; -} + OPCODEDRAW(0x24, o2_freeLIC); + OPCODEDRAW(0x25, o2_getCDTrackPos); -void Inter_v2::executeGoblinOpcode(int i, OpGobParams ¶ms) { - debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); + OPCODEDRAW(0x30, o2_loadFontToSprite); - OpcodeGoblinProcV2 op = 0; + OPCODEDRAW(0x40, o2_totSub); + OPCODEDRAW(0x41, o2_switchTotSub); + OPCODEDRAW(0x42, o2_pushVars); + OPCODEDRAW(0x43, o2_popVars); - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) { - op = _opcodesGoblinV2[_goblinFuncLookUp[j][1]].proc; - break; - } + OPCODEDRAW(0x50, o2_loadMapObjects); + OPCODEDRAW(0x51, o2_freeGoblins); + OPCODEDRAW(0x52, o2_moveGoblin); + OPCODEDRAW(0x53, o2_writeGoblinPos); - if (op == 0) { - int16 val; + OPCODEDRAW(0x54, o2_stopGoblin); + OPCODEDRAW(0x55, o2_setGoblinState); + OPCODEDRAW(0x56, o2_placeGoblin); - _vm->_global->_inter_execPtr -= 2; - val = load16(); - _vm->_global->_inter_execPtr += val << 1; - } else - (this->*op) (params); -} + OPCODEDRAW(0x80, o2_initScreen); + OPCODEDRAW(0x81, o2_scroll); + OPCODEDRAW(0x82, o2_setScrollOffset); + OPCODEDRAW(0x83, o2_playImd); + + OPCODEDRAW(0x84, o2_getImdInfo); + OPCODEDRAW(0x85, o2_openItk); + OPCODEDRAW(0x86, o2_closeItk); + OPCODEDRAW(0x87, o2_setImdFrontSurf); -const char *Inter_v2::getOpcodeDrawDesc(byte i) { - return _opcodesDrawV2[i].desc; + OPCODEDRAW(0x88, o2_resetImdFrontSurf); } -const char *Inter_v2::getOpcodeFuncDesc(byte i, byte j) { - if ((i > 4) || (j > 15)) - return ""; +void Inter_v2::setupOpcodesFunc() { + Inter_v1::setupOpcodesFunc(); + + OPCODEFUNC(0x09, o2_assign); + + OPCODEFUNC(0x11, o2_printText); + + OPCODEFUNC(0x17, o2_animPalInit); - return _opcodesFuncV2[i*16 + j].desc; + OPCODEFUNC(0x18, o2_addCollision); + OPCODEFUNC(0x19, o2_freeCollision); + + OPCODEFUNC(0x25, o2_goblinFunc); + + OPCODEFUNC(0x39, o2_stopSound); + OPCODEFUNC(0x3A, o2_loadSound); + + OPCODEFUNC(0x3E, o2_getFreeMem); + OPCODEFUNC(0x3F, o2_checkData); + + OPCODEFUNC(0x4D, o2_readData); + OPCODEFUNC(0x4E, o2_writeData); } -const char *Inter_v2::getOpcodeGoblinDesc(int i) { - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) - return _opcodesGoblinV2[_goblinFuncLookUp[j][1]].desc; - return ""; +void Inter_v2::setupOpcodesGob() { + OPCODEGOB( 0, o2_loadInfogramesIns); + OPCODEGOB( 1, o2_startInfogrames); + OPCODEGOB( 2, o2_stopInfogrames); + + OPCODEGOB( 10, o2_playInfogrames); + + OPCODEGOB(100, o2_handleGoblins); + + OPCODEGOB(500, o2_playProtracker); + OPCODEGOB(501, o2_stopProtracker); } -void Inter_v2::checkSwitchTable(byte **ppExec) { - byte cmd; +void Inter_v2::checkSwitchTable(uint32 &offset) { + byte type; int16 len; int32 value; bool found; found = false; - *ppExec = 0; + offset = 0; - cmd = *_vm->_global->_inter_execPtr; + type = _vm->_game->_script->peekByte(); - value = _vm->_parse->parseVarIndex(); + value = _vm->_game->_script->readVarIndex(); - switch (cmd) { - case 16: - case 18: + switch (type) { + case TYPE_VAR_INT8: + case TYPE_ARRAY_INT8: value = (int8) READ_VARO_UINT8(value); break; - case 23: - case 26: + case TYPE_VAR_INT32: + case TYPE_ARRAY_INT32: value = READ_VARO_UINT32(value); break; @@ -726,78 +181,74 @@ void Inter_v2::checkSwitchTable(byte **ppExec) { if (_terminate) return; - len = (int8) *_vm->_global->_inter_execPtr++; + len = _vm->_game->_script->readInt8(); while (len != -5) { for (int i = 0; i < len; i++) { - cmd = *_vm->_global->_inter_execPtr; + type = _vm->_game->_script->peekByte(); - switch (cmd) { - case 19: - _vm->_global->_inter_execPtr++; + switch (type) { + case TYPE_IMM_INT32: + _vm->_game->_script->skip(1); if (!found && - (value == - (int32) (READ_LE_UINT32(_vm->_global->_inter_execPtr)))) + (value == _vm->_game->_script->peekInt32())) found = true; - _vm->_global->_inter_execPtr += 5; + _vm->_game->_script->skip(5); break; - case 20: - _vm->_global->_inter_execPtr++; + case TYPE_IMM_INT16: + _vm->_game->_script->skip(1); if (!found && - (value == - (int16) (READ_LE_UINT16(_vm->_global->_inter_execPtr)))) + (value == _vm->_game->_script->peekInt16())) found = true; - _vm->_global->_inter_execPtr += 3; + _vm->_game->_script->skip(3); break; - case 21: - _vm->_global->_inter_execPtr++; - if (!found && (value == (int8) *_vm->_global->_inter_execPtr)) + case TYPE_IMM_INT8: + _vm->_game->_script->skip(1); + if (!found && (value == _vm->_game->_script->peekInt8())) found = true; - _vm->_global->_inter_execPtr += 2; + _vm->_game->_script->skip(2); break; default: if (!found) { - evalExpr(0); - if (value == _vm->_global->_inter_resVal) + _vm->_game->_script->evalExpr(0); + if (value == _vm->_game->_script->getResultInt()) found = true; } else - _vm->_parse->skipExpr(99); + _vm->_game->_script->skipExpr(99); break; } } - if (found && !*ppExec) - *ppExec = _vm->_global->_inter_execPtr; + if (found && (offset == 0)) + offset = _vm->_game->_script->pos(); - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; - len = (int8) *_vm->_global->_inter_execPtr++; + _vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2); + len = _vm->_game->_script->readInt8(); } - if ((*_vm->_global->_inter_execPtr >> 4) != 4) + if ((_vm->_game->_script->peekByte() >> 4) != 4) return; - _vm->_global->_inter_execPtr++; - if (!*ppExec) - *ppExec = _vm->_global->_inter_execPtr; + _vm->_game->_script->skip(1); + if (offset == 0) + offset = _vm->_game->_script->pos(); - _vm->_global->_inter_execPtr += - READ_LE_UINT16(_vm->_global->_inter_execPtr + 2) + 2; + _vm->_game->_script->skip(_vm->_game->_script->peekUint16(2) + 2); } void Inter_v2::o2_playMult() { int16 checkEscape; - checkEscape = load16(); + checkEscape = _vm->_game->_script->readInt16(); _vm->_mult->setMultData(checkEscape >> 1); _vm->_mult->playMult(VAR(57), -1, checkEscape & 0x1, 0); } void Inter_v2::o2_freeMultKeys() { - uint16 index = load16(); + uint16 index = _vm->_game->_script->readUint16(); if (!_vm->_mult->hasMultData(index)) return; @@ -810,7 +261,7 @@ void Inter_v2::o2_freeMultKeys() { void Inter_v2::o2_setRenderFlags() { int16 expr; - expr = _vm->_parse->parseValExpr(); + expr = _vm->_game->_script->readValExpr(); if (expr & 0x8000) { _vm->_draw->_renderFlags |= expr & 0x3FFF; @@ -823,7 +274,7 @@ void Inter_v2::o2_setRenderFlags() { } void Inter_v2::o2_multSub() { - _vm->_mult->multSub(_vm->_parse->parseValExpr()); + _vm->_mult->multSub(_vm->_game->_script->readValExpr()); } void Inter_v2::o2_initMult() { @@ -838,14 +289,14 @@ void Inter_v2::o2_initMult() { oldAnimHeight = _vm->_mult->_animHeight; oldObjCount = _vm->_mult->_objCount; - _vm->_mult->_animLeft = load16(); - _vm->_mult->_animTop = load16(); - _vm->_mult->_animWidth = load16(); - _vm->_mult->_animHeight = load16(); - _vm->_mult->_objCount = load16(); - posXVar = _vm->_parse->parseVarIndex(); - posYVar = _vm->_parse->parseVarIndex(); - animDataVar = _vm->_parse->parseVarIndex(); + _vm->_mult->_animLeft = _vm->_game->_script->readInt16(); + _vm->_mult->_animTop = _vm->_game->_script->readInt16(); + _vm->_mult->_animWidth = _vm->_game->_script->readInt16(); + _vm->_mult->_animHeight = _vm->_game->_script->readInt16(); + _vm->_mult->_objCount = _vm->_game->_script->readInt16(); + posXVar = _vm->_game->_script->readVarIndex(); + posYVar = _vm->_game->_script->readVarIndex(); + animDataVar = _vm->_game->_script->readVarIndex(); if (_vm->_mult->_objects && (oldObjCount != _vm->_mult->_objCount)) { warning("Initializing new objects without having " @@ -947,20 +398,20 @@ void Inter_v2::o2_loadMultObject() { int16 layer; byte *multData; - objIndex = _vm->_parse->parseValExpr(); - val = _vm->_parse->parseValExpr(); + objIndex = _vm->_game->_script->readValExpr(); + val = _vm->_game->_script->readValExpr(); *_vm->_mult->_objects[objIndex].pPosX = val; - val = _vm->_parse->parseValExpr(); + val = _vm->_game->_script->readValExpr(); *_vm->_mult->_objects[objIndex].pPosY = val; debugC(4, kDebugGameFlow, "Loading mult object %d", objIndex); multData = (byte *) _vm->_mult->_objects[objIndex].pAnimData; for (int i = 0; i < 11; i++) { - if (*_vm->_global->_inter_execPtr != 99) - multData[i] = _vm->_parse->parseValExpr(); + if (_vm->_game->_script->peekByte() != 99) + multData[i] = _vm->_game->_script->readValExpr(); else - _vm->_global->_inter_execPtr++; + _vm->_game->_script->skip(1); } Mult::Mult_Object &obj = _vm->_mult->_objects[objIndex]; @@ -1043,22 +494,22 @@ void Inter_v2::o2_renderStatic() { int16 layer; int16 index; - index = _vm->_parse->parseValExpr(); - layer = _vm->_parse->parseValExpr(); + index = _vm->_game->_script->readValExpr(); + layer = _vm->_game->_script->readValExpr(); _vm->_scenery->renderStatic(index, layer); } void Inter_v2::o2_loadCurLayer() { - _vm->_scenery->_curStatic = _vm->_parse->parseValExpr(); - _vm->_scenery->_curStaticLayer = _vm->_parse->parseValExpr(); + _vm->_scenery->_curStatic = _vm->_game->_script->readValExpr(); + _vm->_scenery->_curStaticLayer = _vm->_game->_script->readValExpr(); } void Inter_v2::o2_playCDTrack() { if (!(_vm->_draw->_renderFlags & RENDERFLAG_NOBLITINVALIDATED)) _vm->_draw->blitInvalidated(); - evalExpr(0); - _vm->_sound->cdPlay(_vm->_global->_inter_resStr); + _vm->_game->_script->evalExpr(0); + _vm->_sound->cdPlay(_vm->_game->_script->getResultStr()); } void Inter_v2::o2_waitCDTrackEnd() { @@ -1075,8 +526,8 @@ void Inter_v2::o2_stopCD() { void Inter_v2::o2_readLIC() { char path[40]; - evalExpr(0); - strncpy0(path, _vm->_global->_inter_resStr, 35); + _vm->_game->_script->evalExpr(0); + strncpy0(path, _vm->_game->_script->getResultStr(), 35); strcat(path, ".LIC"); _vm->_sound->cdLoadLIC(path); @@ -1092,24 +543,24 @@ void Inter_v2::o2_getCDTrackPos() { _vm->_util->longDelay(1); - varPos = _vm->_parse->parseVarIndex(); - varName = _vm->_parse->parseVarIndex(); + varPos = _vm->_game->_script->readVarIndex(); + varName = _vm->_game->_script->readVarIndex(); WRITE_VAR_OFFSET(varPos, _vm->_sound->cdGetTrackPos(GET_VARO_STR(varName))); WRITE_VARO_STR(varName, _vm->_sound->cdGetCurrentTrack()); } void Inter_v2::o2_loadFontToSprite() { - int16 i = load16(); - - _vm->_draw->_fontToSprite[i].sprite = *_vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_draw->_fontToSprite[i].base = *_vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_draw->_fontToSprite[i].width = *_vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; - _vm->_draw->_fontToSprite[i].height = *_vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += 2; + int16 i = _vm->_game->_script->readInt16(); + + _vm->_draw->_fontToSprite[i].sprite = _vm->_game->_script->readByte(); + _vm->_game->_script->skip(1); + _vm->_draw->_fontToSprite[i].base = _vm->_game->_script->readByte(); + _vm->_game->_script->skip(1); + _vm->_draw->_fontToSprite[i].width = _vm->_game->_script->readByte(); + _vm->_game->_script->skip(1); + _vm->_draw->_fontToSprite[i].height = _vm->_game->_script->readByte(); + _vm->_game->_script->skip(1); } void Inter_v2::o2_totSub() { @@ -1118,16 +569,16 @@ void Inter_v2::o2_totSub() { int flags; int i; - length = *_vm->_global->_inter_execPtr++; + length = _vm->_game->_script->readByte(); if ((length & 0x7F) > 13) error("Length in o2_totSub is greater than 13 (%d)", length); if (length & 0x80) { - evalExpr(0); - strcpy(totFile, _vm->_global->_inter_resStr); + _vm->_game->_script->evalExpr(0); + strcpy(totFile, _vm->_game->_script->getResultStr()); } else { for (i = 0; i < length; i++) - totFile[i] = (char) *_vm->_global->_inter_execPtr++; + totFile[i] = _vm->_game->_script->readChar(); totFile[i] = 0; } @@ -1135,7 +586,7 @@ void Inter_v2::o2_totSub() { if (!scumm_stricmp(totFile, "edit")) _vm->_util->forceMouseUp(); - flags = *_vm->_global->_inter_execPtr++; + flags = _vm->_game->_script->readByte(); _vm->_game->totSub(flags, totFile); } @@ -1143,8 +594,8 @@ void Inter_v2::o2_switchTotSub() { int16 index; int16 skipPlay; - index = load16(); - skipPlay = load16(); + index = _vm->_game->_script->readInt16(); + skipPlay = _vm->_game->_script->readInt16(); _vm->_game->switchTotSub(index, skipPlay); } @@ -1153,13 +604,13 @@ void Inter_v2::o2_pushVars() { byte count; int16 varOff; - count = *_vm->_global->_inter_execPtr++; + count = _vm->_game->_script->readByte(); for (int i = 0; i < count; i++, _varStackPos++) { - if ((*_vm->_global->_inter_execPtr == 25) || - (*_vm->_global->_inter_execPtr == 28)) { + if ((_vm->_game->_script->peekByte() == 25) || + (_vm->_game->_script->peekByte() == 28)) { - varOff = _vm->_parse->parseVarIndex(); - _vm->_global->_inter_execPtr++; + varOff = _vm->_game->_script->readVarIndex(); + _vm->_game->_script->skip(1); _variables->copyTo(varOff, _varStack + _varStackPos, _vm->_global->_inter_animDataSize * 4); @@ -1167,10 +618,12 @@ void Inter_v2::o2_pushVars() { _varStack[_varStackPos] = _vm->_global->_inter_animDataSize * 4; } else { - if (evalExpr(&varOff) != 20) - _vm->_global->_inter_resVal = 0; + int32 n = _vm->_game->_script->getResultInt(); + + if (_vm->_game->_script->evalExpr(&varOff) != 20) + n = 0; - memcpy(_varStack + _varStackPos, &_vm->_global->_inter_resVal, 4); + memcpy(_varStack + _varStackPos, &n, 4); _varStackPos += 4; _varStack[_varStackPos] = 4; } @@ -1182,9 +635,9 @@ void Inter_v2::o2_popVars() { int16 varOff; int16 size; - count = *_vm->_global->_inter_execPtr++; + count = _vm->_game->_script->readByte(); for (int i = 0; i < count; i++) { - varOff = _vm->_parse->parseVarIndex(); + varOff = _vm->_game->_script->readVarIndex(); size = _varStack[--_varStackPos]; _varStackPos -= size; @@ -1204,9 +657,9 @@ void Inter_v2::o2_moveGoblin() { int16 destX, destY; int16 index; - destX = _vm->_parse->parseValExpr(); - destY = _vm->_parse->parseValExpr(); - index = _vm->_parse->parseValExpr(); + destX = _vm->_game->_script->readValExpr(); + destY = _vm->_game->_script->readValExpr(); + index = _vm->_game->_script->readValExpr(); _vm->_goblin->move(destX, destY, index); } @@ -1214,15 +667,15 @@ void Inter_v2::o2_writeGoblinPos() { int16 varX, varY; int16 index; - varX = _vm->_parse->parseVarIndex(); - varY = _vm->_parse->parseVarIndex(); - index = _vm->_parse->parseValExpr(); + varX = _vm->_game->_script->readVarIndex(); + varY = _vm->_game->_script->readVarIndex(); + index = _vm->_game->_script->readValExpr(); WRITE_VAR_OFFSET(varX, _vm->_mult->_objects[index].goblinX); WRITE_VAR_OFFSET(varY, _vm->_mult->_objects[index].goblinY); } void Inter_v2::o2_stopGoblin() { - int16 index = _vm->_parse->parseValExpr(); + int16 index = _vm->_game->_script->readValExpr(); _vm->_mult->_objects[index].pAnimData->pathExistence = 4; } @@ -1236,9 +689,9 @@ void Inter_v2::o2_setGoblinState() { int16 deltaX, deltaY; int16 deltaWidth, deltaHeight; - index = _vm->_parse->parseValExpr(); - state = _vm->_parse->parseValExpr(); - type = _vm->_parse->parseValExpr(); + index = _vm->_game->_script->readValExpr(); + state = _vm->_game->_script->readValExpr(); + type = _vm->_game->_script->readValExpr(); Mult::Mult_Object &obj = _vm->_mult->_objects[index]; Mult::Mult_AnimData &objAnim = *(obj.pAnimData); @@ -1334,10 +787,10 @@ void Inter_v2::o2_placeGoblin() { int16 x, y; int16 state; - index = _vm->_parse->parseValExpr(); - x = _vm->_parse->parseValExpr(); - y = _vm->_parse->parseValExpr(); - state = _vm->_parse->parseValExpr(); + index = _vm->_game->_script->readValExpr(); + x = _vm->_game->_script->readValExpr(); + y = _vm->_game->_script->readValExpr(); + state = _vm->_game->_script->readValExpr(); _vm->_goblin->placeObject(0, 0, index, x, y, state); } @@ -1347,13 +800,13 @@ void Inter_v2::o2_initScreen() { int16 videoMode; int16 width, height; - offY = load16(); + offY = _vm->_game->_script->readInt16(); videoMode = offY & 0xFF; offY = (offY >> 8) & 0xFF; - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + width = _vm->_game->_script->readValExpr(); + height = _vm->_game->_script->readValExpr(); _vm->_video->clearScreen(); @@ -1441,16 +894,16 @@ void Inter_v2::o2_scroll() { int16 curX; int16 curY; - startX = CLIP((int) _vm->_parse->parseValExpr(), 0, + startX = CLIP((int) _vm->_game->_script->readValExpr(), 0, _vm->_video->_surfWidth - _vm->_width); - startY = CLIP((int) _vm->_parse->parseValExpr(), 0, + startY = CLIP((int) _vm->_game->_script->readValExpr(), 0, _vm->_video->_surfHeight - _vm->_height); - endX = CLIP((int) _vm->_parse->parseValExpr(), 0, + endX = CLIP((int) _vm->_game->_script->readValExpr(), 0, _vm->_video->_surfWidth - _vm->_width); - endY = CLIP((int) _vm->_parse->parseValExpr(), 0, + endY = CLIP((int) _vm->_game->_script->readValExpr(), 0, _vm->_video->_surfHeight - _vm->_height); - stepX = _vm->_parse->parseValExpr(); - stepY = _vm->_parse->parseValExpr(); + stepX = _vm->_game->_script->readValExpr(); + stepY = _vm->_game->_script->readValExpr(); curX = startX; curY = startY; @@ -1470,8 +923,8 @@ void Inter_v2::o2_scroll() { void Inter_v2::o2_setScrollOffset() { int16 offsetX, offsetY; - offsetX = _vm->_parse->parseValExpr(); - offsetY = _vm->_parse->parseValExpr(); + offsetX = _vm->_game->_script->readValExpr(); + offsetY = _vm->_game->_script->readValExpr(); if (offsetX == -1) { WRITE_VAR(2, _vm->_draw->_scrollOffsetX); @@ -1506,22 +959,22 @@ void Inter_v2::o2_playImd() { uint16 palCmd; bool close; - evalExpr(0); - _vm->_global->_inter_resStr[8] = 0; - strncpy0(imd, _vm->_global->_inter_resStr, 127); - - x = _vm->_parse->parseValExpr(); - y = _vm->_parse->parseValExpr(); - startFrame = _vm->_parse->parseValExpr(); - lastFrame = _vm->_parse->parseValExpr(); - breakKey = _vm->_parse->parseValExpr(); - flags = _vm->_parse->parseValExpr(); - palStart = _vm->_parse->parseValExpr(); - palEnd = _vm->_parse->parseValExpr(); + _vm->_game->_script->evalExpr(0); + _vm->_game->_script->getResultStr()[8] = 0; + strncpy0(imd, _vm->_game->_script->getResultStr(), 127); + + x = _vm->_game->_script->readValExpr(); + y = _vm->_game->_script->readValExpr(); + startFrame = _vm->_game->_script->readValExpr(); + lastFrame = _vm->_game->_script->readValExpr(); + breakKey = _vm->_game->_script->readValExpr(); + flags = _vm->_game->_script->readValExpr(); + palStart = _vm->_game->_script->readValExpr(); + palEnd = _vm->_game->_script->readValExpr(); palCmd = 1 << (flags & 0x3F); debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " - "paletteCmd %d (%d - %d), flags %X", _vm->_global->_inter_resStr, x, y, + "paletteCmd %d (%d - %d), flags %X", _vm->_game->_script->getResultStr(), x, y, startFrame, lastFrame, palCmd, palStart, palEnd, flags); if ((imd[0] != 0) && !_vm->_vidPlayer->primaryOpen(imd, x, y, flags)) { @@ -1550,28 +1003,28 @@ void Inter_v2::o2_getImdInfo() { int16 varFrames; int16 varWidth, varHeight; - evalExpr(0); - varX = _vm->_parse->parseVarIndex(); - varY = _vm->_parse->parseVarIndex(); - varFrames = _vm->_parse->parseVarIndex(); - varWidth = _vm->_parse->parseVarIndex(); - varHeight = _vm->_parse->parseVarIndex(); + _vm->_game->_script->evalExpr(0); + varX = _vm->_game->_script->readVarIndex(); + varY = _vm->_game->_script->readVarIndex(); + varFrames = _vm->_game->_script->readVarIndex(); + varWidth = _vm->_game->_script->readVarIndex(); + varHeight = _vm->_game->_script->readVarIndex(); // WORKAROUND: The nut rolling animation in the administration center // in Woodruff is called "noixroul", but the scripts think it's "noixroule". if ((_vm->getGameType() == kGameTypeWoodruff) && - (!scumm_stricmp(_vm->_global->_inter_resStr, "noixroule"))) - strcpy(_vm->_global->_inter_resStr, "noixroul"); + (!scumm_stricmp(_vm->_game->_script->getResultStr(), "noixroule"))) + strcpy(_vm->_game->_script->getResultStr(), "noixroul"); - _vm->_vidPlayer->writeVideoInfo(_vm->_global->_inter_resStr, varX, varY, + _vm->_vidPlayer->writeVideoInfo(_vm->_game->_script->getResultStr(), varX, varY, varFrames, varWidth, varHeight); } void Inter_v2::o2_openItk() { char fileName[32]; - evalExpr(0); - strncpy0(fileName, _vm->_global->_inter_resStr, 27); + _vm->_game->_script->evalExpr(0); + strncpy0(fileName, _vm->_game->_script->getResultStr(), 27); if (!strchr(fileName, '.')) strcat(fileName, ".ITK"); @@ -1589,49 +1042,46 @@ void Inter_v2::o2_resetImdFrontSurf() { } bool Inter_v2::o2_assign(OpFuncParams ¶ms) { - byte *savedPos; - int16 varOff; - int16 token; - int16 result; - byte loopCount; - - savedPos = _vm->_global->_inter_execPtr; - varOff = _vm->_parse->parseVarIndex(); + byte destType = _vm->_game->_script->peekByte(); + int16 dest = _vm->_game->_script->readVarIndex(); - if (*_vm->_global->_inter_execPtr == 99) { - _vm->_global->_inter_execPtr++; - loopCount = *_vm->_global->_inter_execPtr++; + byte loopCount; + if (_vm->_game->_script->peekByte() == 99) { + _vm->_game->_script->skip(1); + loopCount = _vm->_game->_script->readByte(); } else loopCount = 1; for (int i = 0; i < loopCount; i++) { - token = evalExpr(&result); - switch (savedPos[0]) { - case 16: - case 18: - WRITE_VARO_UINT8(varOff + i, _vm->_global->_inter_resVal); + int16 result; + int16 srcType = _vm->_game->_script->evalExpr(&result); + + switch (destType) { + case TYPE_VAR_INT8: + case TYPE_ARRAY_INT8: + WRITE_VARO_UINT8(dest + i, _vm->_game->_script->getResultInt()); break; - case 17: - case 27: - WRITE_VARO_UINT16(varOff + i * 2, _vm->_global->_inter_resVal); + case TYPE_VAR_INT16: + case TYPE_ARRAY_INT16: + WRITE_VARO_UINT16(dest + i * 2, _vm->_game->_script->getResultInt()); break; - case 23: - case 26: - WRITE_VAR_OFFSET(varOff + i * 4, _vm->_global->_inter_resVal); + case TYPE_VAR_INT32: + case TYPE_ARRAY_INT32: + WRITE_VAR_OFFSET(dest + i * 4, _vm->_game->_script->getResultInt()); break; - case 24: - WRITE_VARO_UINT16(varOff + i * 4, _vm->_global->_inter_resVal); + case TYPE_VAR_INT32_AS_INT16: + WRITE_VARO_UINT16(dest + i * 4, _vm->_game->_script->getResultInt()); break; - case 25: - case 28: - if (token == 20) - WRITE_VARO_UINT8(varOff, result); + case TYPE_VAR_STR: + case TYPE_ARRAY_STR: + if (srcType == TYPE_IMM_INT16) + WRITE_VARO_UINT8(dest, result); else - WRITE_VARO_STR(varOff, _vm->_global->_inter_resStr); + WRITE_VARO_STR(dest, _vm->_game->_script->getResultStr()); break; } } @@ -1643,12 +1093,12 @@ bool Inter_v2::o2_printText(OpFuncParams ¶ms) { char buf[60]; int i; - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); - _vm->_draw->_backColor = _vm->_parse->parseValExpr(); - _vm->_draw->_frontColor = _vm->_parse->parseValExpr(); - _vm->_draw->_fontIndex = _vm->_parse->parseValExpr(); + _vm->_draw->_backColor = _vm->_game->_script->readValExpr(); + _vm->_draw->_frontColor = _vm->_game->_script->readValExpr(); + _vm->_draw->_fontIndex = _vm->_game->_script->readValExpr(); _vm->_draw->_destSurface = 21; _vm->_draw->_textToPrint = buf; _vm->_draw->_transparency = 0; @@ -1659,48 +1109,47 @@ bool Inter_v2::o2_printText(OpFuncParams ¶ms) { } do { - for (i = 0; (((char) *_vm->_global->_inter_execPtr) != '.') && - (*_vm->_global->_inter_execPtr != 200); - i++, _vm->_global->_inter_execPtr++) { - buf[i] = (char) *_vm->_global->_inter_execPtr; + for (i = 0; (_vm->_game->_script->peekChar() != '.') && + (_vm->_game->_script->peekByte() != 200); i++) { + buf[i] = _vm->_game->_script->readChar(); } - if (*_vm->_global->_inter_execPtr != 200) { - _vm->_global->_inter_execPtr++; - switch (*_vm->_global->_inter_execPtr) { - case 16: - case 18: + if (_vm->_game->_script->peekByte() != 200) { + _vm->_game->_script->skip(1); + switch (_vm->_game->_script->peekByte()) { + case TYPE_VAR_INT8: + case TYPE_ARRAY_INT8: sprintf(buf + i, "%d", - (int8) READ_VARO_UINT8(_vm->_parse->parseVarIndex())); + (int8) READ_VARO_UINT8(_vm->_game->_script->readVarIndex())); break; - case 17: - case 24: - case 27: + case TYPE_VAR_INT16: + case TYPE_VAR_INT32_AS_INT16: + case TYPE_ARRAY_INT16: sprintf(buf + i, "%d", - (int16) READ_VARO_UINT16(_vm->_parse->parseVarIndex())); + (int16) READ_VARO_UINT16(_vm->_game->_script->readVarIndex())); break; - case 23: - case 26: + case TYPE_VAR_INT32: + case TYPE_ARRAY_INT32: sprintf(buf + i, "%d", - VAR_OFFSET(_vm->_parse->parseVarIndex())); + VAR_OFFSET(_vm->_game->_script->readVarIndex())); break; - case 25: - case 28: + case TYPE_VAR_STR: + case TYPE_ARRAY_STR: sprintf(buf + i, "%s", - GET_VARO_STR(_vm->_parse->parseVarIndex())); + GET_VARO_STR(_vm->_game->_script->readVarIndex())); break; } - _vm->_global->_inter_execPtr++; + _vm->_game->_script->skip(1); } else buf[i] = 0; _vm->_draw->spriteOperation(DRAW_PRINTTEXT); - } while (*_vm->_global->_inter_execPtr != 200); + } while (_vm->_game->_script->peekByte() != 200); - _vm->_global->_inter_execPtr++; + _vm->_game->_script->skip(1); return false; } @@ -1708,20 +1157,20 @@ bool Inter_v2::o2_printText(OpFuncParams ¶ms) { bool Inter_v2::o2_animPalInit(OpFuncParams ¶ms) { int16 index; - index = load16(); + index = _vm->_game->_script->readInt16(); if (index > 0) { index--; - _animPalLowIndex[index] = _vm->_parse->parseValExpr(); - _animPalHighIndex[index] = _vm->_parse->parseValExpr(); + _animPalLowIndex[index] = _vm->_game->_script->readValExpr(); + _animPalHighIndex[index] = _vm->_game->_script->readValExpr(); _animPalDir[index] = 1; } else if (index == 0) { memset(_animPalDir, 0, 8 * sizeof(int16)); - _vm->_parse->parseValExpr(); - _vm->_parse->parseValExpr(); + _vm->_game->_script->readValExpr(); + _vm->_game->_script->readValExpr(); } else { index = -index - 1; - _animPalLowIndex[index] = _vm->_parse->parseValExpr(); - _animPalHighIndex[index] = _vm->_parse->parseValExpr(); + _animPalLowIndex[index] = _vm->_game->_script->readValExpr(); + _animPalHighIndex[index] = _vm->_game->_script->readValExpr(); _animPalDir[index] = -1; } return false; @@ -1734,14 +1183,14 @@ bool Inter_v2::o2_addCollision(OpFuncParams ¶ms) { int16 key; int16 funcSub; - id = _vm->_parse->parseValExpr(); - funcSub = _vm->_global->_inter_execPtr - _vm->_game->_totFileData; - left = _vm->_parse->parseValExpr(); - top = _vm->_parse->parseValExpr(); - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); - flags = _vm->_parse->parseValExpr(); - key = load16(); + id = _vm->_game->_script->readValExpr(); + funcSub = _vm->_game->_script->pos(); + left = _vm->_game->_script->readValExpr(); + top = _vm->_game->_script->readValExpr(); + width = _vm->_game->_script->readValExpr(); + height = _vm->_game->_script->readValExpr(); + flags = _vm->_game->_script->readValExpr(); + key = _vm->_game->_script->readInt16(); if (key == 0) key = ABS(id) + 41960; @@ -1775,7 +1224,7 @@ bool Inter_v2::o2_addCollision(OpFuncParams ¶ms) { bool Inter_v2::o2_freeCollision(OpFuncParams ¶ms) { int16 id; - id = _vm->_parse->parseValExpr(); + id = _vm->_game->_script->readValExpr(); if (id == -2) { for (int i = 0; i < 150; i++) { if ((_vm->_game->_collisionAreas[i].id & 0xF000) == 0xD000) @@ -1797,9 +1246,9 @@ bool Inter_v2::o2_goblinFunc(OpFuncParams ¶ms) { // It's not yet implemented, so we fudge our way through // and pretend we've won. if (_vm->getGameType() == kGameTypeInca2) { - _vm->_global->_inter_execPtr += 4; - uint16 resVar = (uint16) load16(); - _vm->_global->_inter_execPtr += 4; + _vm->_game->_script->skip(4); + uint16 resVar = _vm->_game->_script->readUint16(); + _vm->_game->_script->skip(4); WRITE_VAR(resVar, 1); return false; @@ -1808,18 +1257,20 @@ bool Inter_v2::o2_goblinFunc(OpFuncParams ¶ms) { OpGobParams gobParams; int16 cmd; - cmd = load16(); - _vm->_global->_inter_execPtr += 2; + cmd = _vm->_game->_script->readInt16(); + + gobParams.paramCount = _vm->_game->_script->readInt16(); + gobParams.extraData = cmd; if (cmd != 101) - executeGoblinOpcode(cmd, gobParams); + executeOpcodeGob(cmd, gobParams); return false; } bool Inter_v2::o2_stopSound(OpFuncParams ¶ms) { int16 expr; - expr = _vm->_parse->parseValExpr(); + expr = _vm->_game->_script->readValExpr(); if (expr < 0) { _vm->_sound->adlibStop(); @@ -1839,13 +1290,13 @@ bool Inter_v2::o2_getFreeMem(OpFuncParams ¶ms) { int16 freeVar; int16 maxFreeVar; - freeVar = _vm->_parse->parseVarIndex(); - maxFreeVar = _vm->_parse->parseVarIndex(); + freeVar = _vm->_game->_script->readVarIndex(); + maxFreeVar = _vm->_game->_script->readVarIndex(); // HACK WRITE_VAR_OFFSET(freeVar, 1000000); WRITE_VAR_OFFSET(maxFreeVar, 1000000); - WRITE_VAR(16, READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4); + WRITE_VAR(16, _vm->_game->_script->getVariablesCount() * 4); return false; } @@ -1855,23 +1306,22 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { int32 size; SaveLoad::SaveMode mode; - evalExpr(0); - varOff = _vm->_parse->parseVarIndex(); + _vm->_game->_script->evalExpr(0); + varOff = _vm->_game->_script->readVarIndex(); size = -1; handle = 1; - mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr); + mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); if (mode == SaveLoad::kSaveModeNone) { - handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr); - if (handle >= 0) { - _vm->_dataIO->closeData(handle); - size = _vm->_dataIO->getDataSize(_vm->_global->_inter_resStr); - } else - warning("File \"%s\" not found", _vm->_global->_inter_resStr); + if (_vm->_dataIO->existData(_vm->_game->_script->getResultStr())) + size = _vm->_dataIO->getDataSize(_vm->_game->_script->getResultStr()); + else + warning("File \"%s\" not found", _vm->_game->_script->getResultStr()); + } else if (mode == SaveLoad::kSaveModeSave) - size = _vm->_saveLoad->getSize(_vm->_global->_inter_resStr); + size = _vm->_saveLoad->getSize(_vm->_game->_script->getResultStr()); else if (mode == SaveLoad::kSaveModeExists) size = 23; @@ -1879,7 +1329,7 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { handle = -1; debugC(2, kDebugFileIO, "Requested size of file \"%s\": %d", - _vm->_global->_inter_resStr, size); + _vm->_game->_script->getResultStr(), size); WRITE_VAR_OFFSET(varOff, handle); WRITE_VAR(16, (uint32) size); @@ -1896,20 +1346,20 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { byte *buf; SaveLoad::SaveMode mode; - evalExpr(0); - dataVar = _vm->_parse->parseVarIndex(); - size = _vm->_parse->parseValExpr(); - evalExpr(0); - offset = _vm->_global->_inter_resVal; + _vm->_game->_script->evalExpr(0); + dataVar = _vm->_game->_script->readVarIndex(); + size = _vm->_game->_script->readValExpr(); + _vm->_game->_script->evalExpr(0); + offset = _vm->_game->_script->getResultInt(); retSize = 0; debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)", - _vm->_global->_inter_resStr, dataVar, size, offset); + _vm->_game->_script->getResultStr(), dataVar, size, offset); - mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr); + mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); if (mode == SaveLoad::kSaveModeSave) { WRITE_VAR(1, 1); - if (_vm->_saveLoad->load(_vm->_global->_inter_resStr, dataVar, size, offset)) + if (_vm->_saveLoad->load(_vm->_game->_script->getResultStr(), dataVar, size, offset)) WRITE_VAR(1, 0); return false; } else if (mode == SaveLoad::kSaveModeIgnore) @@ -1917,22 +1367,22 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { if (size < 0) { warning("Attempted to read a raw sprite from file \"%s\"", - _vm->_global->_inter_resStr); + _vm->_game->_script->getResultStr()); return false ; } else if (size == 0) { dataVar = 0; - size = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; + size = _vm->_game->_script->getVariablesCount() * 4; } buf = _variables->getAddressOff8(dataVar); - if (_vm->_global->_inter_resStr[0] == 0) { + if (_vm->_game->_script->getResultStr()[0] == 0) { WRITE_VAR(1, size); return false; } WRITE_VAR(1, 1); - handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr); + handle = _vm->_dataIO->openData(_vm->_game->_script->getResultStr()); if (handle < 0) return false; @@ -1967,23 +1417,23 @@ bool Inter_v2::o2_writeData(OpFuncParams ¶ms) { int16 dataVar; SaveLoad::SaveMode mode; - evalExpr(0); - dataVar = _vm->_parse->parseVarIndex(); - size = _vm->_parse->parseValExpr(); - evalExpr(0); - offset = _vm->_global->_inter_resVal; + _vm->_game->_script->evalExpr(0); + dataVar = _vm->_game->_script->readVarIndex(); + size = _vm->_game->_script->readValExpr(); + _vm->_game->_script->evalExpr(0); + offset = _vm->_game->_script->getResultInt(); debugC(2, kDebugFileIO, "Write to file \"%s\" (%d, %d bytes at %d)", - _vm->_global->_inter_resStr, dataVar, size, offset); + _vm->_game->_script->getResultStr(), dataVar, size, offset); WRITE_VAR(1, 1); - mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr); + mode = _vm->_saveLoad->getSaveMode(_vm->_game->_script->getResultStr()); if (mode == SaveLoad::kSaveModeSave) { - if (_vm->_saveLoad->save(_vm->_global->_inter_resStr, dataVar, size, offset)) + if (_vm->_saveLoad->save(_vm->_game->_script->getResultStr(), dataVar, size, offset)) WRITE_VAR(1, 0); } else if (mode == SaveLoad::kSaveModeNone) - warning("Attempted to write to file \"%s\"", _vm->_global->_inter_resStr); + warning("Attempted to write to file \"%s\"", _vm->_game->_script->getResultStr()); return false; } @@ -1992,7 +1442,7 @@ void Inter_v2::o2_loadInfogramesIns(OpGobParams ¶ms) { int16 varName; char fileName[20]; - varName = load16(); + varName = _vm->_game->_script->readInt16(); strncpy0(fileName, GET_VAR_STR(varName), 15); strcat(fileName, ".INS"); @@ -2004,7 +1454,7 @@ void Inter_v2::o2_playInfogrames(OpGobParams ¶ms) { int16 varName; char fileName[20]; - varName = load16(); + varName = _vm->_game->_script->readInt16(); strncpy0(fileName, GET_VAR_STR(varName), 15); strcat(fileName, ".DUM"); @@ -2014,13 +1464,13 @@ void Inter_v2::o2_playInfogrames(OpGobParams ¶ms) { } void Inter_v2::o2_startInfogrames(OpGobParams ¶ms) { - load16(); + _vm->_game->_script->readInt16(); _vm->_sound->infogramesPlay(); } void Inter_v2::o2_stopInfogrames(OpGobParams ¶ms) { - load16(); + _vm->_game->_script->readInt16(); _vm->_sound->infogramesStop(); } @@ -2034,12 +1484,12 @@ void Inter_v2::o2_stopProtracker(OpGobParams ¶ms) { } void Inter_v2::o2_handleGoblins(OpGobParams ¶ms) { - _vm->_goblin->_gob1NoTurn = VAR(load16()) != 0; - _vm->_goblin->_gob2NoTurn = VAR(load16()) != 0; - _vm->_goblin->_gob1RelaxTimeVar = load16(); - _vm->_goblin->_gob2RelaxTimeVar = load16(); - _vm->_goblin->_gob1Busy = VAR(load16()) != 0; - _vm->_goblin->_gob2Busy = VAR(load16()) != 0; + _vm->_goblin->_gob1NoTurn = VAR(_vm->_game->_script->readInt16()) != 0; + _vm->_goblin->_gob2NoTurn = VAR(_vm->_game->_script->readInt16()) != 0; + _vm->_goblin->_gob1RelaxTimeVar = _vm->_game->_script->readInt16(); + _vm->_goblin->_gob2RelaxTimeVar = _vm->_game->_script->readInt16(); + _vm->_goblin->_gob1Busy = VAR(_vm->_game->_script->readInt16()) != 0; + _vm->_goblin->_gob2Busy = VAR(_vm->_game->_script->readInt16()) != 0; _vm->_goblin->handleGoblins(); } @@ -2050,21 +1500,20 @@ int16 Inter_v2::loadSound(int16 search) { uint16 slotIdMask; uint32 dataSize; SoundType type; - SoundSource source; type = SOUND_SND; slotIdMask = 0; dataSize = 0; if (!search) { - slot = _vm->_parse->parseValExpr(); + slot = _vm->_game->_script->readValExpr(); if (slot < 0) { type = SOUND_ADL; slot = -slot; } - id = load16(); + id = _vm->_game->_script->readInt16(); } else { - id = load16(); + id = _vm->_game->_script->readInt16(); for (slot = 0; slot < Sound::kSoundsCount; slot++) if (_vm->_sound->sampleGetBySlot(slot)->isId(id)) { @@ -2093,37 +1542,37 @@ int16 Inter_v2::loadSound(int16 search) { if (id == -1) { char sndfile[14]; - source = SOUND_FILE; - - strncpy0(sndfile, (const char *) _vm->_global->_inter_execPtr, 9); - _vm->_global->_inter_execPtr += 9; + strncpy0(sndfile, _vm->_game->_script->readString(9), 9); if (type == SOUND_ADL) strcat(sndfile, ".ADL"); else strcat(sndfile, ".SND"); - dataPtr = (byte *) _vm->_dataIO->getData(sndfile); - if (dataPtr) - dataSize = _vm->_dataIO->getDataSize(sndfile); - } else if (id >= 30000) { - source = SOUND_EXT; - - dataPtr = (byte *) _vm->_game->loadExtData(id, 0, 0, &dataSize); - } else { - int16 totSize; + dataPtr = _vm->_dataIO->getData(sndfile); + dataSize = _vm->_dataIO->getDataSize(sndfile); + if (!dataPtr) + return 0; - source = SOUND_TOT; + if (!sample->load(type, dataPtr, dataSize)) { + delete[] dataPtr; + return 0; + } - dataPtr = (byte *) _vm->_game->loadTotResource(id, &totSize); - dataSize = (uint32) ((int32) totSize); + sample->_id = id; + return slot | slotIdMask; } - if (dataPtr) { - sample->load(type, source, dataPtr, dataSize); - sample->_id = id; + Resource *resource = _vm->_game->_resources->getResource(id); + if (!resource) + return 0; + + if (!sample->load(type, resource)) { + delete resource; + return 0; } + sample->_id = id; return slot | slotIdMask; } diff --git a/engines/gob/inter_v3.cpp b/engines/gob/inter_v3.cpp index 6819b369b8..17ce7feafa 100644 --- a/engines/gob/inter_v3.cpp +++ b/engines/gob/inter_v3.cpp @@ -32,683 +32,38 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" -#include "gob/parse.h" +#include "gob/script.h" +#include "gob/resources.h" namespace Gob { -#define OPCODE(x) _OPCODE(Inter_v3, x) - -const int Inter_v3::_goblinFuncLookUp[][2] = { - {0, 0}, - {1, 1}, - {2, 2}, - {4, 3}, - {5, 4}, - {6, 5}, - {7, 6}, - {8, 7}, - {9, 8}, - {10, 9}, - {12, 10}, - {13, 11}, - {14, 12}, - {15, 13}, - {16, 14}, - {21, 15}, - {22, 16}, - {23, 17}, - {24, 18}, - {25, 19}, - {26, 20}, - {27, 21}, - {28, 22}, - {29, 23}, - {30, 24}, - {32, 25}, - {33, 26}, - {34, 27}, - {35, 28}, - {36, 29}, - {37, 30}, - {40, 31}, - {41, 32}, - {42, 33}, - {43, 34}, - {44, 35}, - {50, 36}, - {52, 37}, - {53, 38}, - {100, 39}, - {152, 40}, - {200, 41}, - {201, 42}, - {202, 43}, - {203, 44}, - {204, 45}, - {250, 46}, - {251, 47}, - {252, 48}, - {500, 49}, - {502, 50}, - {503, 51}, - {600, 52}, - {601, 53}, - {602, 54}, - {603, 55}, - {604, 56}, - {605, 57}, - {1000, 58}, - {1001, 59}, - {1002, 60}, - {1003, 61}, - {1004, 62}, - {1005, 63}, - {1006, 64}, - {1008, 65}, - {1009, 66}, - {1010, 67}, - {1011, 68}, - {1015, 69}, - {2005, 70} -}; +#define OPCODEVER Inter_v3 +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) Inter_v3::Inter_v3(GobEngine *vm) : Inter_v2(vm) { - setupOpcodes(); } -void Inter_v3::setupOpcodes() { - static const OpcodeDrawEntryV3 opcodesDraw[256] = { - /* 00 */ - OPCODE(o1_loadMult), - OPCODE(o2_playMult), - OPCODE(o2_freeMultKeys), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o1_initCursor), - /* 08 */ - OPCODE(o1_initCursorAnim), - OPCODE(o1_clearCursorAnim), - OPCODE(o2_setRenderFlags), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - OPCODE(o1_loadAnim), - OPCODE(o1_freeAnim), - OPCODE(o1_updateAnim), - OPCODE(o2_multSub), - /* 14 */ - OPCODE(o2_initMult), - OPCODE(o1_freeMult), - OPCODE(o1_animate), - OPCODE(o2_loadMultObject), - /* 18 */ - OPCODE(o1_getAnimLayerInfo), - OPCODE(o1_getObjAnimSize), - OPCODE(o1_loadStatic), - OPCODE(o1_freeStatic), - /* 1C */ - OPCODE(o2_renderStatic), - OPCODE(o2_loadCurLayer), - {0, ""}, - {0, ""}, - /* 20 */ - OPCODE(o2_playCDTrack), - OPCODE(o2_waitCDTrackEnd), - OPCODE(o2_stopCD), - OPCODE(o2_readLIC), - /* 24 */ - OPCODE(o2_freeLIC), - OPCODE(o2_getCDTrackPos), - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o2_loadFontToSprite), - OPCODE(o1_freeFontToSprite), - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - OPCODE(o2_totSub), - OPCODE(o2_switchTotSub), - OPCODE(o2_pushVars), - OPCODE(o2_popVars), - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 48 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 4C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 50 */ - OPCODE(o2_loadMapObjects), - OPCODE(o2_freeGoblins), - OPCODE(o2_moveGoblin), - OPCODE(o2_writeGoblinPos), - /* 54 */ - OPCODE(o2_stopGoblin), - OPCODE(o2_setGoblinState), - OPCODE(o2_placeGoblin), - {0, ""}, - /* 58 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 5C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 60 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 64 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 68 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 6C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 70 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 74 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 78 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 7C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 80 */ - OPCODE(o2_initScreen), - OPCODE(o2_scroll), - OPCODE(o2_setScrollOffset), - OPCODE(o2_playImd), - /* 84 */ - OPCODE(o2_getImdInfo), - OPCODE(o2_openItk), - OPCODE(o2_closeItk), - OPCODE(o2_setImdFrontSurf), - /* 88 */ - OPCODE(o2_resetImdFrontSurf), - {0, ""}, - {0, ""}, - {0, ""}, - /* 8C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 90 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 94 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 98 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 9C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* AC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* BC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* CC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* DC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* EC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* FC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""} - }; - - static const OpcodeFuncEntryV3 opcodesFunc[80] = { - /* 00 */ - OPCODE(o1_callSub), - OPCODE(o1_callSub), - OPCODE(o1_printTotText), - OPCODE(o1_loadCursor), - /* 04 */ - {0, ""}, - OPCODE(o1_switch), - OPCODE(o1_repeatUntil), - OPCODE(o1_whileDo), - /* 08 */ - OPCODE(o1_if), - OPCODE(o2_assign), - OPCODE(o1_loadSpriteToPos), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - OPCODE(o2_printText), - OPCODE(o1_loadTot), - OPCODE(o1_palLoad), - /* 14 */ - OPCODE(o1_keyFunc), - OPCODE(o1_capturePush), - OPCODE(o1_capturePop), - OPCODE(o2_animPalInit), - /* 18 */ - OPCODE(o2_addCollision), - OPCODE(o2_freeCollision), - OPCODE(o3_getTotTextItemPart), - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - OPCODE(o1_drawOperations), - OPCODE(o1_setcmdCount), - /* 20 */ - OPCODE(o1_return), - OPCODE(o1_renewTimeInVars), - OPCODE(o1_speakerOn), - OPCODE(o1_speakerOff), - /* 24 */ - OPCODE(o1_putPixel), - OPCODE(o2_goblinFunc), - OPCODE(o1_createSprite), - OPCODE(o1_freeSprite), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_returnTo), - OPCODE(o1_loadSpriteContent), - OPCODE(o3_copySprite), - OPCODE(o1_fillRect), - /* 34 */ - OPCODE(o1_drawLine), - OPCODE(o1_strToLong), - OPCODE(o1_invalidate), - OPCODE(o1_setBackDelta), - /* 38 */ - OPCODE(o1_playSound), - OPCODE(o2_stopSound), - OPCODE(o2_loadSound), - OPCODE(o1_freeSoundSlot), - /* 3C */ - OPCODE(o1_waitEndPlay), - OPCODE(o1_playComposition), - OPCODE(o2_getFreeMem), - OPCODE(o2_checkData), - /* 40 */ - {0, ""}, - OPCODE(o1_prepareStr), - OPCODE(o1_insertStr), - OPCODE(o1_cutStr), - /* 44 */ - OPCODE(o1_strstr), - OPCODE(o1_istrlen), - OPCODE(o1_setMousePos), - OPCODE(o1_setFrameRate), - /* 48 */ - OPCODE(o1_animatePalette), - OPCODE(o1_animateCursor), - OPCODE(o1_blitCursor), - OPCODE(o1_loadFont), - /* 4C */ - OPCODE(o1_freeFont), - OPCODE(o2_readData), - OPCODE(o2_writeData), - OPCODE(o1_manageDataFile), - }; - - static const OpcodeGoblinEntryV3 opcodesGoblin[71] = { - /* 00 */ - OPCODE(o2_loadInfogramesIns), - OPCODE(o2_startInfogrames), - OPCODE(o2_stopInfogrames), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 08 */ - {0, ""}, - OPCODE(o2_playInfogrames), - {0, ""}, - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 14 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 18 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 20 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 24 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o3_wobble), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - }; - - _opcodesDrawV3 = opcodesDraw; - _opcodesFuncV3 = opcodesFunc; - _opcodesGoblinV3 = opcodesGoblin; +void Inter_v3::setupOpcodesDraw() { + Inter_v2::setupOpcodesDraw(); } -void Inter_v3::executeDrawOpcode(byte i) { - debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); +void Inter_v3::setupOpcodesFunc() { + Inter_v2::setupOpcodesFunc(); - OpcodeDrawProcV3 op = _opcodesDrawV3[i].proc; - - if (op == 0) - warning("unimplemented opcodeDraw: %d", i); - else - (this->*op) (); -} - -bool Inter_v3::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s)", - i, j, i, j, getOpcodeFuncDesc(i, j)); - - if ((i > 4) || (j > 15)) { - warning("unimplemented opcodeFunc: %d.%d", i, j); - return false; - } - - OpcodeFuncProcV3 op = _opcodesFuncV3[i*16 + j].proc; - - if (op == 0) - warning("unimplemented opcodeFunc: %d.%d", i, j); - else - return (this->*op) (params); - - return false; -} - -void Inter_v3::executeGoblinOpcode(int i, OpGobParams ¶ms) { - debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); - - OpcodeGoblinProcV3 op = 0; - - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) { - op = _opcodesGoblinV3[_goblinFuncLookUp[j][1]].proc; - break; - } - - if (op == 0) { - int16 val; - - _vm->_global->_inter_execPtr -= 2; - val = load16(); - _vm->_global->_inter_execPtr += val << 1; - } else - (this->*op) (params); + OPCODEFUNC(0x1A, o3_getTotTextItemPart); + OPCODEFUNC(0x32, o3_copySprite); } -const char *Inter_v3::getOpcodeDrawDesc(byte i) { - return _opcodesDrawV3[i].desc; -} +void Inter_v3::setupOpcodesGob() { + OPCODEGOB( 0, o2_loadInfogramesIns); + OPCODEGOB( 1, o2_startInfogrames); + OPCODEGOB( 2, o2_stopInfogrames); -const char *Inter_v3::getOpcodeFuncDesc(byte i, byte j) { - if ((i > 4) || (j > 15)) - return ""; + OPCODEGOB( 10, o2_playInfogrames); - return _opcodesFuncV3[i*16 + j].desc; -} - -const char *Inter_v3::getOpcodeGoblinDesc(int i) { - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) - return _opcodesGoblinV3[_goblinFuncLookUp[j][1]].desc; - return ""; + OPCODEGOB(100, o3_wobble); } bool Inter_v3::o3_getTotTextItemPart(OpFuncParams ¶ms) { @@ -720,18 +75,18 @@ bool Inter_v3::o3_getTotTextItemPart(OpFuncParams ¶ms) { uint32 stringStartVar, stringVar; bool end; - totTextItem = load16(); - stringStartVar = _vm->_parse->parseVarIndex(); - part = _vm->_parse->parseValExpr(); + totTextItem = _vm->_game->_script->readInt16(); + stringStartVar = _vm->_game->_script->readVarIndex(); + part = _vm->_game->_script->readValExpr(); stringVar = stringStartVar; WRITE_VARO_UINT8(stringVar, 0); - if (!_vm->_game->_totTextData) + TextItem *textItem = _vm->_game->_resources->getTextItem(totTextItem); + if (!textItem) return false; - totData = _vm->_game->_totTextData->dataPtr + - _vm->_game->_totTextData->items[totTextItem].offset; + totData = textItem->getData(); // Skip background rectangles while (((int16) READ_LE_UINT16(totData)) != -1) @@ -782,6 +137,7 @@ bool Inter_v3::o3_getTotTextItemPart(OpFuncParams ¶ms) { if ((n != 0) || (*totData == 1) || (*totData == 6) || (*totData == 7)) { WRITE_VARO_UINT8(stringVar, 0); + delete textItem; return false; } @@ -813,8 +169,9 @@ bool Inter_v3::o3_getTotTextItemPart(OpFuncParams ¶ms) { WRITE_VARO_UINT16(stringVar, offX); WRITE_VARO_UINT16(stringVar + 2, offY); WRITE_VARO_UINT16(stringVar + 4, - totData - _vm->_game->_totTextData->dataPtr); + totData - _vm->_game->_resources->getTexts()); WRITE_VARO_UINT8(stringVar + 6, 0); + delete textItem; return false; } @@ -860,8 +217,10 @@ bool Inter_v3::o3_getTotTextItemPart(OpFuncParams ¶ms) { if (((*totData != 2) && (*totData != 5)) || (ABS(offY - READ_LE_UINT16(totData + 3)) > 1)) { - if (curPart == part) + if (curPart == part) { + delete textItem; return false; + } stringVar = stringStartVar; WRITE_VARO_UINT8(stringVar, 0); @@ -881,6 +240,7 @@ bool Inter_v3::o3_getTotTextItemPart(OpFuncParams ¶ms) { } } + delete textItem; return false; } diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp index 6ab55d70af..48378a5987 100644 --- a/engines/gob/inter_v4.cpp +++ b/engines/gob/inter_v4.cpp @@ -32,689 +32,32 @@ #include "gob/global.h" #include "gob/draw.h" #include "gob/game.h" -#include "gob/parse.h" +#include "gob/script.h" #include "gob/videoplayer.h" #include "gob/sound/sound.h" namespace Gob { -#define OPCODE(x) _OPCODE(Inter_v4, x) - -const int Inter_v4::_goblinFuncLookUp[][2] = { - {0, 0}, - {1, 1}, - {2, 2}, - {4, 3}, - {5, 4}, - {6, 5}, - {7, 6}, - {8, 7}, - {9, 8}, - {10, 9}, - {12, 10}, - {13, 11}, - {14, 12}, - {15, 13}, - {16, 14}, - {21, 15}, - {22, 16}, - {23, 17}, - {24, 18}, - {25, 19}, - {26, 20}, - {27, 21}, - {28, 22}, - {29, 23}, - {30, 24}, - {32, 25}, - {33, 26}, - {34, 27}, - {35, 28}, - {36, 29}, - {37, 30}, - {40, 31}, - {41, 32}, - {42, 33}, - {43, 34}, - {44, 35}, - {50, 36}, - {52, 37}, - {53, 38}, - {100, 39}, - {152, 40}, - {200, 41}, - {201, 42}, - {202, 43}, - {203, 44}, - {204, 45}, - {250, 46}, - {251, 47}, - {252, 48}, - {500, 49}, - {502, 50}, - {503, 51}, - {600, 52}, - {601, 53}, - {602, 54}, - {603, 55}, - {604, 56}, - {605, 57}, - {1000, 58}, - {1001, 59}, - {1002, 60}, - {1003, 61}, - {1004, 62}, - {1005, 63}, - {1006, 64}, - {1008, 65}, - {1009, 66}, - {1010, 67}, - {1011, 68}, - {1015, 69}, - {2005, 70} -}; +#define OPCODEVER Inter_v4 +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) Inter_v4::Inter_v4(GobEngine *vm) : Inter_v3(vm) { - setupOpcodes(); } -void Inter_v4::setupOpcodes() { - static const OpcodeDrawEntryV4 opcodesDraw[256] = { - /* 00 */ - OPCODE(o1_loadMult), - OPCODE(o2_playMult), - OPCODE(o2_freeMultKeys), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o1_initCursor), - /* 08 */ - OPCODE(o1_initCursorAnim), - OPCODE(o1_clearCursorAnim), - OPCODE(o2_setRenderFlags), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - OPCODE(o1_loadAnim), - OPCODE(o1_freeAnim), - OPCODE(o1_updateAnim), - OPCODE(o2_multSub), - /* 14 */ - OPCODE(o2_initMult), - OPCODE(o1_freeMult), - OPCODE(o1_animate), - OPCODE(o2_loadMultObject), - /* 18 */ - OPCODE(o1_getAnimLayerInfo), - OPCODE(o1_getObjAnimSize), - OPCODE(o1_loadStatic), - OPCODE(o1_freeStatic), - /* 1C */ - OPCODE(o2_renderStatic), - OPCODE(o2_loadCurLayer), - {0, ""}, - {0, ""}, - /* 20 */ - OPCODE(o2_playCDTrack), - OPCODE(o2_waitCDTrackEnd), - OPCODE(o2_stopCD), - OPCODE(o2_readLIC), - /* 24 */ - OPCODE(o2_freeLIC), - OPCODE(o2_getCDTrackPos), - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o2_loadFontToSprite), - OPCODE(o1_freeFontToSprite), - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - OPCODE(o2_totSub), - OPCODE(o2_switchTotSub), - OPCODE(o2_pushVars), - OPCODE(o2_popVars), - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 48 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 4C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 50 */ - OPCODE(o2_loadMapObjects), - OPCODE(o2_freeGoblins), - OPCODE(o2_moveGoblin), - OPCODE(o2_writeGoblinPos), - /* 54 */ - OPCODE(o2_stopGoblin), - OPCODE(o2_setGoblinState), - OPCODE(o2_placeGoblin), - {0, ""}, - /* 58 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 5C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 60 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 64 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 68 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 6C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 70 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 74 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 78 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 7C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 80 */ - OPCODE(o4_initScreen), - OPCODE(o2_scroll), - OPCODE(o2_setScrollOffset), - OPCODE(o4_playVmdOrMusic), - /* 84 */ - OPCODE(o2_getImdInfo), - OPCODE(o2_openItk), - OPCODE(o2_closeItk), - OPCODE(o2_setImdFrontSurf), - /* 88 */ - OPCODE(o2_resetImdFrontSurf), - {0, ""}, - {0, ""}, - {0, ""}, - /* 8C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 90 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 94 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 98 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 9C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* AC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* BC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* CC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* DC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* EC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* FC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""} - }; - - static const OpcodeFuncEntryV4 opcodesFunc[80] = { - /* 00 */ - OPCODE(o1_callSub), - OPCODE(o1_callSub), - OPCODE(o1_printTotText), - OPCODE(o1_loadCursor), - /* 04 */ - {0, ""}, - OPCODE(o1_switch), - OPCODE(o1_repeatUntil), - OPCODE(o1_whileDo), - /* 08 */ - OPCODE(o1_if), - OPCODE(o2_assign), - OPCODE(o1_loadSpriteToPos), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - OPCODE(o2_printText), - OPCODE(o1_loadTot), - OPCODE(o1_palLoad), - /* 14 */ - OPCODE(o1_keyFunc), - OPCODE(o1_capturePush), - OPCODE(o1_capturePop), - OPCODE(o2_animPalInit), - /* 18 */ - OPCODE(o2_addCollision), - OPCODE(o2_freeCollision), - OPCODE(o3_getTotTextItemPart), - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - OPCODE(o1_drawOperations), - OPCODE(o1_setcmdCount), - /* 20 */ - OPCODE(o1_return), - OPCODE(o1_renewTimeInVars), - OPCODE(o1_speakerOn), - OPCODE(o1_speakerOff), - /* 24 */ - OPCODE(o1_putPixel), - OPCODE(o2_goblinFunc), - OPCODE(o1_createSprite), - OPCODE(o1_freeSprite), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_returnTo), - OPCODE(o1_loadSpriteContent), - OPCODE(o1_copySprite), - OPCODE(o1_fillRect), - /* 34 */ - OPCODE(o1_drawLine), - OPCODE(o1_strToLong), - OPCODE(o1_invalidate), - OPCODE(o1_setBackDelta), - /* 38 */ - OPCODE(o1_playSound), - OPCODE(o2_stopSound), - OPCODE(o2_loadSound), - OPCODE(o1_freeSoundSlot), - /* 3C */ - OPCODE(o1_waitEndPlay), - OPCODE(o1_playComposition), - OPCODE(o2_getFreeMem), - OPCODE(o2_checkData), - /* 40 */ - {0, ""}, - OPCODE(o1_prepareStr), - OPCODE(o1_insertStr), - OPCODE(o1_cutStr), - /* 44 */ - OPCODE(o1_strstr), - OPCODE(o1_istrlen), - OPCODE(o1_setMousePos), - OPCODE(o1_setFrameRate), - /* 48 */ - OPCODE(o1_animatePalette), - OPCODE(o1_animateCursor), - OPCODE(o1_blitCursor), - OPCODE(o1_loadFont), - /* 4C */ - OPCODE(o1_freeFont), - OPCODE(o2_readData), - OPCODE(o2_writeData), - OPCODE(o1_manageDataFile), - }; - - static const OpcodeGoblinEntryV4 opcodesGoblin[71] = { - /* 00 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 08 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 14 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 18 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 20 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 24 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - }; - - _opcodesDrawV4 = opcodesDraw; - _opcodesFuncV4 = opcodesFunc; - _opcodesGoblinV4 = opcodesGoblin; -} - -void Inter_v4::executeDrawOpcode(byte i) { - debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); - - OpcodeDrawProcV4 op = _opcodesDrawV4[i].proc; - - if (op == 0) - warning("unimplemented opcodeDraw: %d", i); - else - (this->*op) (); -} - -bool Inter_v4::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d", - i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile, - (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData), - (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4)); - - if ((i > 4) || (j > 15)) { - warning("unimplemented opcodeFunc: %d.%d", i, j); - return false; - } - - OpcodeFuncProcV4 op = _opcodesFuncV4[i*16 + j].proc; - - if (op == 0) - warning("unimplemented opcodeFunc: %d.%d", i, j); - else - return (this->*op) (params); +void Inter_v4::setupOpcodesDraw() { + Inter_v3::setupOpcodesDraw(); - return false; + OPCODEDRAW(0x80, o4_initScreen); + OPCODEDRAW(0x83, o4_playVmdOrMusic); } -void Inter_v4::executeGoblinOpcode(int i, OpGobParams ¶ms) { - debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); - - OpcodeGoblinProcV4 op = 0; - - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) { - op = _opcodesGoblinV4[_goblinFuncLookUp[j][1]].proc; - break; - } - - if (op == 0) { - warning("unimplemented opcodeGoblin: %d", i); - - int16 val; - - _vm->_global->_inter_execPtr -= 2; - val = load16(); - _vm->_global->_inter_execPtr += val << 1; - } else - (this->*op) (params); -} - -const char *Inter_v4::getOpcodeDrawDesc(byte i) { - return _opcodesDrawV4[i].desc; -} - -const char *Inter_v4::getOpcodeFuncDesc(byte i, byte j) { - if ((i > 4) || (j > 15)) - return ""; - - return _opcodesFuncV4[i*16 + j].desc; +void Inter_v4::setupOpcodesFunc() { + Inter_v3::setupOpcodesFunc(); } -const char *Inter_v4::getOpcodeGoblinDesc(int i) { - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) - return _opcodesGoblinV4[_goblinFuncLookUp[j][1]].desc; - return ""; +void Inter_v4::setupOpcodesGob() { } void Inter_v4::o4_initScreen() { @@ -722,13 +65,13 @@ void Inter_v4::o4_initScreen() { int16 videoMode; int16 width, height; - offY = load16(); + offY = _vm->_game->_script->readInt16(); videoMode = offY & 0xFF; offY = (offY >> 8) & 0xFF; - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + width = _vm->_game->_script->readValExpr(); + height = _vm->_game->_script->readValExpr(); _vm->_video->clearScreen(); @@ -809,8 +152,8 @@ void Inter_v4::o4_playVmdOrMusic() { uint16 palCmd; bool close; - evalExpr(0); - strncpy0(fileName, _vm->_global->_inter_resStr, 127); + _vm->_game->_script->evalExpr(0); + strncpy0(fileName, _vm->_game->_script->getResultStr(), 127); // WORKAROUND: The nut rolling animation in the administration center // in Woodruff is called "noixroul", but the scripts think it's "noixroule". @@ -818,14 +161,14 @@ void Inter_v4::o4_playVmdOrMusic() { (!scumm_stricmp(fileName, "noixroule"))) strcpy(fileName, "noixroul"); - x = _vm->_parse->parseValExpr(); - y = _vm->_parse->parseValExpr(); - startFrame = _vm->_parse->parseValExpr(); - lastFrame = _vm->_parse->parseValExpr(); - breakKey = _vm->_parse->parseValExpr(); - flags = _vm->_parse->parseValExpr(); - palStart = _vm->_parse->parseValExpr(); - palEnd = _vm->_parse->parseValExpr(); + x = _vm->_game->_script->readValExpr(); + y = _vm->_game->_script->readValExpr(); + startFrame = _vm->_game->_script->readValExpr(); + lastFrame = _vm->_game->_script->readValExpr(); + breakKey = _vm->_game->_script->readValExpr(); + flags = _vm->_game->_script->readValExpr(); + palStart = _vm->_game->_script->readValExpr(); + palEnd = _vm->_game->_script->readValExpr(); palCmd = 1 << (flags & 0x3F); debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " diff --git a/engines/gob/inter_v5.cpp b/engines/gob/inter_v5.cpp index cb5b28cb67..1c20851c8d 100644 --- a/engines/gob/inter_v5.cpp +++ b/engines/gob/inter_v5.cpp @@ -30,652 +30,73 @@ #include "gob/inter.h" #include "gob/global.h" #include "gob/game.h" -#include "gob/parse.h" +#include "gob/script.h" #include "gob/draw.h" namespace Gob { -#define OPCODE(x) _OPCODE(Inter_v5, x) - -const int Inter_v5::_goblinFuncLookUp[][2] = { - {0, 0}, - {1, 0}, - {3, 0}, - {2, 0}, - {33, 0}, - {80, 1}, - {81, 2}, - {82, 3}, - {83, 4}, - {84, 5}, - {85, 6}, - {86, 7}, - {87, 0}, - {88, 0}, - {89, 0}, - {90, 0}, - {91, 0}, - {92, 8}, - {93, 0}, - {94, 0}, - {95, 9}, - {96, 10}, - {97, 11}, - {98, 12}, - {99, 0}, - {100, 13}, - {200, 14} -}; +#define OPCODEVER Inter_v5 +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) Inter_v5::Inter_v5(GobEngine *vm) : Inter_v4(vm) { - setupOpcodes(); } -void Inter_v5::setupOpcodes() { - static const OpcodeDrawEntryV5 opcodesDraw[256] = { - /* 00 */ - OPCODE(o1_loadMult), - OPCODE(o2_playMult), - OPCODE(o2_freeMultKeys), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o1_initCursor), - /* 08 */ - OPCODE(o1_initCursorAnim), - OPCODE(o1_clearCursorAnim), - OPCODE(o2_setRenderFlags), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - OPCODE(o1_loadAnim), - OPCODE(o1_freeAnim), - OPCODE(o1_updateAnim), - OPCODE(o2_multSub), - /* 14 */ - OPCODE(o2_initMult), - OPCODE(o1_freeMult), - OPCODE(o1_animate), - OPCODE(o2_loadMultObject), - /* 18 */ - OPCODE(o1_getAnimLayerInfo), - OPCODE(o1_getObjAnimSize), - OPCODE(o1_loadStatic), - OPCODE(o1_freeStatic), - /* 1C */ - OPCODE(o2_renderStatic), - OPCODE(o2_loadCurLayer), - {0, ""}, - {0, ""}, - /* 20 */ - OPCODE(o2_playCDTrack), - OPCODE(o2_waitCDTrackEnd), - OPCODE(o2_stopCD), - OPCODE(o2_readLIC), - /* 24 */ - OPCODE(o2_freeLIC), - OPCODE(o2_getCDTrackPos), - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o2_loadFontToSprite), - OPCODE(o1_freeFontToSprite), - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - OPCODE(o2_totSub), - OPCODE(o2_switchTotSub), - OPCODE(o2_pushVars), - OPCODE(o2_popVars), - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 48 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 4C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 50 */ - OPCODE(o2_loadMapObjects), - OPCODE(o2_freeGoblins), - OPCODE(o2_moveGoblin), - OPCODE(o2_writeGoblinPos), - /* 54 */ - OPCODE(o2_stopGoblin), - OPCODE(o2_setGoblinState), - OPCODE(o2_placeGoblin), - {0, ""}, - /* 58 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 5C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 60 */ - {0, ""}, - OPCODE(o5_deleteFile), - {0, ""}, - {0, ""}, - /* 64 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 68 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 6C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 70 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 74 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 78 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 7C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 80 */ - OPCODE(o5_initScreen), - OPCODE(o2_scroll), - OPCODE(o2_setScrollOffset), - OPCODE(o4_playVmdOrMusic), - /* 84 */ - OPCODE(o2_getImdInfo), - OPCODE(o2_openItk), - OPCODE(o2_closeItk), - OPCODE(o2_setImdFrontSurf), - /* 88 */ - OPCODE(o2_resetImdFrontSurf), - {0, ""}, - {0, ""}, - {0, ""}, - /* 8C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 90 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 94 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 98 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 9C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* AC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* BC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* CC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* DC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* EC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* FC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""} - }; - - static const OpcodeFuncEntryV5 opcodesFunc[80] = { - /* 00 */ - OPCODE(o1_callSub), - OPCODE(o1_callSub), - OPCODE(o1_printTotText), - OPCODE(o1_loadCursor), - /* 04 */ - {0, ""}, - OPCODE(o1_switch), - OPCODE(o1_repeatUntil), - OPCODE(o1_whileDo), - /* 08 */ - OPCODE(o1_if), - OPCODE(o2_assign), - OPCODE(o1_loadSpriteToPos), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - OPCODE(o2_printText), - OPCODE(o1_loadTot), - OPCODE(o1_palLoad), - /* 14 */ - OPCODE(o1_keyFunc), - OPCODE(o1_capturePush), - OPCODE(o1_capturePop), - OPCODE(o2_animPalInit), - /* 18 */ - OPCODE(o2_addCollision), - OPCODE(o2_freeCollision), - OPCODE(o3_getTotTextItemPart), - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - OPCODE(o1_drawOperations), - OPCODE(o1_setcmdCount), - /* 20 */ - OPCODE(o1_return), - OPCODE(o1_renewTimeInVars), - OPCODE(o1_speakerOn), - OPCODE(o1_speakerOff), - /* 24 */ - OPCODE(o1_putPixel), - OPCODE(o2_goblinFunc), - OPCODE(o1_createSprite), - OPCODE(o1_freeSprite), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_returnTo), - OPCODE(o1_loadSpriteContent), - OPCODE(o1_copySprite), - OPCODE(o1_fillRect), - /* 34 */ - OPCODE(o1_drawLine), - OPCODE(o1_strToLong), - OPCODE(o1_invalidate), - OPCODE(o1_setBackDelta), - /* 38 */ - OPCODE(o1_playSound), - OPCODE(o2_stopSound), - OPCODE(o2_loadSound), - OPCODE(o1_freeSoundSlot), - /* 3C */ - OPCODE(o1_waitEndPlay), - OPCODE(o1_playComposition), - OPCODE(o2_getFreeMem), - OPCODE(o2_checkData), - /* 40 */ - {0, ""}, - OPCODE(o1_prepareStr), - OPCODE(o1_insertStr), - OPCODE(o1_cutStr), - /* 44 */ - OPCODE(o1_strstr), - OPCODE(o5_istrlen), - OPCODE(o1_setMousePos), - OPCODE(o1_setFrameRate), - /* 48 */ - OPCODE(o1_animatePalette), - OPCODE(o1_animateCursor), - OPCODE(o1_blitCursor), - OPCODE(o1_loadFont), - /* 4C */ - OPCODE(o1_freeFont), - OPCODE(o2_readData), - OPCODE(o2_writeData), - OPCODE(o1_manageDataFile), - }; - - static const OpcodeGoblinEntryV5 opcodesGoblin[71] = { - /* 00 */ - OPCODE(o5_spaceShooter), - OPCODE(o5_getSystemCDSpeed), - OPCODE(o5_getSystemRAM), - OPCODE(o5_getSystemCPUSpeed), - /* 04 */ - OPCODE(o5_getSystemDrawSpeed), - OPCODE(o5_totalSystemSpecs), - OPCODE(o5_saveSystemSpecs), - OPCODE(o5_loadSystemSpecs), - /* 08 */ - OPCODE(o5_gob92), - OPCODE(o5_gob95), - OPCODE(o5_gob96), - OPCODE(o5_gob97), - /* 0C */ - OPCODE(o5_gob98), - OPCODE(o5_gob100), - OPCODE(o5_gob200), - {0, ""}, - /* 10 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 14 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 18 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 20 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 24 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - }; - - _opcodesDrawV5 = opcodesDraw; - _opcodesFuncV5 = opcodesFunc; - _opcodesGoblinV5 = opcodesGoblin; -} - -void Inter_v5::executeDrawOpcode(byte i) { - debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); - - OpcodeDrawProcV5 op = _opcodesDrawV5[i].proc; +void Inter_v5::setupOpcodesDraw() { + Inter_v4::setupOpcodesDraw(); - if (op == 0) - warning("unimplemented opcodeDraw: %d", i); - else - (this->*op) (); + OPCODEDRAW(0x61, o5_deleteFile); + OPCODEDRAW(0x80, o5_initScreen); } -bool Inter_v5::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d", - i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile, - (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData), - (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4)); - - if ((i > 4) || (j > 15)) { - warning("unimplemented opcodeFunc: %d.%d", i, j); - return false; - } +void Inter_v5::setupOpcodesFunc() { + Inter_v4::setupOpcodesFunc(); - OpcodeFuncProcV5 op = _opcodesFuncV5[i*16 + j].proc; - - if (op == 0) - warning("unimplemented opcodeFunc: %d.%d", i, j); - else - return (this->*op) (params); - - return false; -} - -void Inter_v5::executeGoblinOpcode(int i, OpGobParams ¶ms) { - debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); - - OpcodeGoblinProcV5 op = 0; - - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) { - op = _opcodesGoblinV5[_goblinFuncLookUp[j][1]].proc; - break; - } - - _vm->_global->_inter_execPtr -= 2; - - if (op == 0) { - warning("unimplemented opcodeGoblin: %d", i); - - int16 paramCount = load16(); - _vm->_global->_inter_execPtr += paramCount * 2; - } else { - params.extraData = i; - - (this->*op) (params); - } + OPCODEFUNC(0x45, o5_istrlen); } -const char *Inter_v5::getOpcodeDrawDesc(byte i) { - return _opcodesDrawV5[i].desc; -} - -const char *Inter_v5::getOpcodeFuncDesc(byte i, byte j) { - if ((i > 4) || (j > 15)) - return ""; - - return _opcodesFuncV5[i*16 + j].desc; -} - -const char *Inter_v5::getOpcodeGoblinDesc(int i) { - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) - return _opcodesGoblinV5[_goblinFuncLookUp[j][1]].desc; - return ""; +void Inter_v5::setupOpcodesGob() { + OPCODEGOB( 0, o5_spaceShooter); + OPCODEGOB( 1, o5_spaceShooter); + OPCODEGOB( 2, o5_spaceShooter); + OPCODEGOB( 3, o5_spaceShooter); + + OPCODEGOB( 33, o5_spaceShooter); + + OPCODEGOB( 80, o5_getSystemCDSpeed); + OPCODEGOB( 81, o5_getSystemRAM); + OPCODEGOB( 82, o5_getSystemCPUSpeed); + OPCODEGOB( 83, o5_getSystemDrawSpeed); + OPCODEGOB( 84, o5_totalSystemSpecs); + + OPCODEGOB( 85, o5_saveSystemSpecs); + OPCODEGOB( 86, o5_loadSystemSpecs); + + OPCODEGOB( 87, o5_spaceShooter); + OPCODEGOB( 88, o5_spaceShooter); + OPCODEGOB( 89, o5_spaceShooter); + OPCODEGOB( 90, o5_spaceShooter); + + OPCODEGOB( 91, o5_spaceShooter); + OPCODEGOB( 92, o5_gob92); + OPCODEGOB( 93, o5_spaceShooter); + OPCODEGOB( 94, o5_spaceShooter); + + OPCODEGOB( 95, o5_gob95); + OPCODEGOB( 96, o5_gob96); + OPCODEGOB( 97, o5_gob97); + OPCODEGOB( 98, o5_gob98); + + OPCODEGOB( 99, o5_spaceShooter); + OPCODEGOB(100, o5_gob100); + OPCODEGOB(200, o5_gob200); } void Inter_v5::o5_deleteFile() { - evalExpr(0); + _vm->_game->_script->evalExpr(0); - warning("Dynasty Stub: deleteFile \"%s\"", _vm->_global->_inter_resStr); + warning("Dynasty Stub: deleteFile \"%s\"", _vm->_game->_script->getResultStr()); } void Inter_v5::o5_initScreen() { @@ -683,13 +104,13 @@ void Inter_v5::o5_initScreen() { int16 videoMode; int16 width, height; - offY = load16(); + offY = _vm->_game->_script->readInt16(); videoMode = offY & 0xFF; offY = (offY >> 8) & 0xFF; - width = _vm->_parse->parseValExpr(); - height = _vm->_parse->parseValExpr(); + width = _vm->_game->_script->readValExpr(); + height = _vm->_game->_script->readValExpr(); warning("initScreen: %d, %d, %d, %d", width, height, offY, videoMode); @@ -784,18 +205,18 @@ bool Inter_v5::o5_istrlen(OpFuncParams ¶ms) { int16 len; uint16 type; - if (*_vm->_global->_inter_execPtr == 0x80) { - _vm->_global->_inter_execPtr++; + if (_vm->_game->_script->peekByte() == 0x80) { + _vm->_game->_script->skip(1); - strVar1 = _vm->_parse->parseVarIndex(); - strVar2 = _vm->_parse->parseVarIndex(0, &type); + strVar1 = _vm->_game->_script->readVarIndex(); + strVar2 = _vm->_game->_script->readVarIndex(0, &type); len = _vm->_draw->stringLength(GET_VARO_STR(strVar1), READ_VARO_UINT16(strVar2)); } else { - strVar1 = _vm->_parse->parseVarIndex(); - strVar2 = _vm->_parse->parseVarIndex(0, &type); + strVar1 = _vm->_game->_script->readVarIndex(); + strVar2 = _vm->_game->_script->readVarIndex(0, &type); if (_vm->_global->_language == 10) { // Extra handling for Japanese strings @@ -814,40 +235,36 @@ bool Inter_v5::o5_istrlen(OpFuncParams ¶ms) { } void Inter_v5::o5_spaceShooter(OpGobParams ¶ms) { - int16 paramCount = load16(); - warning("Dynasty Stub: Space shooter: %d, %d, %s", - params.extraData, paramCount, _vm->_game->_curTotFile); + params.extraData, params.paramCount, _vm->_game->_curTotFile); - if (paramCount < 4) { + if (params.paramCount < 4) { warning("Space shooter variable counter < 4"); - _vm->_global->_inter_execPtr += paramCount * 2; + _vm->_game->_script->skip(params.paramCount * 2); return; } - uint32 var1 = load16() * 4; - uint32 var2 = load16() * 4; + uint32 var1 = _vm->_game->_script->readInt16() * 4; + uint32 var2 = _vm->_game->_script->readInt16() * 4; - load16(); - load16(); + _vm->_game->_script->readInt16(); + _vm->_game->_script->readInt16(); if (params.extraData != 0) { WRITE_VARO_UINT32(var1, 2); WRITE_VARO_UINT32(var2, 0); } else { - if (paramCount < 5) { + if (params.paramCount < 5) { warning("Space shooter variable counter < 5"); return; } - _vm->_global->_inter_execPtr += (paramCount - 4) * 2; + _vm->_game->_script->skip((params.paramCount - 4) * 2); } } void Inter_v5::o5_getSystemCDSpeed(OpGobParams ¶ms) { - _vm->_global->_inter_execPtr += 2; - - WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 100); // Fudging 100% Video::FontDesc *font; if ((font = _vm->_util->loadFont("SPEED.LET"))) { @@ -859,9 +276,7 @@ void Inter_v5::o5_getSystemCDSpeed(OpGobParams ¶ms) { } void Inter_v5::o5_getSystemRAM(OpGobParams ¶ms) { - _vm->_global->_inter_execPtr += 2; - - WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 100); // Fudging 100% Video::FontDesc *font; if ((font = _vm->_util->loadFont("SPEED.LET"))) { @@ -873,9 +288,7 @@ void Inter_v5::o5_getSystemRAM(OpGobParams ¶ms) { } void Inter_v5::o5_getSystemCPUSpeed(OpGobParams ¶ms) { - _vm->_global->_inter_execPtr += 2; - - WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 100); // Fudging 100% Video::FontDesc *font; if ((font = _vm->_util->loadFont("SPEED.LET"))) { @@ -887,9 +300,7 @@ void Inter_v5::o5_getSystemCPUSpeed(OpGobParams ¶ms) { } void Inter_v5::o5_getSystemDrawSpeed(OpGobParams ¶ms) { - _vm->_global->_inter_execPtr += 2; - - WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 100); // Fudging 100% Video::FontDesc *font; if ((font = _vm->_util->loadFont("SPEED.LET"))) { @@ -901,9 +312,7 @@ void Inter_v5::o5_getSystemDrawSpeed(OpGobParams ¶ms) { } void Inter_v5::o5_totalSystemSpecs(OpGobParams ¶ms) { - _vm->_global->_inter_execPtr += 2; - - WRITE_VAR_UINT32(load16(), 100); // Fudging 100% + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 100); // Fudging 100% Video::FontDesc *font; if ((font = _vm->_util->loadFont("SPEED.LET"))) { @@ -917,8 +326,6 @@ void Inter_v5::o5_totalSystemSpecs(OpGobParams ¶ms) { void Inter_v5::o5_saveSystemSpecs(OpGobParams ¶ms) { warning("Dynasty Stub: Saving system specifications"); - _vm->_global->_inter_execPtr += 2; - /* FILE *f = fopen("SAVE\\SPEED.INF", w); fwrite(&_cdSpeed, sizeof(_cdSpeed), 1, f); @@ -933,8 +340,6 @@ void Inter_v5::o5_saveSystemSpecs(OpGobParams ¶ms) { void Inter_v5::o5_loadSystemSpecs(OpGobParams ¶ms) { warning("Dynasty Stub: Loading system specifications"); - _vm->_global->_inter_execPtr += 2; - /* FILE *f = fopen("SAVE\\SPEED.INF", r); fread(&_cdSpeed, sizeof(_cdSpeed), 1, f); @@ -971,32 +376,26 @@ void Inter_v5::o5_loadSystemSpecs(OpGobParams ¶ms) { void Inter_v5::o5_gob92(OpGobParams ¶ms) { warning("Dynasty Stub: GobFunc 92"); - _vm->_global->_inter_execPtr += 2; - - WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) _gob92_1)) */); + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 0 /* (uint32) ((int32) ((int8) _gob92_1)) */); } void Inter_v5::o5_gob95(OpGobParams ¶ms) { warning("Dynasty Stub: GobFunc 95"); - _vm->_global->_inter_execPtr += 2; - - WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) speedThrottle4)) */); - WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) speedThrottle3)) */); - WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int8) speedThrottle2)) */); - WRITE_VAR_UINT32(load16(), 0 /* (uint32) ((int32) ((int16) speedThrottle1)) */); + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 0 /* (uint32) ((int32) ((int16) speedThrottle4)) */); + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 0 /* (uint32) ((int32) ((int8) speedThrottle3)) */); + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 0 /* (uint32) ((int32) ((int8) speedThrottle2)) */); + WRITE_VAR_UINT32(_vm->_game->_script->readInt16(), 0 /* (uint32) ((int32) ((int16) speedThrottle1)) */); } void Inter_v5::o5_gob96(OpGobParams ¶ms) { int16 speedThrottle4, speedThrottle1; byte speedThrottle3, speedThrottle2; - _vm->_global->_inter_execPtr += 2; - - speedThrottle4 = READ_VAR_UINT16(load16()); - speedThrottle3 = READ_VAR_UINT8(load16()); - speedThrottle2 = READ_VAR_UINT8(load16()); - speedThrottle1 = READ_VAR_UINT16(load16()); + speedThrottle4 = READ_VAR_UINT16(_vm->_game->_script->readInt16()); + speedThrottle3 = READ_VAR_UINT8(_vm->_game->_script->readInt16()); + speedThrottle2 = READ_VAR_UINT8(_vm->_game->_script->readInt16()); + speedThrottle1 = READ_VAR_UINT16(_vm->_game->_script->readInt16()); warning("Dynasty Stub: GobFunc 96: %d, %d, %d, %d", speedThrottle4, speedThrottle3, speedThrottle2, speedThrottle1); @@ -1006,23 +405,17 @@ void Inter_v5::o5_gob96(OpGobParams ¶ms) { void Inter_v5::o5_gob97(OpGobParams ¶ms) { _gob_97_98_val = 1; - - _vm->_global->_inter_execPtr += 2; } void Inter_v5::o5_gob98(OpGobParams ¶ms) { _gob_97_98_val = 0; - - _vm->_global->_inter_execPtr += 2; } void Inter_v5::o5_gob100(OpGobParams ¶ms) { - _vm->_global->_inter_execPtr += 2; - - uint16 var1 = READ_VAR_UINT16(load16()); - uint16 var2 = READ_VAR_UINT16(load16()); - uint16 var3 = READ_VAR_UINT16(load16()); - uint16 var4 = READ_VAR_UINT16(load16()); + uint16 var1 = READ_VAR_UINT16(_vm->_game->_script->readInt16()); + uint16 var2 = READ_VAR_UINT16(_vm->_game->_script->readInt16()); + uint16 var3 = READ_VAR_UINT16(_vm->_game->_script->readInt16()); + uint16 var4 = READ_VAR_UINT16(_vm->_game->_script->readInt16()); warning("Dynasty Stub: GobFunc 100: %d, %d, %d, %d", var1, var2, var3, var4); @@ -1031,11 +424,9 @@ void Inter_v5::o5_gob100(OpGobParams ¶ms) { } void Inter_v5::o5_gob200(OpGobParams ¶ms) { - _vm->_global->_inter_execPtr += 2; - - uint16 var1 = load16(); // index into the spritesArray - uint16 var2 = load16(); - uint16 var3 = load16(); + uint16 var1 = _vm->_game->_script->readUint16(); // index into the spritesArray + uint16 var2 = _vm->_game->_script->readUint16(); + uint16 var3 = _vm->_game->_script->readUint16(); warning("Dynasty Stub: GobFunc 200: %d, %d, %d", var1, var2, var3); } diff --git a/engines/gob/inter_v6.cpp b/engines/gob/inter_v6.cpp index f40314f87e..506de821d4 100644 --- a/engines/gob/inter_v6.cpp +++ b/engines/gob/inter_v6.cpp @@ -32,626 +32,43 @@ #include "gob/helper.h" #include "gob/global.h" #include "gob/game.h" -#include "gob/parse.h" +#include "gob/expression.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/draw.h" #include "gob/sound/sound.h" #include "gob/videoplayer.h" namespace Gob { -#define OPCODE(x) _OPCODE(Inter_v6, x) - -const int Inter_v6::_goblinFuncLookUp[][2] = { - {0, 0}, -}; +#define OPCODEVER Inter_v6 +#define OPCODEDRAW(i, x) _opcodesDraw[i]._OPCODEDRAW(OPCODEVER, x) +#define OPCODEFUNC(i, x) _opcodesFunc[i]._OPCODEFUNC(OPCODEVER, x) +#define OPCODEGOB(i, x) _opcodesGob[i]._OPCODEGOB(OPCODEVER, x) Inter_v6::Inter_v6(GobEngine *vm) : Inter_v5(vm) { _gotFirstPalette = false; - - setupOpcodes(); -} - -void Inter_v6::setupOpcodes() { - static const OpcodeDrawEntryV6 opcodesDraw[256] = { - /* 00 */ - OPCODE(o1_loadMult), - OPCODE(o2_playMult), - OPCODE(o2_freeMultKeys), - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - OPCODE(o1_initCursor), - /* 08 */ - OPCODE(o1_initCursorAnim), - OPCODE(o1_clearCursorAnim), - OPCODE(o2_setRenderFlags), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - OPCODE(o1_loadAnim), - OPCODE(o1_freeAnim), - OPCODE(o1_updateAnim), - OPCODE(o2_multSub), - /* 14 */ - OPCODE(o2_initMult), - OPCODE(o1_freeMult), - OPCODE(o1_animate), - OPCODE(o2_loadMultObject), - /* 18 */ - OPCODE(o1_getAnimLayerInfo), - OPCODE(o1_getObjAnimSize), - OPCODE(o1_loadStatic), - OPCODE(o1_freeStatic), - /* 1C */ - OPCODE(o2_renderStatic), - OPCODE(o2_loadCurLayer), - {0, ""}, - {0, ""}, - /* 20 */ - OPCODE(o2_playCDTrack), - OPCODE(o2_waitCDTrackEnd), - OPCODE(o2_stopCD), - OPCODE(o2_readLIC), - /* 24 */ - OPCODE(o2_freeLIC), - OPCODE(o2_getCDTrackPos), - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o2_loadFontToSprite), - OPCODE(o1_freeFontToSprite), - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - OPCODE(o6_totSub), - OPCODE(o2_switchTotSub), - OPCODE(o2_pushVars), - OPCODE(o2_popVars), - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 48 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 4C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 50 */ - OPCODE(o2_loadMapObjects), - OPCODE(o2_freeGoblins), - OPCODE(o2_moveGoblin), - OPCODE(o2_writeGoblinPos), - /* 54 */ - OPCODE(o2_stopGoblin), - OPCODE(o2_setGoblinState), - OPCODE(o2_placeGoblin), - {0, ""}, - /* 58 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 5C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 60 */ - {0, ""}, - OPCODE(o5_deleteFile), - {0, ""}, - {0, ""}, - /* 64 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 68 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 6C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 70 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 74 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 78 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 7C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 80 */ - OPCODE(o5_initScreen), - OPCODE(o2_scroll), - OPCODE(o2_setScrollOffset), - OPCODE(o6_playVmdOrMusic), - /* 84 */ - OPCODE(o2_getImdInfo), - OPCODE(o6_openItk), - OPCODE(o2_closeItk), - OPCODE(o2_setImdFrontSurf), - /* 88 */ - OPCODE(o2_resetImdFrontSurf), - {0, ""}, - {0, ""}, - {0, ""}, - /* 8C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 90 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 94 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 98 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 9C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* A8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* AC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* B8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* BC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* C8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* CC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* D8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* DC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* E8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* EC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F0 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F4 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* F8 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* FC */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""} - }; - - static const OpcodeFuncEntryV6 opcodesFunc[80] = { - /* 00 */ - OPCODE(o1_callSub), - OPCODE(o1_callSub), - OPCODE(o1_printTotText), - OPCODE(o6_loadCursor), - /* 04 */ - {0, ""}, - OPCODE(o1_switch), - OPCODE(o1_repeatUntil), - OPCODE(o1_whileDo), - /* 08 */ - OPCODE(o1_if), - OPCODE(o6_assign), - OPCODE(o1_loadSpriteToPos), - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - OPCODE(o2_printText), - OPCODE(o1_loadTot), - OPCODE(o6_palLoad), - /* 14 */ - OPCODE(o1_keyFunc), - OPCODE(o1_capturePush), - OPCODE(o1_capturePop), - OPCODE(o2_animPalInit), - /* 18 */ - OPCODE(o2_addCollision), - OPCODE(o6_freeCollision), - OPCODE(o3_getTotTextItemPart), - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - OPCODE(o1_drawOperations), - OPCODE(o1_setcmdCount), - /* 20 */ - OPCODE(o1_return), - OPCODE(o1_renewTimeInVars), - OPCODE(o1_speakerOn), - OPCODE(o1_speakerOff), - /* 24 */ - OPCODE(o1_putPixel), - OPCODE(o2_goblinFunc), - OPCODE(o1_createSprite), - OPCODE(o1_freeSprite), - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - OPCODE(o1_returnTo), - OPCODE(o1_loadSpriteContent), - OPCODE(o1_copySprite), - OPCODE(o6_fillRect), - /* 34 */ - OPCODE(o1_drawLine), - OPCODE(o1_strToLong), - OPCODE(o1_invalidate), - OPCODE(o1_setBackDelta), - /* 38 */ - OPCODE(o1_playSound), - OPCODE(o2_stopSound), - OPCODE(o2_loadSound), - OPCODE(o1_freeSoundSlot), - /* 3C */ - OPCODE(o1_waitEndPlay), - OPCODE(o1_playComposition), - OPCODE(o2_getFreeMem), - OPCODE(o2_checkData), - /* 40 */ - {0, ""}, - OPCODE(o1_prepareStr), - OPCODE(o1_insertStr), - OPCODE(o1_cutStr), - /* 44 */ - OPCODE(o1_strstr), - OPCODE(o5_istrlen), - OPCODE(o1_setMousePos), - OPCODE(o1_setFrameRate), - /* 48 */ - OPCODE(o1_animatePalette), - OPCODE(o1_animateCursor), - OPCODE(o1_blitCursor), - OPCODE(o1_loadFont), - /* 4C */ - OPCODE(o1_freeFont), - OPCODE(o2_readData), - OPCODE(o2_writeData), - OPCODE(o1_manageDataFile), - }; - - static const OpcodeGoblinEntryV6 opcodesGoblin[71] = { - /* 00 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 04 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 08 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 0C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 10 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 14 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 18 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 1C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 20 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 24 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 28 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 2C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 30 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 34 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 38 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 3C */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 40 */ - {0, ""}, - {0, ""}, - {0, ""}, - {0, ""}, - /* 44 */ - {0, ""}, - {0, ""}, - {0, ""}, - }; - - _opcodesDrawV6 = opcodesDraw; - _opcodesFuncV6 = opcodesFunc; - _opcodesGoblinV6 = opcodesGoblin; -} - -void Inter_v6::executeDrawOpcode(byte i) { - debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); - - OpcodeDrawProcV6 op = _opcodesDrawV6[i].proc; - - if (op == 0) - warning("unimplemented opcodeDraw: %d", i); - else - (this->*op) (); -} - -bool Inter_v6::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - _vm->_video->_palLUT->buildNext(); - - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d", - i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile, - (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData), - (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4)); - - if ((i > 4) || (j > 15)) { - warning("unimplemented opcodeFunc: %d.%d", i, j); - return false; - } - - OpcodeFuncProcV6 op = _opcodesFuncV6[i*16 + j].proc; - - if (op == 0) - warning("unimplemented opcodeFunc: %d.%d", i, j); - else - return (this->*op) (params); - - return false; } -void Inter_v6::executeGoblinOpcode(int i, OpGobParams ¶ms) { - debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); - - OpcodeGoblinProcV6 op = 0; - - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) { - op = _opcodesGoblinV6[_goblinFuncLookUp[j][1]].proc; - break; - } - - _vm->_global->_inter_execPtr -= 2; - - if (op == 0) { - warning("unimplemented opcodeGoblin: %d", i); - - int16 paramCount = load16(); - _vm->_global->_inter_execPtr += paramCount * 2; - } else { - params.extraData = i; +void Inter_v6::setupOpcodesDraw() { + Inter_v5::setupOpcodesDraw(); - (this->*op) (params); - } -} - -const char *Inter_v6::getOpcodeDrawDesc(byte i) { - return _opcodesDrawV6[i].desc; + OPCODEDRAW(0x40, o6_totSub); + OPCODEDRAW(0x83, o6_playVmdOrMusic); + OPCODEDRAW(0x85, o6_openItk); } -const char *Inter_v6::getOpcodeFuncDesc(byte i, byte j) { - if ((i > 4) || (j > 15)) - return ""; +void Inter_v6::setupOpcodesFunc() { + Inter_v5::setupOpcodesFunc(); - return _opcodesFuncV6[i*16 + j].desc; + OPCODEFUNC(0x03, o6_loadCursor); + OPCODEFUNC(0x09, o6_assign); + OPCODEFUNC(0x13, o6_palLoad); + OPCODEFUNC(0x19, o6_freeCollision); + OPCODEFUNC(0x33, o6_fillRect); } -const char *Inter_v6::getOpcodeGoblinDesc(int i) { - for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) - if (_goblinFuncLookUp[j][0] == i) - return _opcodesGoblinV6[_goblinFuncLookUp[j][1]].desc; - return ""; +void Inter_v6::setupOpcodesGob() { } void Inter_v6::o6_totSub() { @@ -660,20 +77,20 @@ void Inter_v6::o6_totSub() { int flags; int i; - length = *_vm->_global->_inter_execPtr++; + length = _vm->_game->_script->readByte(); if ((length & 0x7F) > 13) error("Length in o2_totSub is greater than 13 (%d)", length); if (length & 0x80) { - evalExpr(0); - strcpy(totFile, _vm->_global->_inter_resStr); + _vm->_game->_script->evalExpr(0); + strcpy(totFile, _vm->_game->_script->getResultStr()); } else { for (i = 0; i < length; i++) - totFile[i] = (char) *_vm->_global->_inter_execPtr++; + totFile[i] = _vm->_game->_script->readChar(); totFile[i] = 0; } - flags = *_vm->_global->_inter_execPtr++; + flags = _vm->_game->_script->readByte(); if (flags & 0x40) warning("Urban Stub: o6_totSub(), flags & 0x40"); @@ -693,17 +110,17 @@ void Inter_v6::o6_playVmdOrMusic() { uint16 palCmd; bool close; - evalExpr(0); - strncpy0(fileName, _vm->_global->_inter_resStr, 127); - - x = _vm->_parse->parseValExpr(); - y = _vm->_parse->parseValExpr(); - startFrame = _vm->_parse->parseValExpr(); - lastFrame = _vm->_parse->parseValExpr(); - breakKey = _vm->_parse->parseValExpr(); - flags = _vm->_parse->parseValExpr(); - palStart = _vm->_parse->parseValExpr(); - palEnd = _vm->_parse->parseValExpr(); + _vm->_game->_script->evalExpr(0); + strncpy0(fileName, _vm->_game->_script->getResultStr(), 127); + + x = _vm->_game->_script->readValExpr(); + y = _vm->_game->_script->readValExpr(); + startFrame = _vm->_game->_script->readValExpr(); + lastFrame = _vm->_game->_script->readValExpr(); + breakKey = _vm->_game->_script->readValExpr(); + flags = _vm->_game->_script->readValExpr(); + palStart = _vm->_game->_script->readValExpr(); + palEnd = _vm->_game->_script->readValExpr(); palCmd = 1 << (flags & 0x3F); debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " @@ -759,8 +176,8 @@ void Inter_v6::o6_playVmdOrMusic() { void Inter_v6::o6_openItk() { char fileName[32]; - evalExpr(0); - strncpy0(fileName, _vm->_global->_inter_resStr, 27); + _vm->_game->_script->evalExpr(0); + strncpy0(fileName, _vm->_game->_script->getResultStr(), 27); if (!strchr(fileName, '.')) strcat(fileName, ".ITK"); @@ -778,21 +195,21 @@ void Inter_v6::o6_openItk() { } bool Inter_v6::o6_loadCursor(OpFuncParams ¶ms) { - int16 id = load16(); + int16 id = _vm->_game->_script->readInt16(); if ((id == -1) || (id == -2)) { char file[10]; if (id == -1) { for (int i = 0; i < 9; i++) - file[i] = *_vm->_global->_inter_execPtr++; + file[i] = _vm->_game->_script->readChar(); } else - strncpy(file, GET_VAR_STR(load16()), 10); + strncpy(file, GET_VAR_STR(_vm->_game->_script->readInt16()), 10); file[9] = '\0'; - uint16 start = load16(); - int8 index = (int8) *_vm->_global->_inter_execPtr++; + uint16 start = _vm->_game->_script->readUint16(); + int8 index = _vm->_game->_script->readInt8(); int vmdSlot = _vm->_vidPlayer->slotOpen(file); @@ -820,101 +237,102 @@ bool Inter_v6::o6_loadCursor(OpFuncParams ¶ms) { return false; } - int8 index = (int8) *_vm->_global->_inter_execPtr++; + int8 index = _vm->_game->_script->readInt8(); if ((index * _vm->_draw->_cursorWidth) >= _vm->_draw->_cursorSprites->getWidth()) return false; - int16 width, height; - byte *dataBuf = _vm->_game->loadTotResource(id, 0, &width, &height); + Resource *resource = _vm->_game->_resources->getResource((uint16) id); + if (!resource) + return false; _vm->_video->fillRect(*_vm->_draw->_cursorSprites, index * _vm->_draw->_cursorWidth, 0, index * _vm->_draw->_cursorWidth + _vm->_draw->_cursorWidth - 1, _vm->_draw->_cursorHeight - 1, 0); - _vm->_video->drawPackedSprite(dataBuf, width, height, + _vm->_video->drawPackedSprite(resource->getData(), + resource->getWidth(), resource->getHeight(), index * _vm->_draw->_cursorWidth, 0, 0, *_vm->_draw->_cursorSprites); _vm->_draw->_cursorAnimLow[index] = 0; + delete resource; return false; } bool Inter_v6::o6_assign(OpFuncParams ¶ms) { - byte *savedPos; - int16 varOff; - int16 token; - int16 result; - byte loopCount; - uint16 var_6, var_A; + uint16 size, destType; + int16 dest = _vm->_game->_script->readVarIndex(&size, &destType); - varOff = _vm->_parse->parseVarIndex(&var_6, &var_A); + if (size != 0) { + int16 src; - if (var_6 != 0) { - int16 var_4; + _vm->_game->_script->push(); - savedPos = _vm->_global->_inter_execPtr; + src = _vm->_game->_script->readVarIndex(&size, 0); - var_4 = _vm->_parse->parseVarIndex(&var_6, 0); + memcpy(_vm->_inter->_variables->getAddressOff8(dest), + _vm->_inter->_variables->getAddressOff8(src), size * 4); - memcpy(_vm->_inter->_variables->getAddressOff8(varOff), - _vm->_inter->_variables->getAddressOff8(var_4), var_6 * 4); + _vm->_game->_script->pop(); - _vm->_global->_inter_execPtr = savedPos; - evalExpr(&var_4); + _vm->_game->_script->evalExpr(&src); return false; } - if (*_vm->_global->_inter_execPtr == 98) { - _vm->_global->_inter_execPtr++; - loopCount = *_vm->_global->_inter_execPtr++; + byte loopCount; + if (_vm->_game->_script->peekByte() == 98) { + _vm->_game->_script->skip(1); + loopCount = _vm->_game->_script->readByte(); for (int i = 0; i < loopCount; i++) { - uint8 c = *_vm->_global->_inter_execPtr++; - uint16 n = load16(); + uint8 c = _vm->_game->_script->readByte(); + uint16 n = _vm->_game->_script->readUint16(); - memset(_vm->_inter->_variables->getAddressOff8(varOff), c, n); + memset(_vm->_inter->_variables->getAddressOff8(dest), c, n); - varOff += n; + dest += n; } return false; - } else if (*_vm->_global->_inter_execPtr == 99) { - _vm->_global->_inter_execPtr++; - loopCount = *_vm->_global->_inter_execPtr++; + } else if (_vm->_game->_script->peekByte() == 99) { + _vm->_game->_script->skip(1); + loopCount = _vm->_game->_script->readByte(); } else loopCount = 1; for (int i = 0; i < loopCount; i++) { - token = evalExpr(&result); - switch (var_A) { - case 16: - case 18: - WRITE_VARO_UINT8(varOff + i, _vm->_global->_inter_resVal); + int16 result; + int16 srcType = _vm->_game->_script->evalExpr(&result); + + switch (destType) { + case TYPE_VAR_INT8: + case TYPE_ARRAY_INT8: + WRITE_VARO_UINT8(dest + i, _vm->_game->_script->getResultInt()); break; - case 17: - case 27: - WRITE_VARO_UINT16(varOff + i * 2, _vm->_global->_inter_resVal); + case TYPE_VAR_INT16: + case TYPE_ARRAY_INT16: + WRITE_VARO_UINT16(dest + i * 2, _vm->_game->_script->getResultInt()); break; - case 23: - case 26: - WRITE_VAR_OFFSET(varOff + i * 4, _vm->_global->_inter_resVal); + case TYPE_VAR_INT32: + case TYPE_ARRAY_INT32: + WRITE_VAR_OFFSET(dest + i * 4, _vm->_game->_script->getResultInt()); break; - case 24: - WRITE_VARO_UINT16(varOff + i * 4, _vm->_global->_inter_resVal); + case TYPE_VAR_INT32_AS_INT16: + WRITE_VARO_UINT16(dest + i * 4, _vm->_game->_script->getResultInt()); break; - case 25: - case 28: - if (token == 20) - WRITE_VARO_UINT8(varOff, result); + case TYPE_VAR_STR: + case TYPE_ARRAY_STR: + if (srcType == TYPE_IMM_INT16) + WRITE_VARO_UINT8(dest, result); else - WRITE_VARO_STR(varOff, _vm->_global->_inter_resStr); + WRITE_VARO_STR(dest, _vm->_game->_script->getResultStr()); break; } } @@ -936,7 +354,7 @@ bool Inter_v6::o6_palLoad(OpFuncParams ¶ms) { bool Inter_v6::o6_freeCollision(OpFuncParams ¶ms) { int16 id; - id = _vm->_parse->parseValExpr(); + id = _vm->_game->_script->readValExpr(); switch (id + 5) { case 0: @@ -972,17 +390,17 @@ bool Inter_v6::o6_freeCollision(OpFuncParams ¶ms) { bool Inter_v6::o6_fillRect(OpFuncParams ¶ms) { int16 destSurf; - _vm->_draw->_destSurface = destSurf = load16(); + _vm->_draw->_destSurface = destSurf = _vm->_game->_script->readInt16(); - _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); - _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteRight = _vm->_parse->parseValExpr(); - _vm->_draw->_spriteBottom = _vm->_parse->parseValExpr(); + _vm->_draw->_destSpriteX = _vm->_game->_script->readValExpr(); + _vm->_draw->_destSpriteY = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteRight = _vm->_game->_script->readValExpr(); + _vm->_draw->_spriteBottom = _vm->_game->_script->readValExpr(); - evalExpr(0); + _vm->_game->_script->evalExpr(0); - _vm->_draw->_backColor = _vm->_global->_inter_resVal & 0xFFFF; - uint16 extraVar = _vm->_global->_inter_resVal >> 16; + _vm->_draw->_backColor = _vm->_game->_script->getResultInt() & 0xFFFF; + uint16 extraVar = _vm->_game->_script->getResultInt() >> 16; if (extraVar != 0) warning("Urban Stub: o6_fillRect(), extraVar = %d", extraVar); @@ -1019,11 +437,8 @@ void Inter_v6::probe16bitMusic(char *fileName) { fileName[len - 1] = 'V'; - int16 handle; - if ((handle = _vm->_dataIO->openData(fileName)) >= 0) { - _vm->_dataIO->closeData(handle); + if (_vm->_dataIO->existData(fileName)) return; - } fileName[len - 1] = '8'; } diff --git a/engines/gob/map_v1.cpp b/engines/gob/map_v1.cpp index 2c94b3fb24..dacc72d6c7 100644 --- a/engines/gob/map_v1.cpp +++ b/engines/gob/map_v1.cpp @@ -64,7 +64,6 @@ void Map_v1::init(void) { void Map_v1::loadMapObjects(const char *avjFile) { char avoName[128]; byte *dataBuf; - int16 handle; int16 tmp; int32 flag; int16 gobDataCount; @@ -75,15 +74,14 @@ void Map_v1::loadMapObjects(const char *avjFile) { strcpy(avoName, _sourceFile); strcat(avoName, ".avo"); - handle = _vm->_dataIO->openData(avoName); - if (handle >= 0) { + if (_vm->_dataIO->existData(avoName)) { _loadFromAvo = true; - _vm->_dataIO->closeData(handle); dataBuf = _vm->_dataIO->getData(avoName); } else { _loadFromAvo = false; dataBuf = _vm->_dataIO->getData(avjFile); } + Common::MemoryReadStream mapData(dataBuf, 4294967295U); init(); @@ -146,7 +144,6 @@ void Map_v1::loadMapObjects(const char *avjFile) { void Map_v1::loadSounds(Common::SeekableReadStream &data) { int16 count; - int16 handle; char buf[19]; char sndNames[20][14]; @@ -162,11 +159,9 @@ void Map_v1::loadSounds(Common::SeekableReadStream &data) { _vm->_sound->sampleLoad(&_vm->_goblin->_soundData[14], SOUND_SND, "diamant1.snd"); for (int i = 0; i < count; i++) { - handle = _vm->_dataIO->openData(sndNames[i]); - if (handle < 0) + if (!_vm->_dataIO->existData(sndNames[i])) continue; - _vm->_dataIO->closeData(handle); _vm->_sound->sampleLoad(&_vm->_goblin->_soundData[i], SOUND_SND, sndNames[i]); } } diff --git a/engines/gob/map_v2.cpp b/engines/gob/map_v2.cpp index db4f2075e1..6ceda7ab44 100644 --- a/engines/gob/map_v2.cpp +++ b/engines/gob/map_v2.cpp @@ -31,7 +31,8 @@ #include "gob/goblin.h" #include "gob/inter.h" #include "gob/game.h" -#include "gob/parse.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/mult.h" namespace Gob { @@ -51,22 +52,24 @@ void Map_v2::loadMapObjects(const char *avjFile) { int16 mapWidth, mapHeight; int16 tmp; byte *variables; - byte *extData; uint32 tmpPos; uint32 passPos; - var = _vm->_parse->parseVarIndex(); + var = _vm->_game->_script->readVarIndex(); variables = _vm->_inter->_variables->getAddressOff8(var); - id = _vm->_inter->load16(); + id = _vm->_game->_script->readInt16(); if (id == -1) { _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var); return; } - extData = _vm->_game->loadExtData(id, 0, 0); - Common::MemoryReadStream mapData(extData, 4294967295U); + Resource *resource = _vm->_game->_resources->getResource(id); + if (!resource) + return; + + Common::SeekableReadStream &mapData = *resource->stream(); if (mapData.readByte() == 3) { _screenWidth = 640; @@ -88,7 +91,7 @@ void Map_v2::loadMapObjects(const char *avjFile) { passPos = mapData.pos(); mapData.skip(_mapWidth * _mapHeight); - if (*extData == 1) + if (resource->getData()[0] == 1) wayPointsCount = _wayPointsCount = 40; else wayPointsCount = _wayPointsCount == 0 ? 1 : _wayPointsCount; @@ -130,11 +133,11 @@ void Map_v2::loadMapObjects(const char *avjFile) { for (int i = 0; i < _vm->_goblin->_gobsCount; i++) loadGoblinStates(mapData, i); - _vm->_goblin->_soundSlotsCount = _vm->_inter->load16(); + _vm->_goblin->_soundSlotsCount = _vm->_game->_script->readInt16(); for (int i = 0; i < _vm->_goblin->_soundSlotsCount; i++) _vm->_goblin->_soundSlots[i] = _vm->_inter->loadSound(1); - delete[] extData; + delete resource; } void Map_v2::loadGoblinStates(Common::SeekableReadStream &data, int index) { diff --git a/engines/gob/map_v4.cpp b/engines/gob/map_v4.cpp index 858e7972bc..1db3d6a3f8 100644 --- a/engines/gob/map_v4.cpp +++ b/engines/gob/map_v4.cpp @@ -31,7 +31,8 @@ #include "gob/goblin.h" #include "gob/inter.h" #include "gob/game.h" -#include "gob/parse.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/mult.h" namespace Gob { @@ -49,14 +50,13 @@ void Map_v4::loadMapObjects(const char *avjFile) { int16 mapWidth, mapHeight; int16 tmp; byte *variables; - byte *extData; uint32 tmpPos; uint32 passPos; - var = _vm->_parse->parseVarIndex(); + var = _vm->_game->_script->readVarIndex(); variables = _vm->_inter->_variables->getAddressOff8(var); - id = _vm->_inter->load16(); + id = _vm->_game->_script->readInt16(); if (((uint16) id) >= 65520) { warning("Woodruff Stub: loadMapObjects ID >= 65520"); @@ -66,8 +66,11 @@ void Map_v4::loadMapObjects(const char *avjFile) { return; } - extData = _vm->_game->loadExtData(id, 0, 0); - Common::MemoryReadStream mapData(extData, 4294967295U); + Resource *resource = _vm->_game->_resources->getResource(id); + if (!resource) + return; + + Common::SeekableReadStream &mapData = *resource->stream(); _widthByte = mapData.readByte(); if (_widthByte == 4) { @@ -99,7 +102,7 @@ void Map_v4::loadMapObjects(const char *avjFile) { passPos = mapData.pos(); mapData.skip(_mapWidth * _mapHeight); - if (*extData == 1) + if (resource->getData()[0] == 1) wayPointsCount = _wayPointsCount = 40; else wayPointsCount = _wayPointsCount == 0 ? 1 : _wayPointsCount; @@ -146,11 +149,11 @@ void Map_v4::loadMapObjects(const char *avjFile) { for (int i = 0; i < _vm->_goblin->_gobsCount; i++) loadGoblinStates(mapData, i); - _vm->_goblin->_soundSlotsCount = _vm->_inter->load16(); + _vm->_goblin->_soundSlotsCount = _vm->_game->_script->readInt16(); for (int i = 0; i < _vm->_goblin->_soundSlotsCount; i++) _vm->_goblin->_soundSlots[i] = _vm->_inter->loadSound(1); - delete[] extData; + delete resource; } } // End of namespace Gob diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 22a5cd37b9..695976da61 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -9,6 +9,7 @@ MODULE_OBJS := \ draw_bargon.o \ draw_fascin.o \ driver_vga.o \ + expression.o \ game.o \ game_v1.o \ game_v2.o \ @@ -43,10 +44,12 @@ MODULE_OBJS := \ mult_v1.o \ mult_v2.o \ palanim.o \ - parse.o \ + resources.o \ scenery.o \ scenery_v1.o \ scenery_v2.o \ + script.o \ + totfile.o \ util.o \ variables.o \ video.o \ diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp index 1670c26ea5..5aec5ff76e 100644 --- a/engines/gob/mult.cpp +++ b/engines/gob/mult.cpp @@ -31,6 +31,7 @@ #include "gob/util.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/script.h" #include "gob/palanim.h" #include "gob/scenery.h" #include "gob/video.h" @@ -251,8 +252,6 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape, } void Mult::drawText(bool &stop, bool &stopNoClear) { - byte *savedIP; - int16 cmd; for (_index = 0; _index < _multData->textKeysCount; _index++) { if (_multData->textKeys[_index].frame != _frame) @@ -265,9 +264,10 @@ void Mult::drawText(bool &stop, bool &stopNoClear) { stopNoClear = true; _multData->frameStart = 0; } else if (cmd == 3) { + warning("Mult::drawText, cmd == 3"); stop = false; - savedIP = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr = _multData->textKeys[_index].script; +// uint32 startPos = _vm->_game->_script->pos(); +// _vm->_global->_inter_execPtr = _multData->textKeys[_index].script; } } } diff --git a/engines/gob/mult_v1.cpp b/engines/gob/mult_v1.cpp index e2c16674c9..1bb162c789 100644 --- a/engines/gob/mult_v1.cpp +++ b/engines/gob/mult_v1.cpp @@ -1,4 +1,4 @@ -/* ScummVM - Graphic Adventure Engine +/* 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 @@ -32,6 +32,8 @@ #include "gob/util.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/inter.h" #include "gob/scenery.h" @@ -41,9 +43,6 @@ Mult_v1::Mult_v1(GobEngine *vm) : Mult(vm) { } void Mult_v1::loadMult(int16 resId) { - uint32 dataSize; - byte *extData; - debugC(4, kDebugGameFlow, "Loading mult"); _multData = new Mult_Data; @@ -52,8 +51,11 @@ void Mult_v1::loadMult(int16 resId) { _multData->sndSlotsCount = 0; _multData->frameStart = 0; - extData = (byte *) _vm->_game->loadExtData(resId, 0, 0, &dataSize); - Common::MemoryReadStream data(extData, dataSize); + Resource *resource = _vm->_game->_resources->getResource(resId); + if (!resource) + return; + + Common::SeekableReadStream &data = *resource->stream(); _multData->staticCount = data.readSByte() + 1; _multData->animCount = data.readSByte() + 1; @@ -157,15 +159,14 @@ void Mult_v1::loadMult(int16 resId) { switch (_multData->sndKeys[i].cmd) { case 1: case 4: - _multData->sndKeys[i].resId = - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _multData->sndKeys[i].resId = _vm->_game->_script->peekUint16(); for (j = 0; j < i; j++) { if (_multData->sndKeys[i].resId == _multData->sndKeys[j].resId) { _multData->sndKeys[i].soundIndex = _multData->sndKeys[j].soundIndex; - _vm->_global->_inter_execPtr += 2; + _vm->_game->_script->skip(2); break; } } @@ -178,16 +179,16 @@ void Mult_v1::loadMult(int16 resId) { break; case 3: - _vm->_global->_inter_execPtr += 6; + _vm->_game->_script->skip(6); break; case 5: - _vm->_global->_inter_execPtr += _multData->sndKeys[i].freq * 2; + _vm->_game->_script->skip(_multData->sndKeys[i].freq * 2); break; } } - delete[] extData; + delete resource; } void Mult_v1::freeMultKeys() { diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index d9b5be0847..135c50c92c 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -32,9 +32,10 @@ #include "gob/util.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/goblin.h" #include "gob/inter.h" -#include "gob/parse.h" #include "gob/scenery.h" #include "gob/video.h" #include "gob/videoplayer.h" @@ -60,11 +61,9 @@ void Mult_v2::loadMult(int16 resId) { int8 index; uint8 staticCount; uint8 animCount; - uint32 dataSize; - byte *extData; bool hasImds; - index = (resId & 0x8000) ? *_vm->_global->_inter_execPtr++ : 0; + index = (resId & 0x8000) ? _vm->_game->_script->readByte() : 0; resId &= 0x7FFF; debugC(4, kDebugGameFlow, "Loading mult %d", index); @@ -80,8 +79,11 @@ void Mult_v2::loadMult(int16 resId) { _multData->sndSlotsCount = 0; _multData->frameStart = 0; - extData = (byte *) _vm->_game->loadExtData(resId, 0, 0, &dataSize); - Common::MemoryReadStream data(extData, dataSize); + Resource *resource = _vm->_game->_resources->getResource(resId); + if (!resource) + return; + + Common::SeekableReadStream &data = *resource->stream(); _multData->staticCount = staticCount = data.readSByte(); _multData->animCount = animCount = data.readSByte(); @@ -206,14 +208,13 @@ void Mult_v2::loadMult(int16 resId) { switch (_multData->sndKeys[i].cmd) { case 1: case 4: - _multData->sndKeys[i].resId = - READ_LE_UINT16(_vm->_global->_inter_execPtr); + _multData->sndKeys[i].resId = _vm->_game->_script->peekUint16(); for (j = 0; j < i; j++) { if (_multData->sndKeys[j].resId == _multData->sndKeys[i].resId) { _multData->sndKeys[i].soundIndex = _multData->sndKeys[j].soundIndex; - _vm->_global->_inter_execPtr += 2; + _vm->_game->_script->skip(2); break; } } @@ -226,7 +227,7 @@ void Mult_v2::loadMult(int16 resId) { } break; case 3: - _vm->_global->_inter_execPtr += 4; + _vm->_game->_script->skip(4); break; case -1: @@ -244,17 +245,17 @@ void Mult_v2::loadMult(int16 resId) { if (hasImds) loadImds(data); - delete[] extData; + delete resource; } void Mult_v2::loadImds(Common::SeekableReadStream &data) { int16 size; - size = _vm->_inter->load16(); - _multData->execPtr = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += size * 2; + size = _vm->_game->_script->readInt16(); + _multData->execPtr = _vm->_game->_script->getData() + _vm->_game->_script->pos(); + _vm->_game->_script->skip(size * 2); - if (_vm->_game->_totFileData[0x29] < 51) + if (_vm->_game->_script->getVersionMinor() < 3) return; size = data.readSint16LE(); @@ -263,13 +264,27 @@ void Mult_v2::loadImds(Common::SeekableReadStream &data) { data.read(_multData->somepointer10, size * 20); } - size = _vm->_inter->load16(); + size = _vm->_game->_script->readInt16(); if (size <= 0) return; _multData->imdFiles = new char[size * 14]; - memcpy(_multData->imdFiles, _vm->_global->_inter_execPtr, size * 14); - _vm->_global->_inter_execPtr += size * 14; + memcpy(_multData->imdFiles, + _vm->_game->_script->getData() + _vm->_game->_script->pos(), size * 14); + + // WORKAROUND: The Windows version of Lost in Time has VMD not IMD files, + // but they are still referenced as IMD. + if ((_vm->getGameType() == kGameTypeLostInTime) && + (_vm->getPlatform() == Common::kPlatformWindows)) { + + for (int i = 0; i < size; i++) { + char *dot = strrchr(_multData->imdFiles + (i * 14), '.'); + if (dot) + *dot = '\0'; + } + } + + _vm->_game->_script->skip(size * 14); data.seek(2, SEEK_CUR); for (int i = 0; i < 4; i++) { _multData->imdKeysCount[i] = data.readSint16LE(); @@ -382,14 +397,16 @@ void Mult_v2::multSub(uint16 multIndex) { if (multIndex > 7) error("Multindex out of range"); + _vm->_util->notifyNewAnim(); + debugC(4, kDebugGameFlow, "Sub mult %d", multIndex); _multData = _multDatas[multIndex]; if (!_multData) { - _vm->_parse->parseValExpr(); - _vm->_parse->parseValExpr(); - _vm->_parse->parseValExpr(); - _vm->_parse->parseValExpr(); + _vm->_game->_script->readValExpr(); + _vm->_game->_script->readValExpr(); + _vm->_game->_script->readValExpr(); + _vm->_game->_script->readValExpr(); return; } @@ -412,9 +429,9 @@ void Mult_v2::multSub(uint16 multIndex) { _multData->animObjs[index][0] = flags; for (int i = 1; i < 4; i++) - _multData->animObjs[index][i] = _vm->_parse->parseValExpr(); + _multData->animObjs[index][i] = _vm->_game->_script->readValExpr(); - expr = _vm->_parse->parseValExpr(); + expr = _vm->_game->_script->readValExpr(); _multData->animKeysFrames[index] = expr; _multData->animKeysStartFrames[index] = expr; @@ -856,7 +873,7 @@ void Mult_v2::animate() { animObj.newBottom = MAX(animObj.lastBottom, _vm->_scenery->_toRedrawBottom); - if ((_vm->_game->_totFileData[0x29] > 50) && + if ((_vm->_game->_script->getVersionMinor() > 2) && (animObj.newLeft == animObj.lastLeft) && (animObj.newTop == animObj.lastTop) && (animObj.newRight == animObj.lastRight) && diff --git a/engines/gob/parse.cpp b/engines/gob/parse.cpp deleted file mode 100644 index 0fa46097a3..0000000000 --- a/engines/gob/parse.cpp +++ /dev/null @@ -1,1499 +0,0 @@ -/* 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 "common/endian.h" - -#include "gob/gob.h" -#include "gob/parse.h" -#include "gob/global.h" -#include "gob/game.h" -#include "gob/inter.h" - -namespace Gob { - -Parse::Parse(GobEngine *vm) : _vm(vm) { -} - -int32 Parse::encodePtr(byte *ptr, int type) { - int32 offset = 0; - - switch (type) { - case kExecPtr: - offset = ptr - _vm->_game->_totFileData; - break; - case kInterVar: - offset = ptr - ((byte *) _vm->_inter->_variables->getAddressOff8(0)); - break; - case kResStr: - offset = ptr - ((byte *) _vm->_global->_inter_resStr); - break; - default: - error("Parse::encodePtr(): Unknown pointer type"); - } - assert((offset & 0xF0000000) == 0); - return (type << 28) | offset; -} - -byte *Parse::decodePtr(int32 n) { - byte *ptr; - - switch (n >> 28) { - case kExecPtr: - ptr = _vm->_game->_totFileData; - break; - case kInterVar: - ptr = (byte *) _vm->_inter->_variables->getAddressOff8(0); - break; - case kResStr: - ptr = (byte *) _vm->_global->_inter_resStr; - break; - default: - error("Parse::decodePtr(): Unknown pointer type"); - } - return ptr + (n & 0x0FFFFFFF); -} - -void Parse::skipExpr(char stopToken) { - int16 dimCount; - byte operation; - int16 num; - int16 dim; - - num = 0; - while (true) { - operation = *_vm->_global->_inter_execPtr++; - - if ((operation >= 14) && (operation <= OP_FUNC)) { - switch (operation) { - case 14: - _vm->_global->_inter_execPtr += 4; - if (*_vm->_global->_inter_execPtr == 97) - _vm->_global->_inter_execPtr++; - break; - - case OP_LOAD_VAR_INT16: - case OP_LOAD_VAR_INT8: - case OP_LOAD_IMM_INT16: - case 23: - case 24: - _vm->_global->_inter_execPtr += 2; - break; - - case OP_LOAD_IMM_INT32: - _vm->_global->_inter_execPtr += 4; - break; - - case OP_LOAD_IMM_INT8: - _vm->_global->_inter_execPtr += 1; - break; - - case OP_LOAD_IMM_STR: - _vm->_global->_inter_execPtr += - strlen((char *) _vm->_global->_inter_execPtr) + 1; - break; - - case OP_LOAD_VAR_STR: - _vm->_global->_inter_execPtr += 2; - if (*_vm->_global->_inter_execPtr == 13) { - _vm->_global->_inter_execPtr++; - skipExpr(OP_END_MARKER); - } - break; - - case 15: - _vm->_global->_inter_execPtr += 2; - - case OP_ARRAY_UINT8: - case OP_ARRAY_UINT32: - case OP_ARRAY_UINT16: - case OP_ARRAY_STR: - dimCount = _vm->_global->_inter_execPtr[2]; - // skip header and dimensions - _vm->_global->_inter_execPtr += 3 + dimCount; - // skip indices - for (dim = 0; dim < dimCount; dim++) - skipExpr(OP_END_MARKER); - - if ((operation == OP_ARRAY_STR) && (*_vm->_global->_inter_execPtr == 13)) { - _vm->_global->_inter_execPtr++; - skipExpr(OP_END_MARKER); - } - break; - - case OP_FUNC: - _vm->_global->_inter_execPtr++; - skipExpr(OP_END_EXPR); - } - continue; - } // if ((operation >= OP_ARRAY_UINT8) && (operation <= OP_FUNC)) - - if (operation == OP_BEGIN_EXPR) { - num++; - continue; - } - - if ((operation == OP_NOT) || ((operation >= OP_NEG) && (operation <= 8))) - continue; - - if ((operation >= OP_OR) && (operation <= OP_NEQ)) - continue; - - if (operation == OP_END_EXPR) - num--; - - if (operation != stopToken) - continue; - - if ((stopToken != OP_END_EXPR) || (num < 0)) - return; - } -} - -void Parse::printExpr(char stopToken) { - // Expression printing disabled by default - return; - - byte *savedPos = _vm->_global->_inter_execPtr; - printExpr_internal(stopToken); - - // restore IP to start of expression - _vm->_global->_inter_execPtr = savedPos; -} - -void Parse::printExpr_internal(char stopToken) { - int16 dimCount; - byte operation; - int16 num; - int16 dim; - byte *arrDesc; - byte func; - - num = 0; - while (true) { - operation = *_vm->_global->_inter_execPtr++; - - if ((operation >= OP_ARRAY_UINT8) && (operation <= OP_FUNC)) { - // operands - - switch (operation) { - case OP_LOAD_VAR_INT16: // int16 variable load - debugN(5, "var16_%d", _vm->_inter->load16()); - break; - - case OP_LOAD_VAR_INT8: // int8 variable load: - debugN(5, "var8_%d", _vm->_inter->load16()); - break; - - case OP_LOAD_IMM_INT32: // int32/uint32 immediate - debugN(5, "%d", READ_LE_UINT32(_vm->_global->_inter_execPtr)); - _vm->_global->_inter_execPtr += 4; - break; - - case OP_LOAD_IMM_INT16: // int16 immediate - debugN(5, "%d", _vm->_inter->load16()); - break; - - case OP_LOAD_IMM_INT8: // int8 immediate - debugN(5, "%d", (int8) *_vm->_global->_inter_execPtr++); - break; - - case OP_LOAD_IMM_STR: // string immediate - debugN(5, "\42%s\42", _vm->_global->_inter_execPtr); - _vm->_global->_inter_execPtr += - strlen((char *) _vm->_global->_inter_execPtr) + 1; - break; - - case 23: // uint32 variable load - case 24: // uint32 variable load as uint16 - debugN(5, "var_%d", _vm->_inter->load16()); - break; - - case OP_LOAD_VAR_STR: // string variable load - debugN(5, "(&var_%d)", _vm->_inter->load16()); - if (*_vm->_global->_inter_execPtr == 13) { - _vm->_global->_inter_execPtr++; - debugN(5, "{"); - printExpr_internal(OP_END_MARKER); // this also prints the closing } - } - break; - - case OP_ARRAY_UINT8: // uint8 array access - case OP_ARRAY_UINT32: // uint32 array access - case OP_ARRAY_UINT16: // uint16 array access - case OP_ARRAY_STR: // string array access - debugN(5, "\n"); - if (operation == OP_ARRAY_STR) - debugN(5, "(&"); - - debugN(5, "var_%d[", _vm->_inter->load16()); - dimCount = *_vm->_global->_inter_execPtr++; - arrDesc = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += dimCount; - for (dim = 0; dim < dimCount; dim++) { - printExpr_internal(OP_END_MARKER); - debugN(5, " of %d", (int16) arrDesc[dim]); - if (dim != dimCount - 1) - debugN(5, ","); - } - debugN(5, "]"); - if (operation == OP_ARRAY_STR) - debugN(5, ")"); - - if ((operation == OP_ARRAY_STR) && (*_vm->_global->_inter_execPtr == 13)) { - _vm->_global->_inter_execPtr++; - debugN(5, "{"); - printExpr_internal(OP_END_MARKER); // this also prints the closing } - } - break; - - case OP_FUNC: // function - func = *_vm->_global->_inter_execPtr++; - if (func == FUNC_SQR) - debugN(5, "sqr("); - else if (func == FUNC_RAND) - debugN(5, "rand("); - else if (func == FUNC_ABS) - debugN(5, "abs("); - else if ((func == FUNC_SQRT1) || (func == FUNC_SQRT2) || (func == FUNC_SQRT3)) - debugN(5, "sqrt("); - else - debugN(5, "id("); - printExpr_internal(OP_END_EXPR); - break; - } - continue; - } // if ((operation >= OP_ARRAY_UINT8) && (operation <= OP_FUNC)) - - // operators - switch (operation) { - case OP_BEGIN_EXPR: - debugN(5, "("); - break; - - case OP_NOT: - debugN(5, "!"); - break; - - case OP_END_EXPR: - debugN(5, ")"); - break; - - case OP_NEG: - debugN(5, "-"); - break; - - case OP_ADD: - debugN(5, "+"); - break; - - case OP_SUB: - debugN(5, "-"); - break; - - case OP_BITOR: - debugN(5, "|"); - break; - - case OP_MUL: - debugN(5, "*"); - break; - - case OP_DIV: - debugN(5, "/"); - break; - - case OP_MOD: - debugN(5, "%%"); - break; - - case OP_BITAND: - debugN(5, "&"); - break; - - case OP_OR: - debugN(5, "||"); - break; - - case 31: - debugN(5, "&&"); - break; - - case OP_LESS: - debugN(5, "<"); - break; - - case OP_LEQ: - debugN(5, "<="); - break; - - case OP_GREATER: - debugN(5, ">"); - break; - - case OP_GEQ: - debugN(5, ">="); - break; - - case OP_EQ: - debugN(5, "=="); - break; - - case OP_NEQ: - debugN(5, "!="); - break; - - case 99: - debugN(5, "\n"); - break; - - case OP_END_MARKER: - debugN(5, "}"); - if (stopToken != OP_END_MARKER) { - debugN(5, "Closing paren without opening?"); - } - break; - - default: - debugN(5, "<%d>", (int16) operation); - error("Parse::printExpr(): invalid operator in expression"); - break; - } - - if (operation == OP_BEGIN_EXPR) { - num++; - continue; - } - - if ((operation == OP_NOT) || ((operation >= OP_NEG) && (operation <= 8))) - continue; - - if ((operation >= OP_OR) && (operation <= OP_NEQ)) - continue; - - if (operation == OP_END_EXPR) - num--; - - if (operation == stopToken) { - if ((stopToken != OP_END_EXPR) || (num < 0)) { - return; - } - } - } -} - - -void Parse::printVarIndex() { - byte *arrDesc; - int16 dim; - int16 dimCount; - int16 operation; - int16 temp; - - byte *pos = _vm->_global->_inter_execPtr; - - operation = *_vm->_global->_inter_execPtr++; - switch (operation) { - case 23: - case OP_LOAD_VAR_STR: - temp = _vm->_inter->load16() * 4; - debugN(5, "&var_%d", temp); - if ((operation == OP_LOAD_VAR_STR) && (*_vm->_global->_inter_execPtr == 13)) { - _vm->_global->_inter_execPtr++; - debugN(5, "+"); - printExpr(OP_END_MARKER); - } - break; - - case OP_ARRAY_UINT32: - case OP_ARRAY_STR: - debugN(5, "&var_%d[", _vm->_inter->load16()); - dimCount = *_vm->_global->_inter_execPtr++; - arrDesc = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += dimCount; - for (dim = 0; dim < dimCount; dim++) { - printExpr(OP_END_MARKER); - debugN(5, " of %d", (int16) arrDesc[dim]); - if (dim != dimCount - 1) - debugN(5, ","); - } - debugN(5, "]"); - - if ((operation == OP_ARRAY_STR) && (*_vm->_global->_inter_execPtr == 13)) { - _vm->_global->_inter_execPtr++; - debugN(5, "+"); - printExpr(OP_END_MARKER); - } - break; - - default: - debugN(5, "var_0"); - break; - } - debugN(5, "\n"); - _vm->_global->_inter_execPtr = pos; - return; -} - -int16 Parse::getOffset(int16 arg_0, byte arg_2, uint32 arg_3, uint16 arg_7, uint16 arg_9) { - if (arg_0 < 0) - return 0; - - if (arg_2 > arg_0) - return arg_0; - - return arg_2 - 1; -} - -int Parse::cmpHelper(byte *operPtr, int32 *valPtr) { - byte var_C = operPtr[-3]; - int cmpTemp = 0; - if (var_C == OP_LOAD_IMM_INT16) { - cmpTemp = (int)valPtr[-3] - (int)valPtr[-1]; - } else if (var_C == OP_LOAD_IMM_STR) { - if ((char *)decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) { - strcpy(_vm->_global->_inter_resStr, (char *)decodePtr(valPtr[-3])); - valPtr[-3] = encodePtr((byte *) _vm->_global->_inter_resStr, kResStr); - } - cmpTemp = strcmp(_vm->_global->_inter_resStr, (char *)decodePtr(valPtr[-1])); - } - - return cmpTemp; -} - -int16 Parse::parseVarIndex(uint16 *arg_0, uint16 *arg_4) { - int16 temp2; - byte *arrDesc; - int16 dim; - int16 dimCount; - int16 operation; - int16 temp; - int16 offset; - int16 val; - uint32 varPos = 0; - - operation = *_vm->_global->_inter_execPtr++; - - while ((operation == 14) || (operation == 15)) { - if (operation == 14) { - uint16 n = _vm->_inter->load16(); - varPos += n * 4; - - if (arg_0) - *arg_0 = READ_LE_UINT16(_vm->_global->_inter_execPtr); - if (arg_4) - *arg_4 = 14; - - _vm->_global->_inter_execPtr += 2; - - debugC(2, kDebugParser, "parseVarIndex: Prefix %d (%d)", varPos, operation); - - if (*_vm->_global->_inter_execPtr != 97) - return varPos; - - _vm->_global->_inter_execPtr++; - - } else if (operation == 15) { - uint16 n = _vm->_inter->load16(); - varPos += n * 4; - - uint16 var_0C = _vm->_inter->load16(); - if (arg_0) - *arg_0 = var_0C; - if (arg_4) - *arg_4 = 15; - - uint8 var_A = *_vm->_global->_inter_execPtr++; - - byte *var_12 = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += var_A; - - uint16 var_6 = 0; - - for (int i = 0; i < var_A; i++) { - temp2 = parseValExpr(OP_END_MARKER); - - int16 ax = getOffset(temp2, var_12[i], varPos, 0, 0); - - var_6 = var_6 * var_12[i] + ax; - } - - varPos += var_6 * var_0C * 4; - - debugC(2, kDebugParser, "parseVarIndex: Prefix %d (%d)", varPos, operation); - - if (*_vm->_global->_inter_execPtr != 97) - return varPos; - - _vm->_global->_inter_execPtr++; - } - - operation = *_vm->_global->_inter_execPtr++; - } - - if (arg_0) - *arg_0 = 0; - if (arg_4) - *arg_4 = operation; - - debugC(5, kDebugParser, "var parse = %d", operation); - switch (operation) { - case OP_ARRAY_UINT8: - case OP_ARRAY_UINT32: - case OP_ARRAY_UINT16: - case OP_ARRAY_STR: - temp = _vm->_inter->load16(); - dimCount = *_vm->_global->_inter_execPtr++; - arrDesc = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += dimCount; - offset = 0; - for (dim = 0; dim < dimCount; dim++) { - temp2 = parseValExpr(OP_END_MARKER); - offset = arrDesc[dim] * offset + temp2; - } - if (operation == OP_ARRAY_UINT8) - return varPos + temp + offset; - if (operation == OP_ARRAY_UINT32) - return varPos + (temp + offset) * 4; - if (operation == OP_ARRAY_UINT16) - return varPos + (temp + offset) * 2; - temp *= 4; - offset *= 4; - if (*_vm->_global->_inter_execPtr == 13) { - _vm->_global->_inter_execPtr++; - temp += parseValExpr(OP_END_MARKER); - } - return varPos + offset * _vm->_global->_inter_animDataSize + temp; - - case OP_LOAD_VAR_INT16: - return varPos + _vm->_inter->load16() * 2; - - case OP_LOAD_VAR_INT8: - return varPos + _vm->_inter->load16(); - - case 23: - case 24: - case OP_LOAD_VAR_STR: - temp = _vm->_inter->load16() * 4; - debugC(5, kDebugParser, "oper = %d", - (int16) *_vm->_global->_inter_execPtr); - if ((operation == OP_LOAD_VAR_STR) && (*_vm->_global->_inter_execPtr == 13)) { - _vm->_global->_inter_execPtr++; - val = parseValExpr(OP_END_MARKER); - temp += val; - debugC(5, kDebugParser, "parse subscript = %d", val); - } - return varPos + temp; - - default: - return 0; - } -} - -int16 Parse::parseValExpr(byte stopToken) { - int16 values[20]; - byte operStack[20]; - int16 *valPtr; - byte *operPtr; - byte *arrDesc; - byte operation; - int16 temp2; - int16 dim; - int16 dimCount; - int16 temp; - int16 offset; - int16 stkPos; - int16 brackPos; - static int16 flag = 0; - int16 oldflag; - uint32 varPos = 0; - - memset(values, 0, 20 * sizeof(int16)); - - oldflag = flag; - if (flag == 0) { - flag = 1; - printExpr(stopToken); - } - - stkPos = -1; - operPtr = operStack - 1; - valPtr = values - 1; - - while (1) { - operation = *_vm->_global->_inter_execPtr++; - - while ((operation == 14) || (operation == 15)) { - if (operation == 14) { - uint16 n = _vm->_inter->load16(); - varPos += n * 4; - - _vm->_global->_inter_execPtr += 3; - } else if (operation == 15) { - uint16 n = _vm->_inter->load16(); - varPos += n * 4; - - uint16 var_0C = _vm->_inter->load16(); - uint8 var_A = *_vm->_global->_inter_execPtr++; - - byte *var_12 = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += var_A; - - uint16 var_6 = 0; - - for (int i = 0; i < var_A; i++) { - temp2 = parseValExpr(OP_END_MARKER); - - int16 ax = getOffset(temp2, var_12[i], varPos, 0, 0); - - var_6 = var_6 * var_12[i] + ax; - } - - varPos += var_6 * var_0C * 4; - - _vm->_global->_inter_execPtr++; - } - - debugC(2, kDebugParser, "parseValExpr: Prefix %d (%d)", varPos, operation); - - operation = *_vm->_global->_inter_execPtr++; - } - - stkPos++; - operPtr++; - valPtr++; - - if ((operation >= OP_ARRAY_UINT8) && (operation <= OP_FUNC)) { - *operPtr = OP_LOAD_IMM_INT16; - switch (operation) { - case OP_ARRAY_UINT8: - case OP_ARRAY_UINT32: - case OP_ARRAY_UINT16: - case OP_ARRAY_STR: - temp = _vm->_inter->load16(); - dimCount = *_vm->_global->_inter_execPtr++; - arrDesc = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += dimCount; - offset = 0; - for (dim = 0; dim < dimCount; dim++) { - temp2 = parseValExpr(OP_END_MARKER); - offset = arrDesc[dim] * offset + temp2; - } - if (operation == OP_ARRAY_UINT8) - *valPtr = (int8) READ_VARO_UINT8(varPos + temp + offset); - else if (operation == OP_ARRAY_UINT32) - *valPtr = (uint16) READ_VARO_UINT32(varPos + temp * 4 + offset * 4); - else if (operation == OP_ARRAY_UINT16) - *valPtr = READ_VARO_UINT16(varPos + temp * 2 + offset * 2); - else if (operation == OP_ARRAY_STR) { - _vm->_global->_inter_execPtr++; - temp2 = parseValExpr(OP_END_MARKER); - *valPtr = READ_VARO_UINT8(varPos + temp * 4 + - offset * 4 * _vm->_global->_inter_animDataSize + temp2); - } - break; - - case OP_LOAD_VAR_INT16: - *valPtr = READ_VARO_UINT16(varPos + _vm->_inter->load16() * 2); - break; - - case OP_LOAD_VAR_INT8: - *valPtr = (int8) READ_VARO_UINT8(varPos + _vm->_inter->load16()); - break; - - case OP_LOAD_IMM_INT32: - *valPtr = (uint16) READ_LE_UINT32(varPos + _vm->_global->_inter_execPtr); - _vm->_global->_inter_execPtr += 4; - break; - - case OP_LOAD_IMM_INT16: - *valPtr = _vm->_inter->load16(); - break; - - case OP_LOAD_IMM_INT8: - *valPtr = (int8) *_vm->_global->_inter_execPtr++; - break; - - case 23: - *valPtr = (uint16) READ_VARO_UINT32(varPos + _vm->_inter->load16() * 4); - break; - - case 24: - *valPtr = READ_VARO_UINT16(varPos + _vm->_inter->load16() * 4); - break; - - case OP_LOAD_VAR_STR: - temp = _vm->_inter->load16() * 4; - _vm->_global->_inter_execPtr++; - temp += parseValExpr(OP_END_MARKER); - *valPtr = READ_VARO_UINT8(varPos + temp); - break; - - case OP_FUNC: - operation = *_vm->_global->_inter_execPtr++; - parseExpr(OP_END_EXPR, 0); - - if (operation == FUNC_SQR) { - _vm->_global->_inter_resVal = - _vm->_global->_inter_resVal * _vm->_global->_inter_resVal; - } else if (operation == FUNC_ABS) { - if (_vm->_global->_inter_resVal < 0) - _vm->_global->_inter_resVal = -_vm->_global->_inter_resVal; - } else if (operation == FUNC_RAND) { - _vm->_global->_inter_resVal = - _vm->_util->getRandom(_vm->_global->_inter_resVal); - } - *valPtr = _vm->_global->_inter_resVal; - break; - - } // switch - if ((stkPos > 0) && (operPtr[-1] == OP_NEG)) { - stkPos--; - operPtr--; - valPtr--; - operPtr[0] = OP_LOAD_IMM_INT16; - valPtr[0] = -valPtr[1]; - } - - if ((stkPos > 0) && (operPtr[-1] >= OP_MUL) && (operPtr[-1] <= OP_BITAND)) { - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - - switch (operPtr[1]) { - case OP_MUL: - valPtr[0] *= valPtr[2]; - break; - - case OP_DIV: - valPtr[0] /= valPtr[2]; - break; - - case OP_MOD: - valPtr[0] %= valPtr[2]; - break; - - case OP_BITAND: - valPtr[0] &= valPtr[2]; - break; - } - } // if ((stkPos > 0) && (cmdPtr[-1] >= OP_MUL) && (cmdPtr[-1] <= OP_BITAND)) - varPos = 0; - continue; - } - - if ((operation >= OP_NEG) && (operation <= OP_BEGIN_EXPR)) { - *operPtr = operation; - continue; - } - - while (stkPos >= 2) { - if (operPtr[-2] == OP_BEGIN_EXPR) { - stkPos--; - operPtr--; - valPtr--; - - operPtr[-1] = operPtr[0]; - valPtr[-1] = valPtr[0]; - if ((stkPos > 1) && (operPtr[-2] == OP_NEG)) { - operPtr[-2] = OP_LOAD_IMM_INT16; - valPtr[-2] = -valPtr[-1]; - - stkPos--; - operPtr--; - valPtr--; - } - - if ((stkPos > 2) && (operPtr[-2] >= OP_MUL) && (operPtr[-2] <= OP_BITAND)) { - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - switch (operPtr[0]) { - case OP_MUL: - valPtr[-1] *= valPtr[1]; - break; - - case OP_DIV: - valPtr[-1] /= valPtr[1]; - break; - - case OP_MOD: - valPtr[-1] %= valPtr[1]; - break; - - case OP_BITAND: - valPtr[-1] &= valPtr[1]; - break; - } - } - if (operation == OP_END_EXPR) - break; - } // operPtr[-2] == OP_BEGIN_EXPR - - for (brackPos = (stkPos - 2); (brackPos > 0) && - (operStack[brackPos] < OP_OR) && (operStack[brackPos] != OP_BEGIN_EXPR); - brackPos--) - ; - - if ((operStack[brackPos] >= OP_OR) || (operStack[brackPos] == OP_BEGIN_EXPR)) - brackPos++; - - if ((operPtr[-2] < 2) || (operPtr[-2] > 8)) - break; - - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - switch (operPtr[0]) { - case OP_ADD: - values[brackPos] += valPtr[1]; - continue; - case OP_SUB: - values[brackPos] -= valPtr[1]; - continue; - case OP_BITOR: - values[brackPos] |= valPtr[1]; - continue; - case OP_MUL: - valPtr[-1] *= valPtr[1]; - continue; - case OP_DIV: - valPtr[-1] /= valPtr[1]; - continue; - case OP_MOD: - valPtr[-1] %= valPtr[1]; - continue; - case OP_BITAND: - valPtr[-1] &= valPtr[1]; - continue; - } - } - - if (operation != OP_END_EXPR) { - if (operation != stopToken) { - debugC(5, kDebugParser, "stoptoken error: %d != %d", - operation, stopToken); - } - flag = oldflag; - return values[0]; - } - - stkPos--; - operPtr--; - valPtr--; - } -} - -int16 Parse::parseExpr(byte stopToken, byte *arg_2) { - int32 values[20]; - byte operStack[20]; - int32 prevPrevVal; - int32 prevVal; - int32 curVal; - int32 *valPtr; - byte *operPtr; - byte *arrDescPtr; - byte operation; - int16 dimCount; - int16 temp; - int16 temp2; - int16 offset; - int16 dim; - bool var_1A; - int16 stkPos; - int16 brackStart; - uint32 varPos = 0; - - memset(operStack, 0, 20); - - stkPos = -1; - operPtr = operStack - 1; - valPtr = values - 1; - - while (true) { - operation = *_vm->_global->_inter_execPtr++; - - while ((operation == 14) || (operation == 15)) { - if (operation == 14) { - uint16 n = _vm->_inter->load16(); - varPos += n * 4; - - _vm->_global->_inter_execPtr += 2; - if (*_vm->_global->_inter_execPtr == 97) - _vm->_global->_inter_execPtr++; - } else if (operation == 15) { - uint16 n = _vm->_inter->load16(); - varPos += n * 4; - - uint16 var_0C = _vm->_inter->load16(); - uint8 var_A = *_vm->_global->_inter_execPtr++; - - byte *var_12 = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += var_A; - - uint16 var_6 = 0; - - for (int i = 0; i < var_A; i++) { - temp2 = parseValExpr(OP_END_MARKER); - - int16 ax = getOffset(temp2, var_12[i], varPos, 0, 0); - - var_6 = var_6 * var_12[i] + ax; - } - - varPos += var_6 * var_0C * 4; - - if (*_vm->_global->_inter_execPtr == 97) - _vm->_global->_inter_execPtr++; - } - - debugC(2, kDebugParser, "parseExpr: Prefix %d (%d)", varPos, operation); - - operation = *_vm->_global->_inter_execPtr++; - } - - stkPos++; - operPtr++; - valPtr++; - - if ((operation >= OP_ARRAY_UINT8) && (operation <= OP_FUNC)) { - switch (operation) { - case OP_ARRAY_UINT8: - case OP_ARRAY_UINT32: - case OP_ARRAY_UINT16: - case OP_ARRAY_STR: - *operPtr = (operation == OP_ARRAY_STR) ? OP_LOAD_IMM_STR : OP_LOAD_IMM_INT16; - temp = _vm->_inter->load16(); - dimCount = *_vm->_global->_inter_execPtr++; - arrDescPtr = _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += dimCount; - offset = 0; - for (dim = 0; dim < dimCount; dim++) { - temp2 = parseValExpr(OP_END_MARKER); - offset = offset * arrDescPtr[dim] + temp2; - } - if (operation == OP_ARRAY_UINT8) - *valPtr = (int8) READ_VARO_UINT8(varPos + temp + offset); - else if (operation == OP_ARRAY_UINT32) - *valPtr = READ_VARO_UINT32(varPos + temp * 4 + offset * 4); - else if (operation == OP_ARRAY_UINT16) - *valPtr = (int16) READ_VARO_UINT16(varPos + temp * 2 + offset * 2); - else if (operation == OP_ARRAY_STR) { - *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8( - varPos + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4), - kInterVar); - if (*_vm->_global->_inter_execPtr == 13) { - _vm->_global->_inter_execPtr++; - temp2 = parseValExpr(OP_END_MARKER); - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = READ_VARO_UINT8(varPos + temp * 4 + - offset * 4 * _vm->_global->_inter_animDataSize + temp2); - } - } - break; - - case OP_LOAD_VAR_INT16: - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = (int16) READ_VARO_UINT16(varPos + _vm->_inter->load16() * 2); - break; - - case OP_LOAD_VAR_INT8: - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = (int8) READ_VARO_UINT8(varPos + _vm->_inter->load16()); - break; - - case OP_LOAD_IMM_INT32: - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = READ_LE_UINT32(varPos + _vm->_global->_inter_execPtr); - _vm->_global->_inter_execPtr += 4; - break; - - case OP_LOAD_IMM_INT16: - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = _vm->_inter->load16(); - break; - - case OP_LOAD_IMM_INT8: - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = (int8) *_vm->_global->_inter_execPtr++; - break; - - case OP_LOAD_IMM_STR: - *operPtr = OP_LOAD_IMM_STR; - *valPtr = encodePtr(_vm->_global->_inter_execPtr, kExecPtr); - _vm->_global->_inter_execPtr += - strlen((char *) _vm->_global->_inter_execPtr) + 1; - break; - - case 23: - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = READ_VARO_UINT32(varPos + _vm->_inter->load16() * 4); - break; - - case 24: - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = (int16) READ_VARO_UINT16(varPos + _vm->_inter->load16() * 4); - break; - - case OP_LOAD_VAR_STR: - *operPtr = OP_LOAD_IMM_STR; - temp = _vm->_inter->load16() * 4; - *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(varPos + temp), kInterVar); - if (*_vm->_global->_inter_execPtr == 13) { - _vm->_global->_inter_execPtr++; - temp += parseValExpr(OP_END_MARKER); - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = READ_VARO_UINT8(varPos + temp); - } - break; - - case OP_FUNC: - operation = *_vm->_global->_inter_execPtr++; - parseExpr(OP_END_EXPR, 0); - - switch (operation) { - case FUNC_SQRT1: - case FUNC_SQRT2: - case FUNC_SQRT3: - curVal = 1; - prevVal = 1; - - do { - prevPrevVal = prevVal; - prevVal = curVal; - curVal = (curVal + _vm->_global->_inter_resVal / curVal) / 2; - } while ((curVal != prevVal) && (curVal != prevPrevVal)); - _vm->_global->_inter_resVal = curVal; - break; - - case FUNC_SQR: - _vm->_global->_inter_resVal = - _vm->_global->_inter_resVal * _vm->_global->_inter_resVal; - break; - - case FUNC_ABS: - if (_vm->_global->_inter_resVal < 0) - _vm->_global->_inter_resVal = -_vm->_global->_inter_resVal; - break; - - case FUNC_RAND: - _vm->_global->_inter_resVal = - _vm->_util->getRandom(_vm->_global->_inter_resVal); - break; - } - - *operPtr = OP_LOAD_IMM_INT16; - *valPtr = _vm->_global->_inter_resVal; - break; - } - - if ((stkPos > 0) && ((operPtr[-1] == OP_NEG) || (operPtr[-1] == OP_NOT))) { - stkPos--; - operPtr--; - valPtr--; - - if (*operPtr == OP_NEG) { - *operPtr = OP_LOAD_IMM_INT16; - valPtr[0] = -valPtr[1]; - } else - *operPtr = (operPtr[1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; - } - - if (stkPos <= 0) { - varPos = 0; - continue; - } - - switch (operPtr[-1]) { - case OP_ADD: - if (operPtr[-2] == OP_LOAD_IMM_STR) { - if ((char *) decodePtr(valPtr[-2]) != _vm->_global->_inter_resStr) { - strcpy(_vm->_global->_inter_resStr, (char *) decodePtr(valPtr[-2])); - valPtr[-2] = encodePtr((byte *) _vm->_global->_inter_resStr, kResStr); - } - strcat(_vm->_global->_inter_resStr, (char *) decodePtr(valPtr[0])); - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - } - break; - - case OP_MUL: - valPtr[-2] *= valPtr[0]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_DIV: - valPtr[-2] /= valPtr[0]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_MOD: - valPtr[-2] %= valPtr[0]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_BITAND: - valPtr[-2] &= valPtr[0]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - } - varPos = 0; - continue; - } // (op >= OP_ARRAY_UINT8) && (op <= OP_FUNC) - - if ((operation == stopToken) || (operation == OP_OR) || - (operation == OP_AND) || (operation == OP_END_EXPR)) { - while (stkPos >= 2) { - var_1A = false; - if ((operPtr[-2] == OP_BEGIN_EXPR) && - ((operation == OP_END_EXPR) || (operation == stopToken))) { - operPtr[-2] = operPtr[-1]; - if ((operPtr[-2] == OP_LOAD_IMM_INT16) || (operPtr[-2] == OP_LOAD_IMM_STR)) - valPtr[-2] = valPtr[-1]; - - stkPos--; - operPtr--; - valPtr--; - - if (stkPos > 1) { - if (operPtr[-2] == OP_NEG) { - operPtr[-2] = OP_LOAD_IMM_INT16; - valPtr[-2] = -valPtr[-1]; - stkPos--; - operPtr--; - valPtr--; - } else if (operPtr[-2] == OP_NOT) { - operPtr[-2] = (operPtr[-1] == GOB_FALSE) ? GOB_TRUE : GOB_FALSE; - stkPos--; - operPtr--; - valPtr--; - } - } // stkPos > 1 - - if (stkPos > 2) { - switch (operPtr[-2]) { - case OP_MUL: - valPtr[-3] *= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_DIV: - valPtr[-3] /= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_MOD: - valPtr[-3] %= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_BITAND: - valPtr[-3] &= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - } // switch - } // stkPos > 2 - - if (operation != stopToken) - break; - } // if ((operPtr[-2] == OP_BEGIN_EXPR) && ...) - - for (brackStart = (stkPos - 2); (brackStart > 0) && - (operStack[brackStart] < OP_OR) && (operStack[brackStart] != OP_BEGIN_EXPR); - brackStart--) - ; - - if ((operStack[brackStart] >= OP_OR) || (operStack[brackStart] == OP_BEGIN_EXPR)) - brackStart++; - - switch (operPtr[-2]) { - case OP_ADD: - if (operStack[brackStart] == OP_LOAD_IMM_INT16) { - values[brackStart] += valPtr[-1]; - } else if (operStack[brackStart] == OP_LOAD_IMM_STR) { - if ((char *) decodePtr(values[brackStart]) != _vm->_global->_inter_resStr) { - strcpy(_vm->_global->_inter_resStr, (char *) decodePtr(values[brackStart])); - values[brackStart] = - encodePtr((byte *) _vm->_global->_inter_resStr, kResStr); - } - strcat(_vm->_global->_inter_resStr, (char *) decodePtr(valPtr[-1])); - } - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - continue; - - case OP_SUB: - values[brackStart] -= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - continue; - - case OP_BITOR: - values[brackStart] |= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - continue; - - case OP_MUL: - valPtr[-3] *= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_DIV: - valPtr[-3] /= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_MOD: - valPtr[-3] %= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_BITAND: - valPtr[-3] &= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_OR: - // (x OR false) == x - // (x OR true) == true - if (operPtr[-3] == GOB_FALSE) - operPtr[-3] = operPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_AND: - // (x AND false) == false - // (x AND true) == x - if (operPtr[-3] == GOB_TRUE) - operPtr[-3] = operPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_LESS: - operPtr[-3] = (cmpHelper(operPtr, valPtr) < 0) ? GOB_TRUE : GOB_FALSE; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_LEQ: - operPtr[-3] = (cmpHelper(operPtr, valPtr) <= 0) ? GOB_TRUE : GOB_FALSE; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_GREATER: - operPtr[-3] = (cmpHelper(operPtr, valPtr) > 0) ? GOB_TRUE : GOB_FALSE; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_GEQ: - operPtr[-3] = (cmpHelper(operPtr, valPtr) >= 0) ? GOB_TRUE : GOB_FALSE; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_EQ: - operPtr[-3] = (cmpHelper(operPtr, valPtr) == 0) ? GOB_TRUE : GOB_FALSE; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - - case OP_NEQ: { - int cmpTemp = 0; - - if (operPtr[-3] == OP_LOAD_IMM_INT16) { - cmpTemp = valPtr[-3] - valPtr[-1]; - } else if (operPtr[-3] == OP_LOAD_IMM_STR) { - if ((char *) decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) { - strcpy(_vm->_global->_inter_resStr, (char *) decodePtr(valPtr[-3])); - valPtr[-3] = encodePtr((byte *) _vm->_global->_inter_resStr, kResStr); - } - // FIXME: Why scumm_stricmp here and strcmp everywhere else? - cmpTemp = scumm_stricmp(_vm->_global->_inter_resStr, (char *) decodePtr(valPtr[-1])); - } - operPtr[-3] = (cmpTemp != 0) ? GOB_TRUE : GOB_FALSE; - //operPtr[-3] = (cmpHelper(operPtr, valPtr) != 0) ? GOB_TRUE : GOB_FALSE; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - break; - } - - default: - var_1A = true; - break; - } // switch - - if (var_1A) - break; - } // while (stkPos >= 2) - - if ((operation == OP_OR) || (operation == OP_AND)) { - if (operPtr[-1] == OP_LOAD_IMM_INT16) { - if (valPtr[-1] != 0) - operPtr[-1] = GOB_TRUE; - else - operPtr[-1] = GOB_FALSE; - } - - if (((operation == OP_OR) && (operPtr[-1] == GOB_TRUE)) || - ((operation == OP_AND) && (operPtr[-1] == GOB_FALSE))) { - if ((stkPos > 1) && (operPtr[-2] == OP_BEGIN_EXPR)) { - skipExpr(OP_END_EXPR); - operPtr[-2] = operPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - } else { - skipExpr(stopToken); - } - operation = _vm->_global->_inter_execPtr[-1]; - if ((stkPos > 0) && (operPtr[-1] == OP_NOT)) { - if (operPtr[0] == GOB_FALSE) - operPtr[-1] = GOB_TRUE; - else - operPtr[-1] = GOB_FALSE; - - stkPos--; - operPtr--; - valPtr--; - } - } else - operPtr[0] = operation; - } else { - stkPos--; - operPtr--; - valPtr--; - } - - if (operation != stopToken) - continue; - - if (arg_2 != 0) - *arg_2 = operStack[0]; - - switch (operStack[0]) { - case OP_NOT: - if (arg_2 != 0) - *arg_2 ^= 1; - break; - - case OP_LOAD_IMM_INT16: - _vm->_global->_inter_resVal = values[0]; - break; - - case OP_LOAD_IMM_STR: - if ((char *) decodePtr(values[0]) != _vm->_global->_inter_resStr) - strcpy(_vm->_global->_inter_resStr, (char *) decodePtr(values[0])); - break; - - case 23: - case 24: - break; - - default: - _vm->_global->_inter_resVal = 0; - if (arg_2 != 0) - *arg_2 = OP_LOAD_IMM_INT16; - break; - } - return 0; - } // (operation == stopToken) || (operation == OP_OR) || (operation == OP_AND) || (operation == OP_END_EXPR) - - if ((operation < OP_NEG) || (operation > OP_NOT)) { - if ((operation < OP_LESS) || (operation > OP_NEQ)) - continue; - - if (stkPos > 2) { - if (operPtr[-2] == OP_ADD) { - if (operPtr[-3] == OP_LOAD_IMM_INT16) { - valPtr[-3] += valPtr[-1]; - } else if (operPtr[-3] == OP_LOAD_IMM_STR) { - if ((char *) decodePtr(valPtr[-3]) != _vm->_global->_inter_resStr) { - strcpy(_vm->_global->_inter_resStr, (char *) decodePtr(valPtr[-3])); - valPtr[-3] = encodePtr((byte *) _vm->_global->_inter_resStr, kResStr); - } - strcat(_vm->_global->_inter_resStr, (char *) decodePtr(valPtr[-1])); - } - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - - } else if (operPtr[-2] == OP_SUB) { - valPtr[-3] -= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - } else if (operPtr[-2] == OP_BITOR) { - valPtr[-3] |= valPtr[-1]; - stkPos -= 2; - operPtr -= 2; - valPtr -= 2; - } - } - } - *operPtr = operation; - } -} - -} // End of namespace Gob diff --git a/engines/gob/parse.h b/engines/gob/parse.h deleted file mode 100644 index 01f5762b6d..0000000000 --- a/engines/gob/parse.h +++ /dev/null @@ -1,128 +0,0 @@ -/* 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 GOB_PARSE_H -#define GOB_PARSE_H - -namespace Gob { - -enum { - OP_NEG = 1, - OP_ADD = 2, - OP_SUB = 3, - OP_BITOR = 4, - OP_MUL = 5, - OP_DIV = 6, - OP_MOD = 7, - OP_BITAND = 8, - OP_BEGIN_EXPR = 9, - OP_END_EXPR = 10, - OP_NOT = 11, - - OP_END_MARKER = 12, // Marks end of an array or string - - - OP_ARRAY_UINT8 = 16, - - OP_LOAD_VAR_INT16 = 17, - OP_LOAD_VAR_INT8 = 18, - OP_LOAD_IMM_INT32 = 19, - OP_LOAD_IMM_INT16 = 20, - OP_LOAD_IMM_INT8 = 21, - OP_LOAD_IMM_STR = 22, - - OP_LOAD_VAR_UINT32 = 23, // ??? - OP_LOAD_VAR_UINT32_AS_UINT16 = 24, // ??? - OP_LOAD_VAR_STR = 25, - - OP_ARRAY_UINT32 = 26, - OP_ARRAY_UINT16 = 27, - OP_ARRAY_STR = 28, - - OP_FUNC = 29, - - OP_OR = 30, // Logical OR - OP_AND = 31, // Logical AND - OP_LESS = 32, - OP_LEQ = 33, - OP_GREATER = 34, - OP_GEQ = 35, - OP_EQ = 36, - OP_NEQ = 37 -}; - -enum { - FUNC_SQRT1 = 0, - FUNC_SQRT2 = 1, - FUNC_SQRT3 = 6, - - FUNC_SQR = 5, - FUNC_ABS = 7, - FUNC_RAND = 10 -}; - -enum { - // FIXME: The following two 'truth values' are stored inside the list - // of "operators". So they somehow coincide with OP_LOAD_VAR_UINT32 - // and OP_LOAD_VAR_UINT32_AS_UINT16. I haven't yet quite understood - // how, resp. what that means. You have been warned. - GOB_TRUE = 24, - GOB_FALSE = 23 -}; - -class Parse { -public: - void skipExpr(char stopToken); - void printExpr(char stopToken); - void printVarIndex(void); - - int16 parseVarIndex(uint16 *arg_0 = 0, uint16 *arg_4 = 0); - int16 parseValExpr(byte stopToken = 99); - int16 parseExpr(byte stopToken, byte *resultPtr); - - Parse(GobEngine *vm); - virtual ~Parse() {} - -private: - enum PointerType { - kExecPtr = 0, - kInterVar = 1, - kResStr = 2 - }; - - GobEngine *_vm; - - int32 encodePtr(byte *ptr, int type); - byte *decodePtr(int32 n); - - void printExpr_internal(char stopToken); - - int16 getOffset(int16 arg_0, byte arg_2, uint32 arg_3, uint16 arg_7, uint16 arg_9); - int cmpHelper(byte *operPtr, int32 *valPtr); -}; - -} // End of namespace Gob - -#endif // GOB_PARSE_H diff --git a/engines/gob/resources.cpp b/engines/gob/resources.cpp new file mode 100644 index 0000000000..20427e547b --- /dev/null +++ b/engines/gob/resources.cpp @@ -0,0 +1,706 @@ +/* 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 "common/util.h" +#include "common/endian.h" +#include "common/stream.h" + +#include "gob/gob.h" +#include "gob/resources.h" +#include "gob/totfile.h" +#include "gob/dataio.h" +#include "gob/game.h" +#include "gob/global.h" + +namespace Gob { + +Resource::Resource(byte *data, int32 size, bool needFree, + int16 width, int16 height) { + + _data = data; + _size = size; + _width = width; + _height = height; + _needFree = needFree; + + _stream = new Common::MemoryReadStream(data, size); +} + +Resource::~Resource() { + delete _stream; + + if (_needFree) + delete[] _data; +} + +byte *Resource::getData() const { + return _data; +} + +int32 Resource::getSize() const { + return _size; +} + +int16 Resource::getWidth() const { + return _width; +} + +int16 Resource::getHeight() const { + return _height; +} + +Common::MemoryReadStream *Resource::stream() const { + return _stream; +} + + +TextItem::TextItem(byte *data, int32 size) { + _data = data; + _size = size; + + _stream = new Common::MemoryReadStream(data, size); +} + +TextItem::~TextItem() { + delete _stream; +} + +byte *TextItem::getData() const { + return _data; +} + +int32 TextItem::getSize() const { + return _size; +} + +Common::MemoryReadStream *TextItem::stream() const { + return _stream; +} + + +Resources::TOTResourceTable::TOTResourceTable() { + items = 0; +} + +Resources::TOTResourceTable::~TOTResourceTable() { + delete[] items; +} + + +Resources::EXTResourceTable::EXTResourceTable() { + itemsCount = 0; + unknown = 0; + items = 0; +} + +Resources::EXTResourceTable::~EXTResourceTable() { + delete[] items; +} + + +Resources::TOTTextTable::TOTTextTable() { + items = 0; + data = 0; + needFree = false; +} + +Resources::TOTTextTable::~TOTTextTable() { + delete[] items; + if (needFree) + delete[] data; +} + + +Resources::Resources(GobEngine *vm) : _vm(vm) { + unload(false); +} + +Resources::~Resources() { + unload(); +} + +bool Resources::load(const Common::String &fileName) { + unload(); + + Common::String fileBase; + + _totFile = TOTFile::createFileName(fileName, _hasLOM); + + if (_hasLOM) { + warning("Stub: Resources::load(%s)", fileName.c_str()); + unload(); + return false; + } + + fileBase = TOTFile::getFileBase(fileName); + + _extFile = fileBase + ".ext"; + + if (!loadTOTResourceTable()) { + unload(); + return false; + } + + if (!loadEXTResourceTable()) { + unload(); + return false; + } + + if (!loadTOTTextTable(fileBase)) { + unload(); + return false; + } + + if (!loadIMFile()) { + unload(); + return false; + } + + if (!loadEXFile()) { + unload(); + return false; + } + + return true; +} + +void Resources::unload(bool del) { + if (del) { + delete _totResourceTable; + delete _extResourceTable; + delete _totTextTable; + + delete[] _totData; + delete[] _imData; + + _totFile.clear(); + _extFile.clear(); + _exFile.clear(); + } + + _totResourceTable = 0; + _extResourceTable = 0; + _totTextTable = 0; + _totData = 0; + _totSize = 0; + _imData = 0; + _imSize = 0; +} + +bool Resources::isLoaded() const { + return (_totResourceTable != 0); +} + +bool Resources::loadTOTResourceTable() { + TOTFile totFile(_vm); + + if (!totFile.load(_totFile)) + return false; + + TOTFile::Properties totProps; + if (!totFile.getProperties(totProps)) + return false; + + Common::SeekableReadStream *stream = totFile.getStream(); + if (!stream) + return false; + + if ((totProps.resourcesOffset == 0xFFFFFFFF) || + (totProps.resourcesOffset == 0)) + // No resources here + return false; + + _totResourceTable = new TOTResourceTable; + + stream->seek(totProps.resourcesOffset); + _totResourceTable->itemsCount = stream->readSint16LE(); + + _totResourceTable->dataOffset = totProps.resourcesOffset + kTOTResTableSize + + _totResourceTable->itemsCount * kTOTResItemSize; + + + uint32 resSize = _totResourceTable->itemsCount * kTOTResItemSize + + kTOTResTableSize; + + // Would the table actually fit into the TOT? + if ((totProps.resourcesOffset + resSize) > ((uint32) stream->size())) + return false; + + _totResourceTable->unknown = stream->readByte(); + _totResourceTable->items = new TOTResourceItem[_totResourceTable->itemsCount]; + + for (int i = 0; i < _totResourceTable->itemsCount; ++i) { + TOTResourceItem &item = _totResourceTable->items[i]; + + item.offset = stream->readSint32LE(); + item.size = stream->readSint16LE(); + item.width = stream->readSint16LE(); + item.height = stream->readSint16LE(); + + if (item.offset < 0) { + item.type = kResourceIM; + item.index = -item.offset - 1; + } else + item.type = kResourceTOT; + } + + _totResStart = totProps.scriptEnd; + _totSize = stream->size() - _totResStart; + if (_totSize <= 0) + return false; + + if (!stream->seek(totProps.scriptEnd)) + return false; + + _totData = new byte[_totSize]; + if (stream->read(_totData, _totSize) != _totSize) + return false; + + return !stream->err(); +} + +bool Resources::loadEXTResourceTable() { + _extResourceTable = new EXTResourceTable; + + DataStream *stream = _vm->_dataIO->getDataStream(_extFile.c_str()); + if (!stream) + return true; + + _extResourceTable->itemsCount = stream->readSint16LE(); + _extResourceTable->unknown = stream->readByte(); + + if (_extResourceTable->itemsCount > 0) + _extResourceTable->items = new EXTResourceItem[_extResourceTable->itemsCount]; + + for (int i = 0; i < _extResourceTable->itemsCount; i++) { + EXTResourceItem &item = _extResourceTable->items[i]; + + item.offset = stream->readUint32LE(); + item.size = stream->readUint16LE(); + item.width = stream->readUint16LE(); + item.height = stream->readUint16LE(); + + if (item.offset < 0) { + item.type = kResourceEX; + item.offset = -item.offset - 1; + } else { + item.type = kResourceEXT; + item.offset += kEXTResTableSize + + kEXTResItemSize * _extResourceTable->itemsCount; + } + + item.packed = (item.width & 0x8000) != 0; + + item.width &= 0x7FFF; + } + + delete stream; + return true; +} + +bool Resources::loadTOTTextTable(const Common::String &fileBase) { + TOTFile totFile(_vm); + + if (!totFile.load(_totFile)) + return false; + + TOTFile::Properties totProps; + if (!totFile.getProperties(totProps)) + return false; + + Common::SeekableReadStream *stream = totFile.getStream(); + if (!stream) + return false; + + if (totProps.textsOffset == ((uint32) -1)) + // No texts + return true; + + _totTextTable = new TOTTextTable; + + bool fromTOT; + if (totProps.textsOffset == 0) { + fromTOT = false; + _totTextTable->data = loadTOTLocTexts(fileBase, _totTextTable->size); + _totTextTable->needFree = true; + } else { + fromTOT = true; + _totTextTable->data = _totData + totProps.textsOffset - _totResStart; + _totTextTable->needFree = false; + _totTextTable->size = _totSize - totProps.textsOffset; + } + + if (_totTextTable->data) { + Common::MemoryReadStream totTextTable(_totTextTable->data, _totTextTable->size); + _totTextTable->itemsCount = totTextTable.readSint16LE() & 0x3FFF; + + _totTextTable->items = new TOTTextItem[_totTextTable->itemsCount]; + for (int i = 0; i < _totTextTable->itemsCount; ++i) { + TOTTextItem &item = _totTextTable->items[i]; + + item.offset = totTextTable.readSint16LE(); + item.size = totTextTable.readSint16LE(); + + if (fromTOT) + item.offset -= (totProps.textsOffset - _totResStart); + } + } + + return true; +} + +bool Resources::loadIMFile() { + TOTFile totFile(_vm); + + if (!totFile.load(_totFile)) + return false; + + TOTFile::Properties totProps; + if (!totFile.getProperties(totProps)) + return false; + + if ((totProps.communHandling != 0) && (totProps.imFileNumber == 0)) + // No IM file + return true; + + Common::String imFile = "commun.im"; + + char num = totProps.imFileNumber + '0'; + if (num == '0') + num = '1'; + + imFile += num; + + DataStream *stream = _vm->_dataIO->getDataStream(imFile.c_str()); + if (!stream) + return true; + + _imSize = stream->size(); + if (_imSize <= 0) { + _imSize = 0; + delete stream; + return true; + } + + _imData = new byte[_imSize]; + if (stream->read(_imData, _imSize) != _imSize) { + delete[] _imData; + _imData = 0; + _imSize = 0; + } + + delete stream; + return true; +} + +bool Resources::loadEXFile() { + TOTFile totFile(_vm); + + if (!totFile.load(_totFile)) + return false; + + TOTFile::Properties totProps; + if (!totFile.getProperties(totProps)) + return false; + + _exFile = "commun.ex"; + _exFile += totProps.exFileNumber + '0'; + + if (!_vm->_dataIO->existData(_exFile.c_str())) { + _exFile.clear(); + return true; + } + + return true; +} + +Common::String Resources::getLocTextFile(const Common::String &fileBase, + int language) { + + Common::String locTextFile = fileBase + "."; + switch (language) { + case kLanguageFrench: + locTextFile += "dat"; + break; + case kLanguageGerman: + locTextFile += "all"; + break; + case kLanguageSpanish: + locTextFile += "esp"; + break; + case kLanguageItalian: + locTextFile += "ita"; + break; + case kLanguageAmerican: + locTextFile += "usa"; + break; + case kLanguageDutch: + locTextFile += "ndl"; + break; + case kLanguageKorean: + locTextFile += "kor"; + break; + case kLanguageHebrew: + locTextFile += "isr"; + break; + default: + locTextFile += "ang"; + break; + } + + if (!_vm->_dataIO->existData(locTextFile.c_str())) + locTextFile.clear(); + + return locTextFile; +} + +byte *Resources::loadTOTLocTexts(const Common::String &fileBase, int32 &size) { + Common::String locTextFile; + + locTextFile = getLocTextFile(fileBase, _vm->_global->_languageWanted); + + if (!locTextFile.empty()) { + + _vm->_global->_foundLanguage = true; + _vm->_global->_language = _vm->_global->_languageWanted; + + } else if (!_vm->_global->_foundLanguage) { + + // Trying US for GB and vice versa + if (_vm->_global->_languageWanted == kLanguageBritish) { + + locTextFile = getLocTextFile(fileBase, kLanguageAmerican); + if (!locTextFile.empty()) + _vm->_global->_language = kLanguageAmerican; + + } else if (_vm->_global->_languageWanted == kLanguageAmerican) { + + locTextFile = getLocTextFile(fileBase, kLanguageBritish); + if (!locTextFile.empty()) + _vm->_global->_language = kLanguageBritish; + + } + + if (locTextFile.empty()) { + // Looking for the first existing language + for (int i = 0; i < 10; i++) { + locTextFile = getLocTextFile(fileBase, i); + if (!locTextFile.empty()) { + _vm->_global->_language = i; + break; + } + } + } + + } + + debugC(1, kDebugFileIO, "Using language %d for %s", + _vm->_global->_language, _totFile.c_str()); + + if (locTextFile.empty()) + return 0; + + size = _vm->_dataIO->getDataSize(locTextFile.c_str()); + return _vm->_dataIO->getData(locTextFile.c_str()); +} + +Resource *Resources::getResource(uint16 id, int16 *width, int16 *height) const { + if (_hasLOM) { + warning("Stub: Resources::getResource(): Has LOM"); + return 0; + } + + Resource *resource = 0; + if (id >= 30000) + resource = getEXTResource(id - 30000); + else + resource = getTOTResource(id); + + if (!resource) + return 0; + + if (width) + *width = resource->getWidth(); + if (height) + *height = resource->getHeight(); + + return resource; +} + +TextItem *Resources::getTextItem(uint16 id) const { + if (!_totTextTable || !_totTextTable->data) + return 0; + + if (id >= _totTextTable->itemsCount) + return 0; + + TOTTextItem &totItem = _totTextTable->items[id]; + + if ((totItem.offset == 0xFFFF) || (totItem.size == 0)) + return 0; + if ((totItem.offset + totItem.size) > (_totTextTable->size)) + return 0; + + return new TextItem(_totTextTable->data + totItem.offset, totItem.size); +} + +byte *Resources::getTexts() const { + if (!_totTextTable) + return 0; + + return _totTextTable->data; +} + +Resource *Resources::getTOTResource(uint16 id) const { + if (id >= _totResourceTable->itemsCount) { + warning("Trying to load non-existent TOT resource (%s, %d/%d)", + _totFile.c_str(), id, _totResourceTable->itemsCount - 1); + return 0; + } + + TOTResourceItem &totItem = _totResourceTable->items[id]; + + byte *data = 0; + if (totItem.type == kResourceIM) + data = getIMData(totItem); + if (totItem.type == kResourceTOT) + data = getTOTData(totItem); + + if (!data) + return 0; + + return new Resource(data, totItem.size, false, totItem.width, totItem.height); +} + +Resource *Resources::getEXTResource(uint16 id) const { + if (!_extResourceTable || (id > _extResourceTable->itemsCount)) + return 0; + + EXTResourceItem &extItem = _extResourceTable->items[id]; + + uint32 size = extItem.size; + + if (extItem.width & 0x4000) + size += 1 << 16; + if (extItem.width & 0x2000) + size += 2 << 16; + if (extItem.width & 0x1000) + size += 4 << 16; + if (extItem.height == 0) + size += extItem.width << 16; + + byte *data = 0; + if (extItem.type == kResourceEXT) + data = getEXTData(extItem, size); + if (extItem.type == kResourceEX) + data = getEXData(extItem, size); + + if (!data) + return 0; + + if (extItem.packed) { + byte *packedData = data; + + size = READ_LE_UINT32(packedData); + data = new byte[size]; + + _vm->_dataIO->unpackData(packedData, data); + + delete[] packedData; + } + + return new Resource(data, size, true, extItem.width & 0xFFF, extItem.height); +} + +byte *Resources::getTOTData(TOTResourceItem &totItem) const { + if (totItem.size < 0) + return 0; + + int32 offset = _totResourceTable->dataOffset + totItem.offset - _totResStart; + + if ((offset < 0) || (((uint32) (offset + totItem.size)) > _totSize)) + return 0; + + return _totData + offset; +} + +byte *Resources::getIMData(TOTResourceItem &totItem) const { + if (totItem.size < 0) + return 0; + + int32 indexOffset = totItem.index * 4; + if ((indexOffset < 0) || (((uint32) indexOffset) >= _imSize)) + return 0; + + uint32 offset = READ_LE_UINT32(_imData + indexOffset); + if ((offset + totItem.size) > _imSize) + return 0; + + return _imData + offset; +} + +byte *Resources::getEXTData(EXTResourceItem &extItem, uint32 size) const { + DataStream *stream = _vm->_dataIO->getDataStream(_extFile.c_str()); + if (!stream) + return 0; + + if (!stream->seek(extItem.offset)) { + delete stream; + return 0; + } + + byte *data = new byte[extItem.packed ? (size + 2) : size]; + if (stream->read(data, size) != size) { + delete[] data; + delete stream; + return 0; + } + + delete stream; + return data; +} + +byte *Resources::getEXData(EXTResourceItem &extItem, uint32 size) const { + DataStream *stream = _vm->_dataIO->getDataStream(_exFile.c_str()); + if (!stream) + return 0; + + if (!stream->seek(extItem.offset)) { + delete stream; + return 0; + } + + byte *data = new byte[extItem.packed ? (size + 2) : size]; + if (stream->read(data, size) != size) { + delete[] data; + delete stream; + return 0; + } + + delete stream; + return data; +} + +} // End of namespace Gob diff --git a/engines/gob/resources.h b/engines/gob/resources.h new file mode 100644 index 0000000000..80acef645c --- /dev/null +++ b/engines/gob/resources.h @@ -0,0 +1,207 @@ +/* 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 GOB_RESOURCES_H +#define GOB_RESOURCES_H + +#include "common/str.h" + +namespace Common { + class MemoryReadStream; +} + +namespace Gob { + +class GobEngine; + +class Resource { +public: + Resource(byte *data, int32 size, bool needFree = true, + int16 width = 0, int16 height = 0); + ~Resource(); + + byte *getData () const; + int32 getSize () const; + int16 getWidth () const; + int16 getHeight() const; + + Common::MemoryReadStream *stream() const; + +private: + byte *_data; + int32 _size; + int16 _width; + int16 _height; + bool _needFree; + + Common::MemoryReadStream *_stream; +}; + +class TextItem { +public: + TextItem(byte *data, int32 size); + ~TextItem(); + + byte *getData() const; + int32 getSize() const; + + Common::MemoryReadStream *stream() const; + +private: + byte *_data; + int32 _size; + + Common::MemoryReadStream *_stream; +}; + +class Resources { +public: + Resources(GobEngine *vm); + ~Resources(); + + bool load(const Common::String &fileName); + void unload(bool del = true); + + bool isLoaded() const; + + Resource *getResource(uint16 id, int16 *width = 0, int16 *height = 0) const; + TextItem *getTextItem(uint16 id) const; + + byte *getTexts() const; + +private: + // Structure sizes in the files + static const int kTOTResItemSize = 4 + 2 + 2 + 2; + static const int kTOTResTableSize = 2 + 1; + static const int kEXTResItemSize = 4 + 2 + 2 + 2; + static const int kEXTResTableSize = 2 + 1; + static const int kTOTTextTableSize = 2; + static const int kTOTTextItemSize = 2 + 2; + + enum ResourceType { + kResourceTOT, + kResourceIM, + kResourceEXT, + kResourceEX + }; + + struct TOTResourceItem { + ResourceType type; + int16 size; + int16 width; + int16 height; + union { + int32 offset; + int32 index; + }; + }; + + struct TOTResourceTable { + int16 itemsCount; + byte unknown; + TOTResourceItem *items; + uint32 dataOffset; + + TOTResourceTable(); + ~TOTResourceTable(); + }; + + struct EXTResourceItem { + ResourceType type; + int32 offset; + uint16 size; + int16 width; + int16 height; + bool packed; + }; + + struct EXTResourceTable { + int16 itemsCount; + byte unknown; + EXTResourceItem *items; + + EXTResourceTable(); + ~EXTResourceTable(); + }; + + struct TOTTextItem { + uint16 offset; + int16 size; + }; + + struct TOTTextTable { + bool needFree; + int16 itemsCount; + + byte *data; + int32 size; + + TOTTextItem *items; + + TOTTextTable(); + ~TOTTextTable(); + }; + + GobEngine *_vm; + + Common::String _totFile; + Common::String _extFile; + Common::String _exFile; + + byte *_totData; + uint32 _totSize; + + byte *_imData; + uint32 _imSize; + + bool _hasLOM; + int32 _totResStart; + + TOTResourceTable *_totResourceTable; + EXTResourceTable *_extResourceTable; + TOTTextTable *_totTextTable; + + bool loadTOTResourceTable(); + bool loadEXTResourceTable(); + bool loadTOTTextTable(const Common::String &fileBase); + bool loadIMFile(); + bool loadEXFile(); + + byte *loadTOTLocTexts(const Common::String &fileBase, int32 &size); + bool getLocTextFile(char *locTextFile, int language); + Common::String getLocTextFile(const Common::String &fileBase, int language); + + Resource *getTOTResource(uint16 id) const; + Resource *getEXTResource(uint16 id) const; + + byte *getTOTData(TOTResourceItem &totItem) const; + byte *getIMData(TOTResourceItem &totItem) const; + byte *getEXTData(EXTResourceItem &extItem, uint32 size) const; + byte *getEXData(EXTResourceItem &extItem, uint32 size) const; +}; + +} // End of namespace Gob + +#endif // GOB_RESOURCES_H diff --git a/engines/gob/save/savefile.h b/engines/gob/save/savefile.h index 989a37277e..615be8e0f2 100644 --- a/engines/gob/save/savefile.h +++ b/engines/gob/save/savefile.h @@ -163,7 +163,7 @@ public: bool readPalette(const byte *palette); /** Read a sprite into the part. */ bool readSprite(const SurfaceDesc &sprite); - + /** Read size bytes of raw data into the sprite. */ bool readSpriteRaw(const byte *data, uint32 size); diff --git a/engines/gob/save/saveload.cpp b/engines/gob/save/saveload.cpp index abda2f8a65..81239f07dc 100644 --- a/engines/gob/save/saveload.cpp +++ b/engines/gob/save/saveload.cpp @@ -61,7 +61,7 @@ int32 SaveLoad::getSize(const char *fileName) { int32 size = handler->getSize(); debugC(4, kDebugSaveLoad, "Size is %d", size); - + return size; } diff --git a/engines/gob/save/saveload_v3.cpp b/engines/gob/save/saveload_v3.cpp index 2f89644ee0..58232e6991 100644 --- a/engines/gob/save/saveload_v3.cpp +++ b/engines/gob/save/saveload_v3.cpp @@ -302,7 +302,7 @@ bool SaveLoad_v3::GameHandler::createReader(int slot) { if (!_reader || (_reader->getSlot() != ((uint32) slot))) { Common::String slotFile = _slotFile->build(slot); - + if (slotFile.empty()) return false; @@ -319,7 +319,7 @@ bool SaveLoad_v3::GameHandler::createReader(int slot) { } else _reader = new SaveReader(_usesScreenshots ? 3 : 2, slot, slotFile); - + if (!_reader->load()) { delete _reader; _reader = 0; @@ -337,7 +337,7 @@ bool SaveLoad_v3::GameHandler::createWriter(int slot) { if (!_writer || (_writer->getSlot() != ((uint32) slot))) { Common::String slotFile = _slotFile->build(slot); - + if (slotFile.empty()) return false; @@ -495,7 +495,7 @@ SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, ScreenshotType s _gameHandler = new GameHandler(vm, targetName, true); _screenshotHandler = new ScreenshotHandler(vm, _gameHandler, sShotType); } - + _tempSpriteHandler = new TempSpriteHandler(vm); _notesHandler = new NotesHandler(2560, vm, targetName); diff --git a/engines/gob/save/saveload_v4.cpp b/engines/gob/save/saveload_v4.cpp index 6e1d5208ff..06280af2a6 100644 --- a/engines/gob/save/saveload_v4.cpp +++ b/engines/gob/save/saveload_v4.cpp @@ -317,7 +317,7 @@ bool SaveLoad_v4::GameHandler::createReader(int slot) { if (!_reader || (_reader->getSlot() != ((uint32) slot))) { Common::String slotFile = _slotFile->build(slot); - + if (slotFile.empty()) return false; @@ -334,7 +334,7 @@ bool SaveLoad_v4::GameHandler::createReader(int slot) { } else _reader = new SaveReader(3, slot, slotFile); - + if (!_reader->load()) { delete _reader; _reader = 0; @@ -352,7 +352,7 @@ bool SaveLoad_v4::GameHandler::createWriter(int slot) { if (!_writer || (_writer->getSlot() != ((uint32) slot))) { Common::String slotFile = _slotFile->build(slot); - + if (slotFile.empty()) return false; diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index 71750509b4..7a4b8ad868 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -31,6 +31,8 @@ #include "gob/global.h" #include "gob/draw.h" #include "gob/game.h" +#include "gob/script.h" +#include "gob/resources.h" #include "gob/inter.h" #include "gob/map.h" #include "gob/videoplayer.h" @@ -39,33 +41,33 @@ namespace Gob { Scenery::Scenery(GobEngine *vm) : _vm(vm) { for (int i = 0; i < 20; i++) { - _spriteRefs[i] = 0; + _spriteRefs[i] = 0; _spriteResId[i] = 0; } for (int i = 0; i < 10; i++) { _staticPictCount[i] = 0; - _staticResId[i] = 0; - _animPictCount[i] = 0; - _animResId[i] = 0; + _staticResId[i] = 0; + _animPictCount[i] = 0; + _animResId[i] = 0; } - _curStatic = 0; + _curStatic = 0; _curStaticLayer = 0; - _toRedrawLeft = 0; - _toRedrawRight = 0; - _toRedrawTop = 0; + _toRedrawLeft = 0; + _toRedrawRight = 0; + _toRedrawTop = 0; _toRedrawBottom = 0; - _animTop = 0; + _animTop = 0; _animLeft = 0; _pCaptureCounter = 0; for (int i = 0; i < 70; i++ ) { _staticPictToSprite[i] = 0; - _animPictToSprite[i] = 0; + _animPictToSprite[i] = 0; } } @@ -78,17 +80,17 @@ Scenery::~Scenery() { void Scenery::init() { for (int i = 0; i < 10; i++) { - _animPictCount[i] = 0; + _animPictCount[i] = 0; _staticPictCount[i] = -1; } for (int i = 0; i < 20; i++) { - _spriteRefs[i] = 0; + _spriteRefs[i] = 0; _spriteResId[i] = -1; } _curStaticLayer = -1; - _curStatic = -1; + _curStatic = -1; } int16 Scenery::loadStatic(char search) { @@ -97,28 +99,26 @@ int16 Scenery::loadStatic(char search) { int16 picsCount; int16 resId; int16 sceneryIndex; - byte *extData = 0; - byte *dataPtr; Static *ptr; int16 width; int16 height; int16 sprResId; int16 sprIndex; - _vm->_inter->evalExpr(&sceneryIndex); + _vm->_game->_script->evalExpr(&sceneryIndex); - size = _vm->_inter->load16(); - backsPtr = (int16 *) _vm->_global->_inter_execPtr; - _vm->_global->_inter_execPtr += size * 2; - picsCount = _vm->_inter->load16(); - resId = _vm->_inter->load16(); + size = _vm->_game->_script->readInt16(); + backsPtr = (int16 *) (_vm->_game->_script->getData() + _vm->_game->_script->pos()); + _vm->_game->_script->skip(size * 2); + picsCount = _vm->_game->_script->readInt16(); + resId = _vm->_game->_script->readInt16(); if (search) { int i; for (i = 0; i < 10; i++) { if ((_staticPictCount[i] != -1) && (_staticResId[i] == resId)) { - _vm->_global->_inter_execPtr += 8 * _staticPictCount[i]; + _vm->_game->_script->skip(8 * _staticPictCount[i]); return i; } @@ -128,52 +128,54 @@ int16 Scenery::loadStatic(char search) { } _staticPictCount[sceneryIndex] = picsCount; - _staticResId[sceneryIndex] = resId; + _staticResId[sceneryIndex] = resId; - if (resId >= 30000) { - extData = _vm->_game->loadExtData(resId, 0, 0); - dataPtr = extData; - } else - dataPtr = _vm->_game->loadTotResource(resId); + Resource *resource = _vm->_game->_resources->getResource((uint16) resId); + if (!resource) + return 0; ptr = &_statics[sceneryIndex]; - ptr->layersCount = (int16) READ_LE_UINT16(dataPtr); - dataPtr += 2; + ptr->layersCount = resource->stream()->readSint16LE(); ptr->layers = new StaticLayer[ptr->layersCount]; for (int i = 0; i < ptr->layersCount; i++) { - int16 offset = READ_LE_UINT16(dataPtr + i * 2); - Common::MemoryReadStream layerData(dataPtr + offset, 4294967295U); + Common::SeekableReadStream &layerData = *resource->stream(); - ptr->layers[i].planeCount = layerData.readSint16LE(); + layerData.seek(2 + i * 2); + layerData.seek(layerData.readUint16LE()); - ptr->layers[i].planes = new StaticPlane[ptr->layers[i].planeCount]; - for (int j = 0; j < ptr->layers[i].planeCount; ++j) { - ptr->layers[i].planes[j].pictIndex = layerData.readByte(); - ptr->layers[i].planes[j].pieceIndex = layerData.readByte(); - ptr->layers[i].planes[j].drawOrder = layerData.readByte(); - ptr->layers[i].planes[j].destX = layerData.readSint16LE(); - ptr->layers[i].planes[j].destY = layerData.readSint16LE(); - ptr->layers[i].planes[j].transp = layerData.readSByte(); - } + ptr->layers[i].backResId = layerData.readSint16LE(); + ptr->layers[i].planeCount = layerData.readSint16LE(); + if (ptr->layers[i].planeCount > 0) { + ptr->layers[i].planes = new StaticPlane[ptr->layers[i].planeCount]; + for (int j = 0; j < ptr->layers[i].planeCount; j++) { + ptr->layers[i].planes[j].pictIndex = layerData.readByte(); + ptr->layers[i].planes[j].pieceIndex = layerData.readByte(); + ptr->layers[i].planes[j].drawOrder = layerData.readByte(); + ptr->layers[i].planes[j].destX = layerData.readSint16LE(); + ptr->layers[i].planes[j].destY = layerData.readSint16LE(); + ptr->layers[i].planes[j].transp = layerData.readSByte(); + } + } else + ptr->layers[i].planes = 0; ptr->layers[i].backResId = (int16) READ_LE_UINT16(backsPtr); backsPtr++; } - ptr->pieces = new PieceDesc*[picsCount]; + ptr->pieces = new PieceDesc*[picsCount]; ptr->piecesCount = new uint32[picsCount]; for (int i = 0; i < picsCount; i++) { - int16 pictDescId = _vm->_inter->load16(); + int16 pictDescId = _vm->_game->_script->readInt16(); loadPieces(pictDescId, ptr->pieces[i], ptr->piecesCount[i]); - width = _vm->_inter->load16(); - height = _vm->_inter->load16(); - sprResId = _vm->_inter->load16(); + width = _vm->_game->_script->readInt16(); + height = _vm->_game->_script->readInt16(); + sprResId = _vm->_game->_script->readInt16(); for (sprIndex = 0; sprIndex < 20; sprIndex++) { if (_spriteResId[sprIndex] == sprResId) break; @@ -183,9 +185,7 @@ int16 Scenery::loadStatic(char search) { _staticPictToSprite[7 * sceneryIndex + i] = sprIndex; _spriteRefs[sprIndex]++; } else { - for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0; - sprIndex--) - ; + for (sprIndex = 19; _vm->_draw->_spritesArray[sprIndex] != 0; sprIndex--); _staticPictToSprite[7 * sceneryIndex + i] = sprIndex; _spriteRefs[sprIndex] = 1; @@ -193,17 +193,16 @@ int16 Scenery::loadStatic(char search) { _vm->_draw->initSpriteSurf(sprIndex, width, height, 2); _vm->_video->clearSurf(*_vm->_draw->_spritesArray[sprIndex]); - _vm->_draw->_destSurface = sprIndex; - _vm->_draw->_spriteLeft = sprResId; + _vm->_draw->_destSurface = sprIndex; + _vm->_draw->_spriteLeft = sprResId; _vm->_draw->_transparency = 0; - _vm->_draw->_destSpriteX = 0; - _vm->_draw->_destSpriteY = 0; + _vm->_draw->_destSpriteX = 0; + _vm->_draw->_destSpriteY = 0; _vm->_draw->spriteOperation(DRAW_LOADSPRITE); } } - delete[] extData; - + delete resource; return sceneryIndex + 100; } @@ -211,7 +210,7 @@ void Scenery::freeStatic(int16 index) { int16 spr; if (index == -1) - _vm->_inter->evalExpr(&index); + _vm->_game->_script->evalExpr(&index); if (_staticPictCount[index] == -1) return; @@ -229,12 +228,13 @@ void Scenery::freeStatic(int16 index) { for (int i = 0; i < _statics[index].layersCount; i++) delete[] _statics[index].layers[i].planes; + delete[] _statics[index].layers; delete[] _statics[index].pieces; delete[] _statics[index].piecesCount; _statics[index].layersCount = 0; - _staticPictCount[index] = -1; + _staticPictCount[index] = -1; } void Scenery::renderStatic(int16 scenery, int16 layer) { @@ -261,22 +261,21 @@ void Scenery::renderStatic(int16 scenery, int16 layer) { _vm->_draw->_spriteLeft = layerPtr->backResId; if (_vm->_draw->_spriteLeft != -1) { - _vm->_draw->_destSpriteX = 0; - _vm->_draw->_destSpriteY = 0; - _vm->_draw->_destSurface = 21; - _vm->_draw->_transparency = 0; + _vm->_draw->_destSpriteX = 0; + _vm->_draw->_destSpriteY = 0; + _vm->_draw->_destSurface = 21; + _vm->_draw->_transparency = 0; _vm->_draw->spriteOperation(DRAW_LOADSPRITE); } planeCount = layerPtr->planeCount; for (order = 0; order < 100; order++) { - for (plane = 0, planePtr = layerPtr->planes; - plane < planeCount; plane++, planePtr++) { + for (plane = 0, planePtr = layerPtr->planes; plane < planeCount; plane++, planePtr++) { if (planePtr->drawOrder != order) continue; pieceIndex = planePtr->pieceIndex; - pictIndex = planePtr->pictIndex - 1; + pictIndex = planePtr->pictIndex - 1; if (pictIndex >= _staticPictCount[scenery]) continue; @@ -289,19 +288,19 @@ void Scenery::renderStatic(int16 scenery, int16 layer) { _vm->_draw->_destSpriteX = planePtr->destX; _vm->_draw->_destSpriteY = planePtr->destY; - left = ptr->pieces[pictIndex][pieceIndex].left; - right = ptr->pieces[pictIndex][pieceIndex].right; - top = ptr->pieces[pictIndex][pieceIndex].top; + left = ptr->pieces[pictIndex][pieceIndex].left; + right = ptr->pieces[pictIndex][pieceIndex].right; + top = ptr->pieces[pictIndex][pieceIndex].top; bottom = ptr->pieces[pictIndex][pieceIndex].bottom; _vm->_draw->_sourceSurface = _staticPictToSprite[scenery * 7 + pictIndex]; - _vm->_draw->_destSurface = 21; - _vm->_draw->_spriteLeft = left; - _vm->_draw->_spriteTop = top; - _vm->_draw->_spriteRight = right - left + 1; - _vm->_draw->_spriteBottom = bottom - top + 1; - _vm->_draw->_transparency = planePtr->transp ? 3 : 0; + _vm->_draw->_destSurface = 21; + _vm->_draw->_spriteLeft = left; + _vm->_draw->_spriteTop = top; + _vm->_draw->_spriteRight = right - left + 1; + _vm->_draw->_spriteBottom = bottom - top + 1; + _vm->_draw->_transparency = planePtr->transp ? 3 : 0; _vm->_draw->spriteOperation(DRAW_BLITSURF); } } @@ -337,7 +336,7 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { continue; pieceIndex = planePtr->pieceIndex; - pictIndex = planePtr->pictIndex - 1; + pictIndex = planePtr->pictIndex - 1; if (pictIndex >= _staticPictCount[index]) continue; @@ -351,9 +350,9 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { _vm->_draw->_destSpriteX = planePtr->destX; _vm->_draw->_destSpriteY = planePtr->destY; - left = pictPtr[pictIndex][pieceIndex].left; - right = pictPtr[pictIndex][pieceIndex].right; - top = pictPtr[pictIndex][pieceIndex].top; + left = pictPtr[pictIndex][pieceIndex].left; + right = pictPtr[pictIndex][pieceIndex].right; + top = pictPtr[pictIndex][pieceIndex].top; bottom = pictPtr[pictIndex][pieceIndex].bottom; if (_vm->_draw->_destSpriteX > _toRedrawRight) @@ -372,10 +371,10 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { _vm->_draw->_destSpriteY = _toRedrawTop; } - _vm->_draw->_spriteLeft = left; - _vm->_draw->_spriteTop = top; - _vm->_draw->_spriteRight = right - left + 1; - _vm->_draw->_spriteBottom = bottom - top + 1; + _vm->_draw->_spriteLeft = left; + _vm->_draw->_spriteTop = top; + _vm->_draw->_spriteRight = right - left + 1; + _vm->_draw->_spriteBottom = bottom - top + 1; if ((_vm->_draw->_spriteRight <= 0) || (_vm->_draw->_spriteBottom <= 0)) @@ -393,8 +392,8 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { _vm->_draw->_sourceSurface = _staticPictToSprite[index * 7 + pictIndex]; - _vm->_draw->_destSurface = 21; - _vm->_draw->_transparency = planePtr->transp ? 3 : 0; + _vm->_draw->_destSurface = 21; + _vm->_draw->_transparency = planePtr->transp ? 3 : 0; _vm->_draw->spriteOperation(DRAW_BLITSURF); } } @@ -422,8 +421,6 @@ int16 Scenery::loadAnim(char search) { int16 j; int16 sceneryIndex; int16 framesCount; - byte *extData; - byte *dataPtr; Animation *ptr; int16 width; int16 height; @@ -431,15 +428,14 @@ int16 Scenery::loadAnim(char search) { int16 sprIndex; uint32 layerPos; - extData = 0; - _vm->_inter->evalExpr(&sceneryIndex); - picsCount = _vm->_inter->load16(); - resId = _vm->_inter->load16(); + _vm->_game->_script->evalExpr(&sceneryIndex); + picsCount = _vm->_game->_script->readInt16(); + resId = _vm->_game->_script->readInt16(); if (search) { for (i = 0; i < 10; i++) { if ((_animPictCount[i] != 0) && (_animResId[i] == resId)) { - _vm->_global->_inter_execPtr += 8 * _animPictCount[i]; + _vm->_game->_script->skip(8 * _animPictCount[i]); return i; } @@ -451,50 +447,50 @@ int16 Scenery::loadAnim(char search) { _animPictCount[sceneryIndex] = picsCount; _animResId[sceneryIndex] = resId; - if (resId >= 30000) { - extData = _vm->_game->loadExtData(resId, 0, 0); - dataPtr = extData; - } else - dataPtr = _vm->_game->loadTotResource(resId); + Resource *resource = _vm->_game->_resources->getResource((uint16) resId); + if (!resource) + return 0; ptr = &_animations[sceneryIndex]; - ptr->layersCount = READ_LE_UINT16(dataPtr); - dataPtr += 2; + ptr->layersCount = resource->stream()->readSint16LE(); ptr->layers = new AnimLayer[ptr->layersCount]; for (i = 0; i < ptr->layersCount; i++) { - int16 offset = READ_LE_UINT16(dataPtr + i * 2); - Common::MemoryReadStream layerData(dataPtr + offset - 2, 4294967295U); - - ptr->layers[i].unknown0 = layerData.readSint16LE(); - ptr->layers[i].posX = layerData.readSint16LE(); - ptr->layers[i].posY = layerData.readSint16LE(); - ptr->layers[i].animDeltaX = layerData.readSint16LE(); - ptr->layers[i].animDeltaY = layerData.readSint16LE(); - ptr->layers[i].transp = layerData.readSByte(); + Common::SeekableReadStream &layerData = *resource->stream(); + + layerData.seek(2 + i * 2); + layerData.seek(layerData.readUint16LE()); + + ptr->layers[i].unknown0 = layerData.readSint16LE(); + ptr->layers[i].posX = layerData.readSint16LE(); + ptr->layers[i].posY = layerData.readSint16LE(); + ptr->layers[i].animDeltaX = layerData.readSint16LE(); + ptr->layers[i].animDeltaY = layerData.readSint16LE(); + ptr->layers[i].transp = layerData.readSByte(); ptr->layers[i].framesCount = layerData.readSint16LE(); + // Going through the AnimFramePiece, finding the end for each layerPos = layerData.pos(); framesCount = 0; - layerData.seek(4, SEEK_CUR); - for (j = 0; j < ptr->layers[i].framesCount; - j++, framesCount++, layerData.seek(4, SEEK_CUR)) { + for (j = 0; j < ptr->layers[i].framesCount; j++) { + layerData.skip(4); // pictIndex, pieceIndex, destX, destY while (layerData.readByte() == 1) { framesCount++; - layerData.seek(4, SEEK_CUR); + layerData.skip(4); // pictIndex, pieceIndex, destX, destY } + framesCount++; } layerData.seek(layerPos); ptr->layers[i].frames = new AnimFramePiece[framesCount]; for (j = 0; j < framesCount; j++) { - ptr->layers[i].frames[j].pictIndex = layerData.readByte(); + ptr->layers[i].frames[j].pictIndex = layerData.readByte(); ptr->layers[i].frames[j].pieceIndex = layerData.readByte(); - ptr->layers[i].frames[j].destX = layerData.readSByte(); - ptr->layers[i].frames[j].destY = layerData.readSByte(); - ptr->layers[i].frames[j].notFinal = layerData.readSByte(); + ptr->layers[i].frames[j].destX = layerData.readSByte(); + ptr->layers[i].frames[j].destY = layerData.readSByte(); + ptr->layers[i].frames[j].notFinal = layerData.readSByte(); } } @@ -502,13 +498,13 @@ int16 Scenery::loadAnim(char search) { ptr->piecesCount = new uint32[picsCount]; for (i = 0; i < picsCount; i++) { - int16 pictDescId = _vm->_inter->load16(); + int16 pictDescId = _vm->_game->_script->readInt16(); loadPieces(pictDescId, ptr->pieces[i], ptr->piecesCount[i]); - width = _vm->_inter->load16(); - height = _vm->_inter->load16(); - sprResId = _vm->_inter->load16(); + width = _vm->_game->_script->readInt16(); + height = _vm->_game->_script->readInt16(); + sprResId = _vm->_game->_script->readInt16(); for (sprIndex = 0; sprIndex < 20; sprIndex++) if (_spriteResId[sprIndex] == sprResId) break; @@ -522,22 +518,21 @@ int16 Scenery::loadAnim(char search) { ; _animPictToSprite[7 * sceneryIndex + i] = sprIndex; - _spriteRefs[sprIndex] = 1; + _spriteRefs[sprIndex] = 1; _spriteResId[sprIndex] = sprResId; _vm->_draw->initSpriteSurf(sprIndex, width, height, 2); _vm->_video->clearSurf(*_vm->_draw->_spritesArray[sprIndex]); - _vm->_draw->_destSurface = sprIndex; - _vm->_draw->_spriteLeft = sprResId; + _vm->_draw->_destSurface = sprIndex; + _vm->_draw->_spriteLeft = sprResId; _vm->_draw->_transparency = 0; - _vm->_draw->_destSpriteX = 0; - _vm->_draw->_destSpriteY = 0; + _vm->_draw->_destSpriteX = 0; + _vm->_draw->_destSpriteY = 0; _vm->_draw->spriteOperation(DRAW_LOADSPRITE); } } - delete[] extData; - + delete resource; return sceneryIndex + 100; } @@ -545,7 +540,7 @@ void Scenery::freeAnim(int16 index) { int16 spr; if (index == -1) - _vm->_inter->evalExpr(&index); + _vm->_game->_script->evalExpr(&index); if (_animPictCount[index] == 0) return; @@ -563,6 +558,7 @@ void Scenery::freeAnim(int16 index) { for (int i = 0; i < _animations[index].layersCount; i++) delete[] _animations[index].layers[i].frames; + delete[] _animations[index].layers; delete[] _animations[index].pieces; delete[] _animations[index].piecesCount; @@ -607,8 +603,8 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, return; _vm->_game->capturePush(_toRedrawLeft, _toRedrawTop, - _toRedrawRight - _toRedrawLeft + 1, - _toRedrawBottom - _toRedrawTop + 1); + _toRedrawRight - _toRedrawLeft + 1, + _toRedrawBottom - _toRedrawTop + 1); *_pCaptureCounter = *_pCaptureCounter + 1; } @@ -628,7 +624,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, while (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) <= frame) _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); } else { - int16 curFrame = _vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1); + int16 curFrame = _vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1); uint8 frameWrap = curFrame / 256; frame = (frame + 1) % 256; @@ -636,17 +632,17 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); } - destX = 0; - destY = 0; - left = *(obj.pPosX); - top = *(obj.pPosY); - right = left + _vm->_vidPlayer->getWidth(obj.videoSlot - 1) - 1; - bottom = top + _vm->_vidPlayer->getHeight(obj.videoSlot - 1) - 1; + destX = 0; + destY = 0; + left = *(obj.pPosX); + top = *(obj.pPosY); + right = left + _vm->_vidPlayer->getWidth(obj.videoSlot - 1) - 1; + bottom = top + _vm->_vidPlayer->getHeight(obj.videoSlot - 1) - 1; if (flags & 2) { if (left < _vm->_mult->_animLeft) { destX += _vm->_mult->_animLeft - left; - left = _vm->_mult->_animLeft; + left = _vm->_mult->_animLeft; } if ((_vm->_mult->_animLeft + _vm->_mult->_animWidth) <= right) @@ -654,7 +650,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, if (top < _vm->_mult->_animTop) { destY += _vm->_mult->_animTop - top; - top = _vm->_mult->_animTop; + top = _vm->_mult->_animTop; } if ((_vm->_mult->_animTop + _vm->_mult->_animHeight) <= bottom) @@ -663,7 +659,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, } else if (flags & 4) { if (left < _toRedrawLeft) { destX += _toRedrawLeft - left; - left = _toRedrawLeft; + left = _toRedrawLeft; } if (right > _toRedrawRight) @@ -671,16 +667,16 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, if (top < _toRedrawTop) { destY += _toRedrawTop - top; - top = _toRedrawTop; + top = _toRedrawTop; } if (bottom > _toRedrawBottom) bottom = _toRedrawBottom; } else { - _toRedrawTop = top; - _toRedrawLeft = left; - _toRedrawRight = right; + _toRedrawTop = top; + _toRedrawLeft = left; + _toRedrawRight = right; _toRedrawBottom = bottom; } @@ -690,7 +686,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, if (left < _vm->_mult->_animLeft) { destX += _vm->_mult->_animLeft - left; - left = _vm->_mult->_animLeft; + left = _vm->_mult->_animLeft; } if ((_vm->_mult->_animLeft + _vm->_mult->_animWidth) <= right) @@ -698,40 +694,40 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, if (top < _vm->_mult->_animTop) { destY += _vm->_mult->_animTop - top; - top = _vm->_mult->_animTop; + top = _vm->_mult->_animTop; } if ((_vm->_mult->_animTop + _vm->_mult->_animHeight) <= bottom) bottom = _vm->_mult->_animTop + _vm->_mult->_animHeight - 1; - _vm->_draw->_spriteLeft = destX; - _vm->_draw->_spriteTop = destY; - _vm->_draw->_spriteRight = right - left + 1; - _vm->_draw->_spriteBottom = bottom - top + 1; - _vm->_draw->_destSpriteX = left; - _vm->_draw->_destSpriteY = top; + _vm->_draw->_spriteLeft = destX; + _vm->_draw->_spriteTop = destY; + _vm->_draw->_spriteRight = right - left + 1; + _vm->_draw->_spriteBottom = bottom - top + 1; + _vm->_draw->_destSpriteX = left; + _vm->_draw->_destSpriteY = top; _vm->_draw->_transparency = layer; if (layer & 0x80) _vm->_draw->_spriteLeft = _vm->_vidPlayer->getWidth(obj.videoSlot - 1) - (destX + _vm->_draw->_spriteRight); _vm->_vidPlayer->slotCopyFrame(obj.videoSlot - 1, _vm->_draw->_backSurface->getVidMem(), - _vm->_draw->_spriteLeft, _vm->_draw->_spriteTop, + _vm->_draw->_spriteLeft, _vm->_draw->_spriteTop, _vm->_draw->_spriteRight, _vm->_draw->_spriteBottom, _vm->_draw->_destSpriteX, _vm->_draw->_destSpriteY, _vm->_draw->_backSurface->getWidth(), (_vm->_draw->_transparency != 0) ? 0 : -1); _vm->_draw->invalidateRect(_vm->_draw->_destSpriteX, _vm->_draw->_destSpriteY, - _vm->_draw->_destSpriteX + _vm->_draw->_spriteRight - 1, + _vm->_draw->_destSpriteX + _vm->_draw->_spriteRight - 1, _vm->_draw->_destSpriteY + _vm->_draw->_spriteBottom - 1); } if (!(flags & 4)) { - _animLeft = _toRedrawLeft = left; - _animTop = _toRedrawTop = top; - _animRight = _toRedrawRight = right; + _animLeft = _toRedrawLeft = left; + _animTop = _toRedrawTop = top; + _animRight = _toRedrawRight = right; _animBottom = _toRedrawBottom = bottom; } @@ -757,13 +753,13 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, return; _vm->_game->capturePush(_toRedrawLeft, _toRedrawTop, - _toRedrawRight - _toRedrawLeft + 1, - _toRedrawBottom - _toRedrawTop + 1); + _toRedrawRight - _toRedrawLeft + 1, + _toRedrawBottom - _toRedrawTop + 1); *_pCaptureCounter = *_pCaptureCounter + 1; } - pictPtr = _animations[animation].pieces; + pictPtr = _animations[animation].pieces; framePtr = layerPtr->frames; for (i = 0; i < frame; i++, framePtr++) @@ -771,9 +767,9 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, framePtr++; if (flags & 4) { - _toRedrawLeft = MAX(_toRedrawLeft, _vm->_mult->_animLeft); - _toRedrawTop = MAX(_toRedrawTop, _vm->_mult->_animTop); - _toRedrawRight = MIN(_toRedrawRight, + _toRedrawLeft = MAX(_toRedrawLeft, _vm->_mult->_animLeft); + _toRedrawTop = MAX(_toRedrawTop, _vm->_mult->_animTop); + _toRedrawRight = MIN(_toRedrawRight, (int16)(_vm->_mult->_animLeft + _vm->_mult->_animWidth - 1)); _toRedrawBottom = MIN(_toRedrawBottom, (int16)(_vm->_mult->_animTop + _vm->_mult->_animHeight - 1)); @@ -844,7 +840,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, (_vm->_mult->_animLeft + _vm->_mult->_animWidth) + 1; if (destY < _vm->_mult->_animTop) { - top += _vm->_mult->_animTop - destY; + top += _vm->_mult->_animTop - destY; destY = _vm->_mult->_animTop; } @@ -863,7 +859,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, right -= destX + right - left - _toRedrawRight; if (destY < _toRedrawTop) { - top += _toRedrawTop - destY; + top += _toRedrawTop - destY; destY = _toRedrawTop; } @@ -877,33 +873,33 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, if (doDraw) { _vm->_draw->_sourceSurface = _animPictToSprite[animation * 7 + pictIndex]; - _vm->_draw->_destSurface = 21; + _vm->_draw->_destSurface = 21; - _vm->_draw->_spriteLeft = left; - _vm->_draw->_spriteTop = top; - _vm->_draw->_spriteRight = right - left + 1; + _vm->_draw->_spriteLeft = left; + _vm->_draw->_spriteTop = top; + _vm->_draw->_spriteRight = right - left + 1; _vm->_draw->_spriteBottom = bottom - top + 1; - _vm->_draw->_destSpriteX = destX; - _vm->_draw->_destSpriteY = destY; + _vm->_draw->_destSpriteX = destX; + _vm->_draw->_destSpriteY = destY; _vm->_draw->_transparency = transp; _vm->_draw->spriteOperation(DRAW_BLITSURF); } if (!(flags & 4)) { if (_toRedrawLeft == -12345) { - _toRedrawLeft = destX; - _animLeft = destX; - _toRedrawTop = destY; - _animTop = destY; - _toRedrawRight = destX + right - left; - _animRight = destX + right - left; + _toRedrawLeft = destX; + _animLeft = destX; + _toRedrawTop = destY; + _animTop = destY; + _toRedrawRight = destX + right - left; + _animRight = destX + right - left; _toRedrawBottom = destY + bottom - top; - _animBottom = destY + bottom - top; + _animBottom = destY + bottom - top; } else { - _toRedrawLeft = MIN(_toRedrawLeft, destX); - _toRedrawTop = MIN(_toRedrawTop, destY); - _toRedrawRight = - MAX(_toRedrawRight, (int16)(destX + right - left)); + _toRedrawLeft = MIN(_toRedrawLeft, destX); + _toRedrawTop = MIN(_toRedrawTop, destY); + _toRedrawRight = + MAX(_toRedrawRight, (int16)(destX + right - left)); _toRedrawBottom = MAX(_toRedrawBottom, (int16)(destY + bottom - top)); } @@ -952,41 +948,23 @@ Scenery::AnimLayer *Scenery::getAnimLayer(uint16 index, uint16 layer) { } void Scenery::loadPieces(int16 pictDescId, PieceDesc *&pieceDesc, uint32 &piecesCount) { - byte *data; - uint32 size; - bool fromExt = false; - - if (pictDescId >= 30000) { - fromExt = true; - - uint32 eSize; - - data = _vm->_game->loadExtData(pictDescId, 0, 0, &eSize); - size = eSize; - } else { - int16 tSize; - - data = _vm->_game->loadTotResource(pictDescId, &tSize); - size = tSize; + Resource *resource = _vm->_game->_resources->getResource(pictDescId); + if (!resource) { + warning("Scenery::loadPieces(): Can't load %d", pictDescId); + return; } - if (!data) - error("Scenery::loadPieces(): Can't load pictDescId %d", pictDescId); - - piecesCount = size / 8; + piecesCount = resource->getSize() / 8; pieceDesc = new PieceDesc[piecesCount]; - Common::MemoryReadStream pieceData(data, size); - for (uint32 i = 0; i < piecesCount; i++) { - pieceDesc[i].left = (int16) pieceData.readUint16LE(); - pieceDesc[i].right = (int16) pieceData.readUint16LE(); - pieceDesc[i].top = (int16) pieceData.readUint16LE(); - pieceDesc[i].bottom = (int16) pieceData.readUint16LE(); + pieceDesc[i].left = resource->stream()->readSint16LE(); + pieceDesc[i].right = resource->stream()->readSint16LE(); + pieceDesc[i].top = resource->stream()->readSint16LE(); + pieceDesc[i].bottom = resource->stream()->readSint16LE(); } - if (fromExt) - delete[] data; + delete resource; } } // End of namespace Gob diff --git a/engines/gob/script.cpp b/engines/gob/script.cpp new file mode 100644 index 0000000000..6162e943bf --- /dev/null +++ b/engines/gob/script.cpp @@ -0,0 +1,522 @@ +/* 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 "common/util.h" +#include "common/endian.h" + +#include "gob/gob.h" +#include "gob/script.h" +#include "gob/dataio.h" +#include "gob/expression.h" +#include "gob/videoplayer.h" + +namespace Gob { + +Script::Script(GobEngine *vm) : _vm(vm) { + _expression = new Expression(vm); + + _finished = true; + + _totData = 0; + _totPtr = 0; + _totSize = 0; + + _lomHandle = -1; + + memset(&_totProperties, 0, sizeof(TOTFile::Properties)); +} + +Script::~Script() { + unload(); + + delete _expression; +} + +uint32 Script::read(byte *data, int32 size) { + int32 toRead = MIN<int32>(size, _totSize - (_totPtr - _totData)); + + if (toRead < 1) + return 0; + + memcpy(data, _totPtr, toRead); + _totPtr += toRead; + + return toRead; +} + +uint32 Script::peek(byte *data, int32 size, int32 offset) const { + int32 totOffset = ((_totPtr + offset) - _totData); + + if (totOffset < 1) + return 0; + if (((uint32) totOffset) >= _totSize) + return 0; + + int32 toPeek = MIN<int32>(size, _totSize - totOffset); + if (toPeek < 1) + return 0; + + memcpy(data, _totPtr + offset, toPeek); + + return toPeek; +} + +int32 Script::pos() const { + if (!_totData) + return -1; + + return _totPtr - _totData; +} + +int32 Script::getSize() const { + if (!_totData) + return -1; + + return _totSize; +} + +bool Script::seek(int32 offset, int whence) { + if (!_totData) + return false; + + if (whence == SEEK_CUR) + offset += pos(); + else if (whence == SEEK_END) + offset += _totSize; + + if ((offset < 0) || (((uint32) offset) >= _totSize)) + return false; + + // Cannot seek into the header + if (offset < 128) { + _finished = true; + return false; + } + + // A successful seek means the script file continues to be executed + _finished = false; + + _totPtr = _totData + offset; + + return true; +} + +bool Script::skip(int32 offset) { + return seek(offset, SEEK_CUR); +} + +int32 Script::getOffset(byte *ptr) const { + if (!_totData) + return -1; + + if ((ptr < _totData) || (ptr >= (_totData + _totSize))) + return -1; + + return ptr - _totData; +} + +byte *Script::getData(int32 offset) const { + if (!_totData) + return 0; + if ((offset < 0) || (((uint32) offset) >= _totSize)) + return 0; + + return _totData + offset; +} + +byte *Script::getData() { + return _totData; +} + +byte Script::readByte() { + byte v; + + read(&v, 1); + + return v; +} + +char Script::readChar() { + return (char) readByte(); +} + +uint8 Script::readUint8() { + return (uint8) readByte(); +} + +uint16 Script::readUint16() { + byte v[2]; + + read(v, 2); + + return READ_LE_UINT16(v); +} + +uint32 Script::readUint32() { + byte v[4]; + + read(v, 4); + + return READ_LE_UINT32(v); +} + +int8 Script::readInt8() { + return (int8) readByte(); +} + +int16 Script::readInt16() { + return (int16) readUint16(); +} + +int32 Script::readInt32() { + return (int32) readUint32(); +} + +char *Script::readString(int32 length) { + if (length < 0) { + length = 0; + while (_totPtr[length++] != '\0'); + } + + char *string = (char *) _totPtr; + + _totPtr += length; + + return string; +} + +byte Script::peekByte(int32 offset) { + byte v; + + peek(&v, 1, offset); + + return v; +} + +char Script::peekChar(int32 offset) { + return (char) peekByte(offset); +} + +uint8 Script::peekUint8(int32 offset) { + return (uint8) peekByte(offset); +} + +uint16 Script::peekUint16(int32 offset) { + byte v[2]; + + peek(v, 2, offset); + + return READ_LE_UINT16(v); +} + +uint32 Script::peekUint32(int32 offset) { + byte v[4]; + + peek(v, 4, offset); + + return READ_LE_UINT32(v); +} + +int8 Script::peekInt8(int32 offset) { + return (int8) peekByte(offset); +} + +int16 Script::peekInt16(int32 offset) { + return (int16) peekUint16(offset); +} + +int32 Script::peekInt32(int32 offset) { + return (int32) peekUint32(offset); +} + +char *Script::peekString(int32 offset) { + return (char *) (_totPtr + offset); +} + +int16 Script::readVarIndex(uint16 *size, uint16 *type) { + return _expression->parseVarIndex(size, type); +} + +int16 Script::readValExpr(byte stopToken) { + return _expression->parseValExpr(stopToken); +} + +int16 Script::readExpr(byte stopToken, byte *type) { + return _expression->parseExpr(stopToken, type); +} + +void Script::skipExpr(char stopToken) { + _expression->skipExpr(stopToken); +} + +char Script::evalExpr(int16 *pRes) { + byte type; + + _expression->printExpr(99); + + _expression->parseExpr(99, &type); + if (!pRes) + return type; + + switch (type) { + case TYPE_IMM_INT16: + *pRes = _expression->getResultInt(); + break; + + case TYPE_IMM_STR: + case GOB_FALSE: + *pRes = 0; + break; + + case GOB_TRUE: + *pRes = 1; + break; + } + + return type; +} + +bool Script::evalBoolResult() { + byte type; + + _expression->printExpr(99); + + _expression->parseExpr(99, &type); + if ( (type == GOB_TRUE) || + ((type == TYPE_IMM_INT16) && _expression->getResultInt())) + return true; + else + return false; +} + +int32 Script::getResultInt() const { + return _expression->getResultInt(); +} + +char *Script::getResultStr() const { + return _expression->getResultStr(); +} + +bool Script::load(const Common::String &fileName) { + unload(); + + _finished = false; + + bool isLOM; + + _totFile = TOTFile::createFileName(fileName, isLOM); + + if (isLOM) { + if (!loadLOM(_totFile)) { + unload(); + return false; + } + } else { + if (!loadTOT(_totFile)) { + unload(); + return false; + } + } + + return true; +} + +bool Script::loadTOT(const Common::String &fileName) { + TOTFile totFile(_vm); + + if (!totFile.load(fileName)) + return false; + + Common::SeekableReadStream *stream = totFile.getStream(); + if (!stream) + return false; + + if (!totFile.getProperties(_totProperties)) + return false; + + _totSize = _totProperties.scriptEnd; + if (_totSize <= 0) + return false; + + _totData = new byte[_totSize]; + if (stream->read(_totData, _totSize) != _totSize) + return false; + + return true; +} + +bool Script::loadLOM(const Common::String &fileName) { + warning("Stub: Script::loadLOM(%s)", _totFile.c_str()); + + _lomHandle = _vm->_dataIO->openData(_totFile.c_str()); + if (_lomHandle < 0) + return false; + + DataStream *stream = _vm->_dataIO->openAsStream(_lomHandle); + + stream->seek(48); + _totSize = stream->readUint32LE(); + stream->seek(0); + + _totData = new byte[_totSize]; + stream->read(_totData, _totSize); + + delete stream; + + return false; +} + +void Script::unload() { + unloadTOT(); +} + +void Script::unloadTOT() { + if (_lomHandle >= 0) + _vm->_dataIO->closeData(_lomHandle); + + // Unwind the call stack + while (!_callStack.empty()) + pop(); + + delete[] _totData; + + _totData = 0; + _totSize = 0; + _totPtr = 0; + _lomHandle = -1; + _totFile.clear(); + + _finished = true; +} + +bool Script::isLoaded() const { + return _totData != 0; +} + +void Script::setFinished(bool finished) { + _finished = finished; +} + +bool Script::isFinished() const { + return _finished; +} + +void Script::push() { + if (!isLoaded()) + // Nothing to do + return; + + CallEntry currentCall; + + currentCall.totPtr = _totPtr; + currentCall.finished = _finished; + + _callStack.push(currentCall); +} + +void Script::pop(bool ret) { + if (!isLoaded()) + // Nothing to do + return; + + // Unmatched pop? + assert(!_callStack.empty()); + + CallEntry lastCall = _callStack.pop(); + + if (ret) { + _totPtr = lastCall.totPtr; + _finished = lastCall.finished; + } +} + +void Script::call(uint32 offset) { + if (!isLoaded()) + // Nothing to do + return; + + push(); + seek(offset); +} + +uint8 Script::getVersionMajor() const { + return _totProperties.versionMajor; +} + +uint8 Script::getVersionMinor() const { + return _totProperties.versionMinor; +} + +uint32 Script::getVariablesCount() const { + return _totProperties.variablesCount; +} + +uint32 Script::getTextsOffset() const { + return _totProperties.textsOffset; +} + +uint32 Script::getResourcesOffset() const { + return _totProperties.resourcesOffset; +} + +uint16 Script::getAnimDataSize() const { + return _totProperties.animDataSize; +} + +uint8 Script::getImFileNumber() const { + return _totProperties.imFileNumber; +} + +uint8 Script::getExFileNumber() const { + return _totProperties.exFileNumber; +} + +uint8 Script::getCommunHandling() const { + return _totProperties.communHandling; +} + +uint16 Script::getFunctionOffset(uint8 function) const { + if (!_totData) + return 0; + + // Offsets 100-128, 2 bytes per function + assert(function <= 13); + + return _totProperties.functions[function]; +} + +uint32 Script::getVariablesCount(const char *fileName, GobEngine *vm) { + DataStream *stream = vm->_dataIO->getDataStream(fileName); + if (!stream) + return 0; + + stream->seek(0x2C); + uint32 variablesCount = stream->readUint32LE(); + delete stream; + + return variablesCount; +} + +} // End of namespace Gob diff --git a/engines/gob/script.h b/engines/gob/script.h new file mode 100644 index 0000000000..64a04503b1 --- /dev/null +++ b/engines/gob/script.h @@ -0,0 +1,169 @@ +/* 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 GOB_SCRIPT_H +#define GOB_SCRIPT_H + +#include "common/str.h" +#include "common/stack.h" + +#include "gob/totfile.h" + +namespace Gob { + +class GobEngine; +class Expression; + +class Script { +public: + Script(GobEngine *vm); + ~Script(); + + /** Read data and move the pointer accordingly. */ + uint32 read(byte *data, int32 size); + /** Read data (from an optional offset) without moving the pointer. */ + uint32 peek(byte *data, int32 size, int32 offset = 0) const; + + // Stream properties + int32 pos() const; + int32 getSize() const; + + // Stream seeking + bool seek(int32 offset, int whence = SEEK_SET); + bool skip(int32 offset); + + // Reading data + byte readByte (); + char readChar (); + uint8 readUint8 (); + uint16 readUint16(); + uint32 readUint32(); + int8 readInt8 (); + int16 readInt16 (); + int32 readInt32 (); + char *readString(int32 length = -1); + + // Peeking data + byte peekByte (int32 offset = 0); + char peekChar (int32 offset = 0); + uint8 peekUint8 (int32 offset = 0); + uint16 peekUint16(int32 offset = 0); + uint32 peekUint32(int32 offset = 0); + int8 peekInt8 (int32 offset = 0); + int16 peekInt16 (int32 offset = 0); + int32 peekInt32 (int32 offset = 0); + char *peekString(int32 offset = 0); + + // Expression parsing functions + int16 readVarIndex(uint16 *size = 0, uint16 *type = 0); + int16 readValExpr(byte stopToken = 99); + int16 readExpr(byte stopToken, byte *type); + void skipExpr(char stopToken); + + // Higher-level expression parsing functions + char evalExpr(int16 *pRes); + bool evalBoolResult(); + + // Accessing the result of expressions + int32 getResultInt() const; + char *getResultStr() const; + + /** Returns the offset the specified pointer is within the script data. */ + int32 getOffset(byte *ptr) const; + /** Returns the data pointer to the offset. */ + byte *getData(int32 offset) const; + + /** Returns the raw data pointer. */ + byte *getData(); + + /** Load a script file. */ + bool load(const Common::String &fileName); + /** Unload the script. */ + void unload(); + /** Was a script loaded? */ + bool isLoaded() const; + + /** Setting the 'finished' property. */ + void setFinished(bool finished); + /** Querying the 'finished' property. */ + bool isFinished() const; + + // Call stack operations + /** Push the current script position onto the call stack. */ + void push(); + /** Pop a script position from the call stack (and return there). */ + void pop(bool ret = true); + /** Push the current script position and branch to the specified offset. */ + void call(uint32 offset); + + // Fixed properties + uint8 getVersionMajor () const; + uint8 getVersionMinor () const; + uint32 getVariablesCount () const; + uint32 getTextsOffset () const; + uint32 getResourcesOffset() const; + uint16 getAnimDataSize () const; + uint8 getImFileNumber () const; + uint8 getExFileNumber () const; + uint8 getCommunHandling () const; + + uint16 getFunctionOffset (uint8 function) const; + + static uint32 getVariablesCount(const char *fileName, GobEngine *vm); + +private: + struct CallEntry { + byte *totPtr; + bool finished; + }; + + GobEngine *_vm; + Expression *_expression; + + bool _finished; + + Common::String _totFile; + byte *_totData; + byte *_totPtr; + uint32 _totSize; + + int16 _lomHandle; + + TOTFile::Properties _totProperties; + + Common::Stack<CallEntry> _callStack; + + /** Loading a TOT file. */ + bool loadTOT(const Common::String &fileName); + /** Loading a LOM file. */ + bool loadLOM(const Common::String &fileName); + + /** Unloading a TOT file. */ + void unloadTOT(); +}; + +} // End of namespace Gob + +#endif // GOB_SCRIPT_H diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp index 07481431b6..7ab8e1f8dd 100644 --- a/engines/gob/sound/adlib.cpp +++ b/engines/gob/sound/adlib.cpp @@ -39,18 +39,33 @@ const unsigned char AdLib::_volRegNums[] = { }; AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer) { + init(); +} + +AdLib::~AdLib() { + Common::StackLock slock(_mutex); + + _mixer->stopHandle(_handle); + OPLDestroy(_opl); + if (_data && _freeData) + delete[] _data; +} + +void AdLib::init() { _index = -1; _data = 0; _playPos = 0; _dataSize = 0; _rate = _mixer->getOutputRate(); + _opl = makeAdlibOPL(_rate); _first = true; _ended = false; _playing = false; - _needFree = false; + + _freeData = false; _repCount = -1; _samplesTillPoll = 0; @@ -63,15 +78,6 @@ AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer) { this, -1, 255, 0, false, true); } -AdLib::~AdLib() { - Common::StackLock slock(_mutex); - - _mixer->stopHandle(_handle); - OPLDestroy(_opl); - if (_data && _needFree) - delete[] _data; -} - int AdLib::readBuffer(int16 *buffer, const int numSamples) { Common::StackLock slock(_mutex); int samples; @@ -107,7 +113,9 @@ int AdLib::readBuffer(int16 *buffer, const int numSamples) { if (_ended) { _first = true; _ended = false; - _playPos = _data + 3 + (_data[1] + 1) * 0x38; + + rewind(); + _samplesTillPoll = 0; if (_repCount == -1) { reset(); @@ -120,7 +128,6 @@ int AdLib::readBuffer(int16 *buffer, const int numSamples) { else _playing = false; } - return numSamples; } @@ -173,48 +180,6 @@ void AdLib::reset() { writeOPL(0x01, 0x20); } -void AdLib::setVoices() { - // Definitions of the 9 instruments - for (int i = 0; i < 9; i++) - setVoice(i, i, true); -} - -void AdLib::setVoice(byte voice, byte instr, bool set) { - int i; - int j; - uint16 strct[27]; - byte channel; - byte *dataPtr; - - // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 - // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 - for (i = 0; i < 2; i++) { - dataPtr = _data + 3 + instr * 0x38 + i * 0x1A; - for (j = 0; j < 27; j++) { - strct[j] = READ_LE_UINT16(dataPtr); - dataPtr += 2; - } - channel = _operators[voice] + i * 3; - writeOPL(0xBD, 0x00); - writeOPL(0x08, 0x00); - writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); - if (!i) - writeOPL(0xC0 | voice, - ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); - writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); - writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); - writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | - ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | - ((strct[11] & 1) << 4) | (strct[1] & 0xF)); - if (!i) - writeOPL(0xE0 | channel, (strct[26] & 3)); - else - writeOPL(0xE0 | channel, (strct[14] & 3)); - if (i && set) - writeOPL(0x40 | channel, 0); - } -} - void AdLib::setKey(byte voice, byte note, bool on, bool spec) { short freq = 0; short octa = 0; @@ -278,7 +243,7 @@ void AdLib::setKey(byte voice, byte note, bool on, bool spec) { writeOPL(0xB0 + voice, (freq >> 8) | (octa << 2) | 0x20 * on); if (!freq) - warning("Voice %d, note %02X unknown", voice, note); + warning("AdLib: Voice %d, note %02X unknown", voice, note); } void AdLib::setVolume(byte voice, byte volume) { @@ -287,17 +252,102 @@ void AdLib::setVolume(byte voice, byte volume) { } void AdLib::pollMusic() { + if ((_playPos > (_data + _dataSize)) && (_dataSize != 0xFFFFFFFF)) { + _ended = true; + return; + } + + interpret(); +} + +void AdLib::unload() { + _playing = false; + _index = -1; + + if (_data && _freeData) + delete[] _data; + + _freeData = false; +} + +bool AdLib::isPlaying() const { + return _playing; +} + +bool AdLib::getRepeating() const { + return _repCount != 0; +} + +void AdLib::setRepeating(int32 repCount) { + _repCount = repCount; +} + +int AdLib::getIndex() const { + return _index; +} + +void AdLib::startPlay() { + if (_data) _playing = true; +} + +void AdLib::stopPlay() { + Common::StackLock slock(_mutex); + _playing = false; +} + +ADLPlayer::ADLPlayer(Audio::Mixer &mixer) : AdLib(mixer) { +} + +ADLPlayer::~ADLPlayer() { +} + +bool ADLPlayer::load(const char *fileName) { + Common::File song; + + unload(); + song.open(fileName); + if (!song.isOpen()) + return false; + + _freeData = true; + _dataSize = song.size(); + _data = new byte[_dataSize]; + song.read(_data, _dataSize); + song.close(); + + reset(); + setVoices(); + _playPos = _data + 3 + (_data[1] + 1) * 0x38; + + return true; +} + +bool ADLPlayer::load(byte *data, uint32 size, int index) { + unload(); + _repCount = 0; + + _dataSize = size; + _data = data; + _index = index; + + reset(); + setVoices(); + _playPos = _data + 3 + (_data[1] + 1) * 0x38; + + return true; +} + +void ADLPlayer::unload() { + AdLib::unload(); +} + +void ADLPlayer::interpret() { unsigned char instr; byte channel; byte note; byte volume; uint16 tempo; - if ((_playPos > (_data + _dataSize)) && (_dataSize != 0xFFFFFFFF)) { - _ended = true; - return; - } - // First tempo, we'll ignore it... if (_first) { tempo = *(_playPos++); @@ -352,7 +402,7 @@ void AdLib::pollMusic() { _samplesTillPoll = 0; return; default: - warning("Unknown special command in ADL, stopping playback: %X", + warning("ADLPlayer: Unknown special command %X, stopping playback", instr & 0x0F); _repCount = 0; _ended = true; @@ -360,7 +410,7 @@ void AdLib::pollMusic() { } break; default: - warning("Unknown command in ADL, stopping playback: %X", + warning("ADLPlayer: Unknown command %X, stopping playback", instr & 0xF0); _repCount = 0; _ended = true; @@ -383,75 +433,349 @@ void AdLib::pollMusic() { _samplesTillPoll = tempo * (_rate / 1000); } -bool AdLib::load(const char *fileName) { +void ADLPlayer::reset() { + AdLib::reset(); +} + +void ADLPlayer::rewind() { + _playPos = _data + 3 + (_data[1] + 1) * 0x38; +} + +void ADLPlayer::setVoices() { + // Definitions of the 9 instruments + for (int i = 0; i < 9; i++) + setVoice(i, i, true); +} + +void ADLPlayer::setVoice(byte voice, byte instr, bool set) { + uint16 strct[27]; + byte channel; + byte *dataPtr; + + // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 + // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 + for (int i = 0; i < 2; i++) { + dataPtr = _data + 3 + instr * 0x38 + i * 0x1A; + for (int j = 0; j < 27; j++) { + strct[j] = READ_LE_UINT16(dataPtr); + dataPtr += 2; + } + channel = _operators[voice] + i * 3; + writeOPL(0xBD, 0x00); + writeOPL(0x08, 0x00); + writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); + if (!i) + writeOPL(0xC0 | voice, + ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); + writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); + writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); + writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | + ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | + ((strct[11] & 1) << 4) | (strct[1] & 0xF)); + if (!i) + writeOPL(0xE0 | channel, (strct[26] & 3)); + else + writeOPL(0xE0 | channel, (strct[14] & 3)); + if (i && set) + writeOPL(0x40 | channel, 0); + } +} + + +MDYPlayer::MDYPlayer(Audio::Mixer &mixer) : AdLib(mixer) { + init(); +} + +MDYPlayer::~MDYPlayer() { +} + +void MDYPlayer::init() { + _soundMode = 0; + + _timbres = 0; + _tbrCount = 0; + _tbrStart = 0; + _timbresSize = 0; +} + +bool MDYPlayer::loadMDY(Common::SeekableReadStream &stream) { + unloadMDY(); + + _freeData = true; + + byte mdyHeader[70]; + stream.read(mdyHeader, 70); + + _tickBeat = mdyHeader[36]; + _beatMeasure = mdyHeader[37]; + _totalTick = mdyHeader[38] + (mdyHeader[39] << 8) + (mdyHeader[40] << 16) + (mdyHeader[41] << 24); + _dataSize = mdyHeader[42] + (mdyHeader[43] << 8) + (mdyHeader[44] << 16) + (mdyHeader[45] << 24); + _nrCommand = mdyHeader[46] + (mdyHeader[47] << 8) + (mdyHeader[48] << 16) + (mdyHeader[49] << 24); +// _soundMode is either 0 (melodic) or 1 (percussive) + _soundMode = mdyHeader[58]; + _pitchBendRangeStep = 25*mdyHeader[59]; + _basicTempo = mdyHeader[60] + (mdyHeader[61] << 8); + + if (_pitchBendRangeStep < 25) + _pitchBendRangeStep = 25; + else if (_pitchBendRangeStep > 300) + _pitchBendRangeStep = 300; + + _data = new byte[_dataSize]; + stream.read(_data, _dataSize); + + reset(); + _playPos = _data; + + return true; +} + +bool MDYPlayer::loadMDY(const char *fileName) { Common::File song; - unload(); song.open(fileName); if (!song.isOpen()) return false; - _needFree = true; - _dataSize = song.size(); - _data = new byte[_dataSize]; - song.read(_data, _dataSize); - song.close(); + bool loaded = loadMDY(song); - reset(); - setVoices(); - _playPos = _data + 3 + (_data[1] + 1) * 0x38; + song.close(); - return true; + return loaded; } -bool AdLib::load(byte *data, uint32 size, int index) { - unload(); - _repCount = 0; +bool MDYPlayer::loadTBR(Common::SeekableReadStream &stream) { + unloadTBR(); - _dataSize = size; - _data = data; - _index = index; + _timbresSize = stream.size(); + + _timbres = new byte[_timbresSize]; + stream.read(_timbres, _timbresSize); reset(); setVoices(); - _playPos = _data + 3 + (_data[1] + 1) * 0x38; return true; } -void AdLib::unload() { - _playing = false; - _index = -1; +bool MDYPlayer::loadTBR(const char *fileName) { + Common::File timbres; - if (_data && _needFree) - delete[] _data; + timbres.open(fileName); + if (!timbres.isOpen()) + return false; + + bool loaded = loadTBR(timbres); - _needFree = false; + timbres.close(); + + return loaded; } -bool AdLib::isPlaying() const { - return _playing; +void MDYPlayer::unload() { + unloadTBR(); + unloadMDY(); } -bool AdLib::getRepeating() const { - return _repCount != 0; +void MDYPlayer::unloadMDY() { + AdLib::unload(); } -void AdLib::setRepeating(int32 repCount) { - _repCount = repCount; +void MDYPlayer::unloadTBR() { + delete[] _timbres; + + _timbres = 0; + _timbresSize = 0; } -int AdLib::getIndex() const { - return _index; +void MDYPlayer::interpret() { + unsigned char instr; + byte channel; + byte note; + byte volume; + uint8 tempoMult, tempoFrac; + uint8 ctrlByte1, ctrlByte2; + uint8 timbre; + + if (_first) { + for (int i = 0; i < 11; i ++) + setVolume(i, 0); + +// TODO : Set pitch range + + _tempo = _basicTempo; + _wait = *(_playPos++); + _first = false; + } + do { + instr = *_playPos; +// printf("instr 0x%X\n", instr); + switch(instr) { + case 0xF8: + _wait = *(_playPos++); + break; + case 0xFC: + _ended = true; + _samplesTillPoll = 0; + return; + case 0xF0: + _playPos++; + ctrlByte1 = *(_playPos++); + ctrlByte2 = *(_playPos++); + if (ctrlByte1 != 0x7F || ctrlByte2 != 0) { + _playPos -= 2; + while (*(_playPos++) != 0xF7); + } else { + tempoMult = *(_playPos++); + tempoFrac = *(_playPos++); + _tempo = _basicTempo * tempoMult + (unsigned)(((long)_basicTempo * tempoFrac) >> 7); + _playPos++; + } + _wait = *(_playPos++); + break; + default: + if (instr >= 0x80) { + _playPos++; + } + channel = (int)(instr & 0x0f); + + switch(instr & 0xf0) { + case 0x90: + note = *(_playPos++); + volume = *(_playPos++); + _pollNotes[channel] = note; + setVolume(channel, volume); + setKey(channel, note, true, false); + break; + case 0x80: + _playPos += 2; + note = _pollNotes[channel]; + setKey(channel, note, false, false); + break; + case 0xA0: + setVolume(channel, *(_playPos++)); + break; + case 0xC0: + timbre = *(_playPos++); + setVoice(channel, timbre, false); + break; + case 0xE0: + warning("MDYPlayer: Pitch bend not yet implemented"); + + note = *(_playPos)++; + note += (unsigned)(*(_playPos++)) << 7; + + setKey(channel, note, _notOn[channel], true); + + break; + case 0xB0: + _playPos += 2; + break; + case 0xD0: + _playPos++; + break; + default: + warning("MDYPlayer: Bad MIDI instr byte: 0%X", instr); + while ((*_playPos) < 0x80) + _playPos++; + if (*_playPos != 0xF8) + _playPos--; + break; + } //switch instr & 0xF0 + _wait = *(_playPos++); + break; + } //switch instr + } while (_wait == 0); + + if (_wait == 0xF8) { + _wait = 0xF0; + if (*_playPos != 0xF8) + _wait += *(_playPos++); + } +// _playPos++; + _samplesTillPoll = _wait * (_rate / 1000); } -void AdLib::startPlay() { - if (_data) _playing = true; +void MDYPlayer::reset() { + AdLib::reset(); + +// _soundMode 1 : Percussive mode. + if (_soundMode == 1) { + writeOPL(0xA6, 0); + writeOPL(0xB6, 0); + writeOPL(0xA7, 0); + writeOPL(0xB7, 0); + writeOPL(0xA8, 0); + writeOPL(0xB8, 0); + +// TODO set the correct frequency for the last 4 percussive voices + } } -void AdLib::stopPlay() { - Common::StackLock slock(_mutex); - _playing = false; +void MDYPlayer::rewind() { + _playPos = _data; +} + +void MDYPlayer::setVoices() { + byte *timbrePtr; + + timbrePtr = _timbres; + debugC(6, kDebugSound, "TBR version: %X.%X", timbrePtr[0], timbrePtr[1]); + timbrePtr += 2; + + _tbrCount = READ_LE_UINT16(timbrePtr); + debugC(6, kDebugSound, "Timbres counter: %d", _tbrCount); + timbrePtr += 2; + _tbrStart = READ_LE_UINT16(timbrePtr); + + timbrePtr += 2; + for (int i = 0; i < _tbrCount ; i++) + setVoice(i, i, true); +} + +void MDYPlayer::setVoice(byte voice, byte instr, bool set) { + uint16 strct[27]; + byte channel; + byte *timbrePtr; + char timbreName[10]; + + timbreName[9] = '\0'; + for (int j = 0; j < 9; j++) + timbreName[j] = _timbres[6 + j + (instr * 9)]; + debugC(6, kDebugSound, "Loading timbre %s", timbreName); + + // i = 0 : 0 1 2 3 4 5 6 7 8 9 10 11 12 26 + // i = 1 : 13 14 15 16 17 18 19 20 21 22 23 24 25 27 + for (int i = 0; i < 2; i++) { + timbrePtr = _timbres + _tbrStart + instr * 0x38 + i * 0x1A; + for (int j = 0; j < 27; j++) { + if (timbrePtr >= (_timbres + _timbresSize)) { + warning("MDYPlayer: Instrument %d out of range (%d, %d)", instr, + (uint32) (timbrePtr - _timbres), _timbresSize); + strct[j] = 0; + } else + strct[j] = READ_LE_UINT16(timbrePtr); + timbrePtr += 2; + } + channel = _operators[voice] + i * 3; + writeOPL(0xBD, 0x00); + writeOPL(0x08, 0x00); + writeOPL(0x40 | channel, ((strct[0] & 3) << 6) | (strct[8] & 0x3F)); + if (!i) + writeOPL(0xC0 | voice, + ((strct[2] & 7) << 1) | (1 - (strct[12] & 1))); + writeOPL(0x60 | channel, ((strct[3] & 0xF) << 4) | (strct[6] & 0xF)); + writeOPL(0x80 | channel, ((strct[4] & 0xF) << 4) | (strct[7] & 0xF)); + writeOPL(0x20 | channel, ((strct[9] & 1) << 7) | + ((strct[10] & 1) << 6) | ((strct[5] & 1) << 5) | + ((strct[11] & 1) << 4) | (strct[1] & 0xF)); + if (!i) + writeOPL(0xE0 | channel, (strct[26] & 3)); + else { + writeOPL(0xE0 | channel, (strct[14] & 3)); + writeOPL(0x40 | channel, 0); + } + } } } // End of namespace Gob diff --git a/engines/gob/sound/adlib.h b/engines/gob/sound/adlib.h index 4cd83d5883..3f7b46643f 100644 --- a/engines/gob/sound/adlib.h +++ b/engines/gob/sound/adlib.h @@ -38,7 +38,7 @@ class GobEngine; class AdLib : public Audio::AudioStream { public: AdLib(Audio::Mixer &mixer); - ~AdLib(); + virtual ~AdLib(); bool isPlaying() const; int getIndex() const; @@ -49,9 +49,7 @@ public: void startPlay(); void stopPlay(); - bool load(const char *fileName); - bool load(byte *data, uint32 size, int index = -1); - void unload(); + virtual void unload(); // AudioStream API int readBuffer(int16 *buffer, const int numSamples); @@ -89,18 +87,88 @@ protected: bool _playing; bool _first; bool _ended; - bool _needFree; + + bool _freeData; int _index; + unsigned char _wait; + uint8 _tickBeat; + uint8 _beatMeasure; + uint32 _totalTick; + uint32 _nrCommand; + uint16 _pitchBendRangeStep; + uint16 _basicTempo, _tempo; + void writeOPL(byte reg, byte val); void setFreqs(); - void reset(); - void setVoices(); - void setVoice(byte voice, byte instr, bool set); void setKey(byte voice, byte note, bool on, bool spec); void setVolume(byte voice, byte volume); void pollMusic(); + + virtual void interpret() = 0; + + virtual void reset(); + virtual void rewind() = 0; + virtual void setVoices() = 0; + +private: + void init(); +}; + +class ADLPlayer : public AdLib { +public: + ADLPlayer(Audio::Mixer &mixer); + ~ADLPlayer(); + + bool load(const char *fileName); + bool load(byte *data, uint32 size, int index = -1); + + void unload(); + +protected: + void interpret(); + + void reset(); + void rewind(); + + void setVoices(); + void setVoice(byte voice, byte instr, bool set); +}; + +class MDYPlayer : public AdLib { +public: + MDYPlayer(Audio::Mixer &mixer); + ~MDYPlayer(); + + bool loadMDY(const char *fileName); + bool loadMDY(Common::SeekableReadStream &stream); + bool loadTBR(const char *fileName); + bool loadTBR(Common::SeekableReadStream &stream); + + void unload(); + +protected: + byte _soundMode; + + byte *_timbres; + uint16 _tbrCount; + uint16 _tbrStart; + uint32 _timbresSize; + + void interpret(); + + void reset(); + void rewind(); + + void setVoices(); + void setVoice(byte voice, byte instr, bool set); + + void unloadTBR(); + void unloadMDY(); + +private: + void init(); }; } // End of namespace Gob diff --git a/engines/gob/sound/bgatmosphere.cpp b/engines/gob/sound/bgatmosphere.cpp index 12ceb031b7..6ce184155e 100644 --- a/engines/gob/sound/bgatmosphere.cpp +++ b/engines/gob/sound/bgatmosphere.cpp @@ -27,6 +27,7 @@ #include "common/events.h" #include "gob/sound/bgatmosphere.h" +#include "gob/sound/sounddesc.h" namespace Gob { diff --git a/engines/gob/sound/bgatmosphere.h b/engines/gob/sound/bgatmosphere.h index 3fa648b94d..aa8cf58e10 100644 --- a/engines/gob/sound/bgatmosphere.h +++ b/engines/gob/sound/bgatmosphere.h @@ -29,11 +29,12 @@ #include "sound/mixer.h" #include "common/mutex.h" -#include "gob/sound/sounddesc.h" #include "gob/sound/soundmixer.h" namespace Gob { +class SoundDesc; + class BackgroundAtmosphere : private SoundMixer { public: enum PlayMode { diff --git a/engines/gob/sound/cdrom.cpp b/engines/gob/sound/cdrom.cpp index ec9b2aaccb..4d6a7ec966 100644 --- a/engines/gob/sound/cdrom.cpp +++ b/engines/gob/sound/cdrom.cpp @@ -30,6 +30,7 @@ #include "gob/gob.h" #include "gob/sound/cdrom.h" #include "gob/helper.h" +#include "gob/dataio.h" namespace Gob { @@ -86,7 +87,7 @@ void CDROM::startTrack(const char *trackName) { byte *matchPtr = getTrackBuffer(trackName); if (!matchPtr) { - warning("Track \"%s\" not found", trackName); + warning("CDROM: Track \"%s\" not found", trackName); return; } diff --git a/engines/gob/sound/cdrom.h b/engines/gob/sound/cdrom.h index 201f7adb75..6f01e6f90a 100644 --- a/engines/gob/sound/cdrom.h +++ b/engines/gob/sound/cdrom.h @@ -26,10 +26,10 @@ #ifndef GOB_SOUND_CDROM_H #define GOB_SOUND_CDROM_H -#include "gob/dataio.h" - namespace Gob { +class DataStream; + class CDROM { public: CDROM(); diff --git a/engines/gob/sound/infogrames.cpp b/engines/gob/sound/infogrames.cpp index 0b46f3485c..c955dba43f 100644 --- a/engines/gob/sound/infogrames.cpp +++ b/engines/gob/sound/infogrames.cpp @@ -55,7 +55,7 @@ bool Infogrames::loadSong(const char *fileName) { _mixer->getOutputRate(), _mixer->getOutputRate() / 75); if (!_song->load(fileName)) { - warning("Couldn't load infogrames music"); + warning("Infogrames: Couldn't load music \"%s\"", fileName); clearSong(); return false; } @@ -92,7 +92,7 @@ void Infogrames::clearSong() { bool Infogrames::loadInst(const char *fileName) { _instruments = new Audio::Infogrames::Instruments; if (!_instruments->load(fileName)) { - warning("Couldn't load instruments file"); + warning("Infogrames: Couldn't load instruments \"%s\"", fileName); clearInstruments(); return false; } diff --git a/engines/gob/sound/protracker.cpp b/engines/gob/sound/protracker.cpp index 891580ef40..3e33cfd494 100644 --- a/engines/gob/sound/protracker.cpp +++ b/engines/gob/sound/protracker.cpp @@ -25,6 +25,8 @@ #include "common/file.h" +#include "sound/mods/protracker.h" + #include "gob/sound/protracker.h" namespace Gob { diff --git a/engines/gob/sound/protracker.h b/engines/gob/sound/protracker.h index 6270530427..73cae0d510 100644 --- a/engines/gob/sound/protracker.h +++ b/engines/gob/sound/protracker.h @@ -28,7 +28,6 @@ #include "sound/mixer.h" #include "sound/audiostream.h" -#include "sound/mods/protracker.h" namespace Gob { diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp index f0cf17b989..d3afc9baa3 100644 --- a/engines/gob/sound/sound.cpp +++ b/engines/gob/sound/sound.cpp @@ -31,20 +31,28 @@ #include "gob/game.h" #include "gob/inter.h" +#include "gob/sound/pcspeaker.h" +#include "gob/sound/soundblaster.h" +#include "gob/sound/adlib.h" +#include "gob/sound/infogrames.h" +#include "gob/sound/protracker.h" +#include "gob/sound/cdrom.h" + namespace Gob { Sound::Sound(GobEngine *vm) : _vm(vm) { _pcspeaker = new PCSpeaker(*_vm->_mixer); _blaster = new SoundBlaster(*_vm->_mixer); - _adlib = 0; + _adlPlayer = 0; + _mdyPlayer = 0; _infogrames = 0; _protracker = 0; _cdrom = 0; _bgatmos = 0; - if (!_vm->_noMusic && _vm->hasAdlib()) - _adlib = new AdLib(*_vm->_mixer); + _hasAdLib = (!_vm->_noMusic && _vm->hasAdlib()); + if (!_vm->_noMusic && (_vm->getPlatform() == Common::kPlatformAmiga)) { _infogrames = new Infogrames(*_vm->_mixer); _protracker = new Protracker(*_vm->_mixer); @@ -62,7 +70,8 @@ Sound::Sound(GobEngine *vm) : _vm(vm) { Sound::~Sound() { delete _pcspeaker; delete _blaster; - delete _adlib; + delete _adlPlayer; + delete _mdyPlayer; delete _infogrames; delete _protracker; delete _cdrom; @@ -105,14 +114,11 @@ bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, debugC(2, kDebugSound, "Loading sample \"%s\"", fileName); - int16 handle = _vm->_dataIO->openData(fileName); - if (handle < 0) { + if (!_vm->_dataIO->existData(fileName)) { warning("Can't open sample file \"%s\"", fileName); return false; } - _vm->_dataIO->closeData(handle); - byte *data; uint32 size; @@ -121,7 +127,7 @@ bool Sound::sampleLoad(SoundDesc *sndDesc, SoundType type, const char *fileName, return false; size = _vm->_dataIO->getDataSize(fileName); - return sndDesc->load(type, SOUND_FILE, data, size); + return sndDesc->load(type, data, size); } void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdlib, int index) { @@ -130,9 +136,14 @@ void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdlib, int index) { if (sndDesc->getType() == SOUND_ADL) { - if (_adlib && noteAdlib) - if ((index == -1) || (_adlib->getIndex() == index)) - _adlib->stopPlay(); + if (noteAdlib) { + if (_adlPlayer) + if ((index == -1) || (_adlPlayer->getIndex() == index)) + _adlPlayer->stopPlay(); + if (_mdyPlayer) + if ((index == -1) || (_mdyPlayer->getIndex() == index)) + _mdyPlayer->stopPlay(); + } } else { @@ -223,50 +234,112 @@ void Sound::infogramesStop() { _infogrames->stop(); } -bool Sound::adlibLoad(const char *fileName) { - if (!_adlib) +bool Sound::adlibLoadADL(const char *fileName) { + if (!_hasAdLib) return false; - debugC(1, kDebugSound, "Adlib: Loading data (\"%s\")", fileName); + if (!_adlPlayer) + _adlPlayer = new ADLPlayer(*_vm->_mixer); + + debugC(1, kDebugSound, "Adlib: Loading ADL data (\"%s\")", fileName); - return _adlib->load(fileName); + return _adlPlayer->load(fileName); } -bool Sound::adlibLoad(byte *data, uint32 size, int index) { - if (!_adlib) +bool Sound::adlibLoadADL(byte *data, uint32 size, int index) { + if (!_hasAdLib) return false; - debugC(1, kDebugSound, "Adlib: Loading data (%d)", index); + if (!_adlPlayer) + _adlPlayer = new ADLPlayer(*_vm->_mixer); + + debugC(1, kDebugSound, "Adlib: Loading ADL data (%d)", index); - return _adlib->load(data, size, index); + return _adlPlayer->load(data, size, index); } void Sound::adlibUnload() { - if (!_adlib) + if (!_hasAdLib) return; debugC(1, kDebugSound, "Adlib: Unloading data"); - _adlib->unload(); + if (_adlPlayer) + _adlPlayer->unload(); + if (_mdyPlayer) + _mdyPlayer->unload(); +} + +bool Sound::adlibLoadMDY(const char *fileName) { + if (!_hasAdLib) + return false; + + if (!_mdyPlayer) + _mdyPlayer = new MDYPlayer(*_vm->_mixer); + + debugC(1, kDebugSound, "Adlib: Loading MDY data (\"%s\")", fileName); + + if (!_vm->_dataIO->existData(fileName)) { + warning("Can't open MDY file \"%s\"", fileName); + return false; + } + + DataStream *stream = _vm->_dataIO->getDataStream(fileName); + + bool loaded = _mdyPlayer->loadMDY(*stream); + + delete stream; + + return loaded; +} + +bool Sound::adlibLoadTBR(const char *fileName) { + if (!_hasAdLib) + return false; + + if (!_mdyPlayer) + _mdyPlayer = new MDYPlayer(*_vm->_mixer); + + if (!_vm->_dataIO->existData(fileName)) { + warning("Can't open TBR file \"%s\"", fileName); + return false; + } + + debugC(1, kDebugSound, "Adlib: Loading MDY instruments (\"%s\")", fileName); + + DataStream *stream = _vm->_dataIO->getDataStream(fileName); + + bool loaded = _mdyPlayer->loadTBR(*stream); + + delete stream; + + return loaded; } void Sound::adlibPlayTrack(const char *trackname) { - if (!_adlib || _adlib->isPlaying()) + if (!_hasAdLib) return; - debugC(1, kDebugSound, "Adlib: Playing track \"%s\"", trackname); + if (!_adlPlayer) + _adlPlayer = new ADLPlayer(*_vm->_mixer); - _adlib->unload(); - _adlib->load(trackname); - _adlib->startPlay(); + if (_adlPlayer->isPlaying()) + return; + + debugC(1, kDebugSound, "Adlib: Playing ADL track \"%s\"", trackname); + + _adlPlayer->unload(); + _adlPlayer->load(trackname); + _adlPlayer->startPlay(); } void Sound::adlibPlayBgMusic() { - int track; - - if (!_adlib) + if (!_hasAdLib) return; + if (!_adlPlayer) + _adlPlayer = new ADLPlayer(*_vm->_mixer); + static const char *tracksMac[] = { // "musmac1.adl", // TODO: This track isn't played correctly at all yet "musmac2.adl", @@ -285,58 +358,82 @@ void Sound::adlibPlayBgMusic() { }; if (_vm->getPlatform() == Common::kPlatformWindows) { - track = _vm->_util->getRandom(ARRAYSIZE(tracksWin)); + int track = _vm->_util->getRandom(ARRAYSIZE(tracksWin)); adlibPlayTrack(tracksWin[track]); } else { - track = _vm->_util->getRandom(ARRAYSIZE(tracksMac)); + int track = _vm->_util->getRandom(ARRAYSIZE(tracksMac)); adlibPlayTrack(tracksMac[track]); } } void Sound::adlibPlay() { - if (!_adlib) + if (!_hasAdLib) return; debugC(1, kDebugSound, "Adlib: Starting playback"); - _adlib->startPlay(); + if (_adlPlayer) + _adlPlayer->startPlay(); + if (_mdyPlayer) + _mdyPlayer->startPlay(); } void Sound::adlibStop() { - if (!_adlib) + if (!_hasAdLib) return; debugC(1, kDebugSound, "Adlib: Stopping playback"); - _adlib->stopPlay(); + if (_adlPlayer) + _adlPlayer->stopPlay(); + if (_mdyPlayer) + _mdyPlayer->stopPlay(); } bool Sound::adlibIsPlaying() const { - if (!_adlib) + if (!_hasAdLib) return false; - return _adlib->isPlaying(); + if (_adlPlayer && _adlPlayer->isPlaying()) + return true; + if (_mdyPlayer && _mdyPlayer->isPlaying()) + return true; + + return false; } int Sound::adlibGetIndex() const { - if (!_adlib) + if (!_hasAdLib) return -1; - return _adlib->getIndex(); + if (_adlPlayer) + return _adlPlayer->getIndex(); + if (_mdyPlayer) + return _mdyPlayer->getIndex(); + + return -1; } bool Sound::adlibGetRepeating() const { - if (!_adlib) + if (!_hasAdLib) return false; - return _adlib->getRepeating(); + if (_adlPlayer) + return _adlPlayer->getRepeating(); + if (_mdyPlayer) + return _mdyPlayer->getRepeating(); + + return false; } void Sound::adlibSetRepeating(int32 repCount) { - if (!_adlib) + if (!_hasAdLib) return; - _adlib->setRepeating(repCount); + if (_adlPlayer) + _adlPlayer->setRepeating(repCount); + if (_mdyPlayer) + _mdyPlayer->setRepeating(repCount); } void Sound::blasterPlay(SoundDesc *sndDesc, int16 repCount, @@ -425,17 +522,12 @@ void Sound::cdLoadLIC(const char *fname) { debugC(1, kDebugSound, "CDROM: Loading LIC \"%s\"", fname); - int handle = _vm->_dataIO->openData(fname); - - if (handle == -1) + if (!_vm->_dataIO->existData(fname)) return; - _vm->_dataIO->closeData(handle); - _vm->_dataIO->getUnpackedData(fname); - handle = _vm->_dataIO->openData(fname); - DataStream *stream = _vm->_dataIO->openAsStream(handle, true); + DataStream *stream = _vm->_dataIO->getDataStream(fname); _cdrom->readLIC(*stream); diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h index dbdd580ec7..6f6c1d0469 100644 --- a/engines/gob/sound/sound.h +++ b/engines/gob/sound/sound.h @@ -27,16 +27,19 @@ #define GOB_SOUND_SOUND_H #include "gob/sound/sounddesc.h" -#include "gob/sound/pcspeaker.h" -#include "gob/sound/soundblaster.h" -#include "gob/sound/adlib.h" -#include "gob/sound/infogrames.h" -#include "gob/sound/protracker.h" -#include "gob/sound/cdrom.h" #include "gob/sound/bgatmosphere.h" namespace Gob { +class GobEngine; +class PCSpeaker; +class SoundBlaster; +class ADLPlayer; +class MDYPlayer; +class Infogrames; +class Protracker; +class CDROM; + class Sound { public: static const int kSoundsCount = 60; @@ -77,8 +80,10 @@ public: // AdLib - bool adlibLoad(const char *fileName); - bool adlibLoad(byte *data, uint32 size, int index = -1); + bool adlibLoadADL(const char *fileName); + bool adlibLoadADL(byte *data, uint32 size, int index = -1); + bool adlibLoadMDY(const char *fileName); + bool adlibLoadTBR(const char *fileName); void adlibUnload(); void adlibPlayTrack(const char *trackname); @@ -139,11 +144,14 @@ public: private: GobEngine *_vm; + bool _hasAdLib; + SoundDesc _sounds[kSoundsCount]; PCSpeaker *_pcspeaker; SoundBlaster *_blaster; - AdLib *_adlib; + ADLPlayer *_adlPlayer; + MDYPlayer *_mdyPlayer; Infogrames *_infogrames; Protracker *_protracker; CDROM *_cdrom; diff --git a/engines/gob/sound/soundblaster.cpp b/engines/gob/sound/soundblaster.cpp index 23eea90688..69610dc949 100644 --- a/engines/gob/sound/soundblaster.cpp +++ b/engines/gob/sound/soundblaster.cpp @@ -24,6 +24,7 @@ */ #include "gob/sound/soundblaster.h" +#include "gob/sound/sounddesc.h" namespace Gob { diff --git a/engines/gob/sound/soundblaster.h b/engines/gob/sound/soundblaster.h index c57e4a443e..a2dc87267c 100644 --- a/engines/gob/sound/soundblaster.h +++ b/engines/gob/sound/soundblaster.h @@ -29,11 +29,12 @@ #include "common/mutex.h" #include "sound/mixer.h" -#include "gob/sound/sounddesc.h" #include "gob/sound/soundmixer.h" namespace Gob { +class SoundDesc; + class SoundBlaster : public SoundMixer { public: SoundBlaster(Audio::Mixer &mixer); diff --git a/engines/gob/sound/sounddesc.cpp b/engines/gob/sound/sounddesc.cpp index c4c78eebbd..b9b327d105 100644 --- a/engines/gob/sound/sounddesc.cpp +++ b/engines/gob/sound/sounddesc.cpp @@ -29,15 +29,17 @@ #include "sound/wave.h" #include "gob/sound/sounddesc.h" +#include "gob/resources.h" namespace Gob { SoundDesc::SoundDesc() { + _resource = 0; + _data = _dataPtr = 0; _size = 0; _type = SOUND_SND; - _source = SOUND_FILE; _repCount = 0; _frequency = 0; @@ -50,23 +52,31 @@ SoundDesc::~SoundDesc() { free(); } -void SoundDesc::set(SoundType type, SoundSource src, - byte *data, uint32 dSize) { - +void SoundDesc::set(SoundType type, byte *data, uint32 dSize) { free(); _type = type; - _source = src; _data = _dataPtr = data; _size = dSize; } -bool SoundDesc::load(SoundType type, SoundSource src, - byte *data, uint32 dSize) { +void SoundDesc::set(SoundType type, Resource *resource) { + byte *data = 0; + uint32 dSize = 0; + + if (resource && (resource->getSize() > 0)) { + data = resource->getData(); + dSize = resource->getSize(); + } + + set(type, data, dSize); + _resource = resource; +} + +bool SoundDesc::load(SoundType type, byte *data, uint32 dSize) { free(); - _source = src; switch (type) { case SOUND_ADL: return loadADL(data, dSize); @@ -79,10 +89,28 @@ bool SoundDesc::load(SoundType type, SoundSource src, return false; } +bool SoundDesc::load(SoundType type, Resource *resource) { + if (!resource || (resource->getSize() <= 0)) + return false; + + if (!load(type, resource->getData(), resource->getSize())) + return false; + + _resource = resource; + return true; +} + void SoundDesc::free() { - if (_source != SOUND_TOT) - delete[] _data; - _data = _dataPtr = 0; + if (_resource) { + delete _resource; + _data = 0; + } + + delete[] _data; + + _resource = 0; + _data = 0; + _dataPtr = 0; _id = 0; } diff --git a/engines/gob/sound/sounddesc.h b/engines/gob/sound/sounddesc.h index 83efd61e6d..9e5d20e138 100644 --- a/engines/gob/sound/sounddesc.h +++ b/engines/gob/sound/sounddesc.h @@ -30,18 +30,14 @@ namespace Gob { +class Resource; + enum SoundType { SOUND_SND, SOUND_WAV, SOUND_ADL }; -enum SoundSource { - SOUND_FILE, - SOUND_TOT, - SOUND_EXT -}; - class SoundDesc { public: int16 _repCount; @@ -58,8 +54,11 @@ public: bool isId(int16 id) const { return _dataPtr && (_id == id); } - void set(SoundType type, SoundSource src, byte *data, uint32 dSize); - bool load(SoundType type, SoundSource src, byte *data, uint32 dSize); + void set(SoundType type, byte *data, uint32 dSize); + void set(SoundType type, Resource *resource); + bool load(SoundType type, byte *data, uint32 dSize); + bool load(SoundType type, Resource *resource); + void free(); void convToSigned(); @@ -71,12 +70,12 @@ public: ~SoundDesc(); private: + Resource *_resource; byte *_data; byte *_dataPtr; uint32 _size; SoundType _type; - SoundSource _source; bool loadSND(byte *data, uint32 dSize); bool loadWAV(byte *data, uint32 dSize); diff --git a/engines/gob/sound/soundmixer.cpp b/engines/gob/sound/soundmixer.cpp index ea1dd2ef82..68a96d3b01 100644 --- a/engines/gob/sound/soundmixer.cpp +++ b/engines/gob/sound/soundmixer.cpp @@ -24,6 +24,7 @@ */ #include "gob/sound/soundmixer.h" +#include "gob/sound/sounddesc.h" namespace Gob { diff --git a/engines/gob/sound/soundmixer.h b/engines/gob/sound/soundmixer.h index f32beb149f..20376b5152 100644 --- a/engines/gob/sound/soundmixer.h +++ b/engines/gob/sound/soundmixer.h @@ -31,10 +31,10 @@ #include "sound/audiostream.h" #include "sound/mixer.h" -#include "gob/sound/sounddesc.h" - namespace Gob { +class SoundDesc; + class SoundMixer : public Audio::AudioStream { public: SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type); diff --git a/engines/gob/totfile.cpp b/engines/gob/totfile.cpp new file mode 100644 index 0000000000..bbf62c143b --- /dev/null +++ b/engines/gob/totfile.cpp @@ -0,0 +1,135 @@ +/* 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 "common/str.h" +#include "common/stream.h" + +#include "gob/gob.h" +#include "gob/totfile.h" +#include "gob/dataio.h" +#include "gob/videoplayer.h" + +namespace Gob { + +TOTFile::TOTFile(GobEngine *vm) : _vm(vm) { + _stream = 0; + + memset(_header, 0, 128); +} + +TOTFile::~TOTFile() { + unload(); +} + +bool TOTFile::load(const Common::String &fileName) { + // Trying to open normally + _stream = _vm->_dataIO->getDataStream(fileName.c_str()); + + if (!_stream) + // Trying to open from video + _stream = _vm->_vidPlayer->getExtraData(fileName.c_str()); + + if (!_stream) + return false; + + if (_stream->read(_header, 128) != 128) + return false; + + _stream->seek(0); + + return true; +} + +void TOTFile::unload() { + delete _stream; + + _stream = 0; +} + +Common::SeekableReadStream *TOTFile::getStream() const { + return _stream; +} + +bool TOTFile::getProperties(Properties &props) const { + if (!_stream) + return false; + + // Offset 39-41: Version in "Major.Minor" string form + if (_header[40] != '.') + return false; + + props.versionMajor = _header[39] - '0'; + props.versionMinor = _header[41] - '0'; + + props.variablesCount = READ_LE_UINT32(_header + 44); + + props.textsOffset = READ_LE_UINT32(_header + 48); + props.resourcesOffset = READ_LE_UINT32(_header + 52); + + props.animDataSize = READ_LE_UINT16(_header + 56); + + props.imFileNumber = _header[59]; + props.exFileNumber = _header[60]; + props.communHandling = _header[61]; + + for (int i = 0; i < 14; i++) + props.functions[i] = READ_LE_UINT16(_header + 100 + i * 2); + + props.scriptEnd = _stream->size(); + if (props.textsOffset > 0) + props.scriptEnd = MIN(props.scriptEnd, props.textsOffset); + if (props.resourcesOffset > 0) + props.scriptEnd = MIN(props.scriptEnd, props.resourcesOffset); + + return true; +} + +Common::String TOTFile::createFileName(const Common::String &base, bool &isLOM) { + isLOM = false; + + const char *dot; + if ((dot = strrchr(base.c_str(), '.'))) { + // fileName includes an extension + + if (!scumm_stricmp(dot + 1, "LOM")) + isLOM = true; + + return base; + } + + return base + ".tot"; +} + +Common::String TOTFile::getFileBase(const Common::String &fileName) { + const char *dot; + if ((dot = strrchr(fileName.c_str(), '.'))) { + // fileName includes an extension + return Common::String(fileName.c_str(), dot); + } + + return fileName; +} + +} // End of namespace Gob diff --git a/engines/gob/totfile.h b/engines/gob/totfile.h new file mode 100644 index 0000000000..00963d36a2 --- /dev/null +++ b/engines/gob/totfile.h @@ -0,0 +1,80 @@ +/* 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 GOB_TOTFILE_H +#define GOB_TOTFILE_H + +#include "common/str.h" + +namespace Common { + class SeekableReadStream; +} + +namespace Gob { + +class TOTFile { +public: + enum Function { + kFunctionStart = 0, + kFunctionCenter = 13 + }; + + struct Properties { + uint8 versionMajor; + uint8 versionMinor; + uint32 variablesCount; + uint32 textsOffset; + uint32 resourcesOffset; + uint16 animDataSize; + uint8 imFileNumber; + uint8 exFileNumber; + uint8 communHandling; + uint16 functions[14]; + uint32 scriptEnd; + }; + + TOTFile(GobEngine *vm); + ~TOTFile(); + + bool load(const Common::String &fileName); + void unload(); + + Common::SeekableReadStream *getStream() const; + bool getProperties(Properties &props) const; + + static Common::String createFileName(const Common::String &base, bool &isLOM); + static Common::String getFileBase(const Common::String &fileName); + +private: + GobEngine *_vm; + + Common::SeekableReadStream *_stream; + + byte _header[128]; +}; + +} // End of namespace Gob + +#endif // GOB_TOTFILE_H diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index e1148dacb9..b0e7691c07 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -331,6 +331,12 @@ void Util::setFrameRate(int16 rate) { _frameRate = rate; _frameWaitTime = 1000 / rate; _startFrameTime = getTimeKey(); + _frameWaitLag = 0; +} + +void Util::notifyNewAnim() { + _startFrameTime = getTimeKey(); + _frameWaitLag = 0; } void Util::waitEndFrame() { diff --git a/engines/gob/util.h b/engines/gob/util.h index 3d7520fe69..0a76ee40ab 100644 --- a/engines/gob/util.h +++ b/engines/gob/util.h @@ -76,6 +76,7 @@ public: void clearPalette(void); int16 getFrameRate(); void setFrameRate(int16 rate); + void notifyNewAnim(); void waitEndFrame(); void setScrollOffset(int16 x = -1, int16 y = -1); diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index e82805d6ac..6c07d22333 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -201,15 +201,11 @@ bool VideoPlayer::findFile(char *fileName, Type &which) { int i; for (i = 0; i < ARRAYSIZE(_extensions); i++) { if ((which == kVideoTypeTry) || (which == ((Type) i))) { - int16 handle; - fileName[len] = '.'; fileName[len + 1] = 0; strcat(fileName, _extensions[i]); - handle = _vm->_dataIO->openData(fileName); - if (handle >= 0) { - _vm->_dataIO->closeData(handle); + if (_vm->_dataIO->existData(fileName)) { which = (Type) i; break; } diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp index 8d0e466bba..14f1c6463c 100644 --- a/engines/groovie/detection.cpp +++ b/engines/groovie/detection.cpp @@ -48,8 +48,6 @@ static const PlainGameDescriptor groovieGames[] = { {0, 0} }; -using Common::GUIO_NONE; - static const GroovieGameDescription gameDescriptions[] = { // The 7th Guest DOS English @@ -57,7 +55,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "t7g", "", AD_ENTRY1s("script.grv", "d1b8033b40aa67c076039881eccce90d", 16659), - Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, Common::GUIO_NONE }, kGroovieT7G, 0 }, @@ -67,7 +65,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "t7g", "", AD_ENTRY1s("script.grv", "6e30b54b1f3bc2262cdcf7961db2ae67", 17191), - Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, GUIO_NONE + Common::EN_ANY, Common::kPlatformMacintosh, ADGF_NO_FLAGS, Common::GUIO_NONE }, kGroovieT7G, 0 }, @@ -81,7 +79,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "intro.gjd", 0, NULL, 31711554}, { NULL, 0, NULL, 0} }, - Common::RU_RUS, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + Common::RU_RUS, Common::kPlatformPC, ADGF_NO_FLAGS, Common::GUIO_NONE }, kGroovieT7G, 0 }, @@ -92,7 +90,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "11h", "", AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227), - Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, Common::GUIO_NONE }, kGroovieV2, 1 }, @@ -102,7 +100,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "11h", "Demo", AD_ENTRY1s("disk.1", "aacb32ce07e0df2894bd83a3dee40c12", 70), - Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, Common::GUIO_NOLAUNCHLOAD }, kGroovieV2, 1 }, @@ -112,7 +110,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "11h", "Making Of", AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227), - Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, Common::GUIO_NOMIDI | Common::GUIO_NOLAUNCHLOAD }, kGroovieV2, 2 }, @@ -122,7 +120,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "clandestiny", "Trailer", AD_ENTRY1s("disk.1", "5c0428cd3659fc7bbcd0aa16485ed5da", 227), - Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, Common::GUIO_NOMIDI | Common::GUIO_NOLAUNCHLOAD }, kGroovieV2, 3 }, @@ -132,7 +130,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "clandestiny", "", AD_ENTRY1s("disk.1", "f79fc1515174540fef6a34132efc4c53", 76), - Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, Common::GUIO_NOMIDI }, kGroovieV2, 1 }, @@ -142,7 +140,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "unclehenry", "", AD_ENTRY1s("disk.1", "0e1b1d3cecc4fc7efa62a968844d1f7a", 72), - Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, Common::GUIO_NOMIDI }, kGroovieV2, 1 }, @@ -152,7 +150,7 @@ static const GroovieGameDescription gameDescriptions[] = { { "tlc", "", AD_ENTRY1s("disk.1", "32a1afa68478f1f9d2b25eeea427f2e3", 84), - Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE + Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, Common::GUIO_NOMIDI }, kGroovieV2, 1 }, @@ -179,7 +177,7 @@ static const ADParams detectionParams = { // Flags kADFlagUseExtraAsHint, // Additional GUI options (for every game} - Common::GUIO_NOMIDI + Common::GUIO_NOSUBTITLES | Common::GUIO_NOSFX }; diff --git a/engines/groovie/groovie.cpp b/engines/groovie/groovie.cpp index 6e18b86062..e2315459d4 100644 --- a/engines/groovie/groovie.cpp +++ b/engines/groovie/groovie.cpp @@ -264,6 +264,11 @@ void GroovieEngine::errorString(const char *buf_input, char *buf_output, int buf void GroovieEngine::syncSoundSettings() { _musicPlayer->setUserVolume(ConfMan.getInt("music_volume")); + // VDX videos just contain one digital audio track, which can be used for + // both SFX or Speech, but the engine doesn't know what they contain, so + // we have to use just one volume setting for videos. + // We use "speech" because most users will want to change the videos + // volume when they can't hear the speech because of the music. _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("speech_volume")); } diff --git a/engines/kyra/animator_mr.cpp b/engines/kyra/animator_mr.cpp index d7139a9e70..faf1b150a2 100644 --- a/engines/kyra/animator_mr.cpp +++ b/engines/kyra/animator_mr.cpp @@ -119,7 +119,7 @@ void KyraEngine_MR::drawSceneAnimObject(AnimObj *obj, int x, int y, int layer) { flags |= 0x8000; x = obj->xPos2 - _sceneAnimMovie[obj->animNum]->xAdd(); y = obj->yPos2 - _sceneAnimMovie[obj->animNum]->yAdd(); - _sceneAnimMovie[obj->animNum]->displayFrame(obj->shapeIndex3, 2, x, y, flags | layer); + _sceneAnimMovie[obj->animNum]->displayFrame(obj->shapeIndex3, 2, x, y, flags | layer, 0, 0); } } } diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp index e0c2c0aa77..d71f7b8b25 100644 --- a/engines/kyra/debugger.cpp +++ b/engines/kyra/debugger.cpp @@ -69,7 +69,7 @@ bool Debugger::cmd_setScreenDebug(int argc, const char **argv) { } bool Debugger::cmd_loadPalette(int argc, const char **argv) { - uint8 palette[768]; + Palette palette(_vm->screen()->getPalette(0).getNumColors()); if (argc <= 1) { DebugPrintf("Use load_palette <file> [start_col] [end_col]\n"); @@ -80,7 +80,7 @@ bool Debugger::cmd_loadPalette(int argc, const char **argv) { uint8 buffer[320*200]; _vm->screen()->copyRegionToBuffer(5, 0, 0, 320, 200, buffer); _vm->screen()->loadBitmap(argv[1], 5, 5, 0); - memcpy(palette, _vm->screen()->getCPagePtr(5), 768); + palette.copy(_vm->screen()->getCPagePtr(5), 0, 256); _vm->screen()->copyBlockToPage(5, 0, 0, 320, 200, buffer); } else if (!_vm->screen()->loadPalette(argv[1], palette)) { DebugPrintf("ERROR: Palette '%s' not found!\n", argv[1]); @@ -88,16 +88,16 @@ bool Debugger::cmd_loadPalette(int argc, const char **argv) { } int startCol = 0; - int endCol = 255; + int endCol = palette.getNumColors(); if (argc > 2) - startCol = MIN(255, MAX(0, atoi(argv[2]))); + startCol = MIN(palette.getNumColors(), MAX(0, atoi(argv[2]))); if (argc > 3) - endCol = MIN(255, MAX(0, atoi(argv[3]))); + endCol = MIN(palette.getNumColors(), MAX(0, atoi(argv[3]))); if (startCol > 0) - memcpy(palette, _vm->screen()->getScreenPalette(), startCol*3); - if (endCol < 255) - memcpy(palette + endCol * 3, _vm->screen()->getScreenPalette() + endCol * 3, (255-endCol)*3); + palette.copy(_vm->screen()->getPalette(0), 0, startCol); + if (endCol < palette.getNumColors()) + palette.copy(_vm->screen()->getPalette(0), endCol); _vm->screen()->setScreenPalette(palette); _vm->screen()->updateScreen(); diff --git a/engines/kyra/gui.cpp b/engines/kyra/gui.cpp index faea2c9a72..85d974f675 100644 --- a/engines/kyra/gui.cpp +++ b/engines/kyra/gui.cpp @@ -83,17 +83,21 @@ void GUI::initMenu(Menu &menu) { int menu_y2 = menu.height + menu.y - 1; _screen->fillRect(menu.x + 2, menu.y + 2, menu_x2 - 2, menu_y2 - 2, menu.bkgdColor); - _screen->drawShadedBox(menu.x, menu.y, menu_x2, menu_y2, menu.color1, menu.color2); + _screen->drawShadedBox(menu.x, menu.y, menu_x2, menu_y2, menu.color1, menu.color2, _vm->gameFlags().gameID == GI_LOL ? Screen::kShadeTypeLol : Screen::kShadeTypeKyra); if (menu.titleX != -1) textX = menu.titleX; else - textX = _text->getCenterStringX(getMenuTitle(menu), menu.x, menu_x2); + textX = getMenuCenterStringX(getMenuTitle(menu), menu.x, menu_x2); textY = menu.y + menu.titleY; - _text->printText(getMenuTitle(menu), textX - 1, textY + 1, defaultColor1(), defaultColor2(), 0); - _text->printText(getMenuTitle(menu), textX, textY, menu.textColor, 0, 0); + if (_vm->gameFlags().gameID == GI_LOL) { + printMenuText(getMenuTitle(menu), textX, textY, menu.textColor, 0, 9); + } else { + printMenuText(getMenuTitle(menu), textX - 1, textY + 1, defaultColor1(), defaultColor2(), 0); + printMenuText(getMenuTitle(menu), textX, textY, menu.textColor, 0, 0); + } int x1, y1, x2, y2; for (int i = 0; i < menu.numberOfItems; ++i) { @@ -114,35 +118,49 @@ void GUI::initMenu(Menu &menu) { menuButtonData->width = menu.item[i].width - 1; menuButtonData->height = menu.item[i].height - 1; menuButtonData->buttonCallback = menu.item[i].callback; - menuButtonData->keyCode = menu.item[i].unk1F; + menuButtonData->keyCode = menu.item[i].keyCode; menuButtonData->keyCode2 = 0; + menuButtonData->arg = menu.item[i].itemId; _menuButtonList = addButtonToList(_menuButtonList, menuButtonData); } _screen->fillRect(x1, y1, x2, y2, menu.item[i].bkgdColor); - _screen->drawShadedBox(x1, y1, x2, y2, menu.item[i].color1, menu.item[i].color2); + _screen->drawShadedBox(x1, y1, x2, y2, menu.item[i].color1, menu.item[i].color2, _vm->gameFlags().gameID == GI_LOL ? Screen::kShadeTypeLol : Screen::kShadeTypeKyra); if (getMenuItemTitle(menu.item[i])) { if (menu.item[i].titleX != -1) textX = x1 + menu.item[i].titleX + 3; else - textX = _text->getCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2); + textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2); textY = y1 + 2; - _text->printText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0); - - if (i == menu.highlightedItem) - _text->printText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 0); - else - _text->printText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 0); + if (_vm->gameFlags().gameID == GI_LOL) { + textY++; + if (i == menu.highlightedItem) + printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 8); + else + printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 8); + } else { + printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0); + if (i == menu.highlightedItem) + printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 0); + else + printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 0); + } } } for (int i = 0; i < menu.numberOfItems; ++i) { if (getMenuItemLabel(menu.item[i])) { - _text->printText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX - 1, menu.y + menu.item[i].labelY + 1, defaultColor1(), 0, 0); - _text->printText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, menu.item[i].textColor, 0, 0); + if (_vm->gameFlags().gameID == GI_LOL) { + menu.item[i].labelX = menu.item[i].x - 1; + menu.item[i].labelY = menu.item[i].y + 3; + printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, menu.item[i].textColor, 0, 10); + } else { + printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX - 1, menu.y + menu.item[i].labelY + 1, defaultColor1(), 0, 0); + printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, menu.item[i].textColor, 0, 0); + } } } @@ -172,8 +190,22 @@ void GUI::initMenu(Menu &menu) { _screen->updateScreen(); } -void GUI::processHighlights(Menu &menu, int mouseX, int mouseY) { +void GUI::processHighlights(Menu &menu) { int x1, y1, x2, y2; + Common::Point p = _vm->getMousePos(); + int mouseX = p.x; + int mouseY = p.y; + + if (_vm->_flags.gameID == GI_LOL && menu.highlightedItem != 255) { + // LoL doesnt't have default highlighted items. + // We use a highlightedItem value of 255 for this. + + // With LoL no highlighting should take place unless the + // mouse cursor moves over a button. The highlighting should end + // when the mouse cursor leaves the button. + if (menu.item[menu.highlightedItem].enabled) + redrawText(menu); + } for (int i = 0; i < menu.numberOfItems; ++i) { if (!menu.item[i].enabled) @@ -188,9 +220,11 @@ void GUI::processHighlights(Menu &menu, int mouseX, int mouseY) { if (mouseX > x1 && mouseX < x2 && mouseY > y1 && mouseY < y2) { - if (menu.highlightedItem != i) { - if (menu.item[menu.highlightedItem].enabled) - redrawText(menu); + if (menu.highlightedItem != i || _vm->_flags.gameID == GI_LOL) { + if (_vm->_flags.gameID != GI_LOL) { + if (menu.item[menu.highlightedItem].enabled) + redrawText(menu); + } menu.highlightedItem = i; redrawHighlight(menu); @@ -212,11 +246,16 @@ void GUI::redrawText(const Menu &menu) { if (menu.item[i].titleX >= 0) textX = x1 + menu.item[i].titleX + 3; else - textX = _text->getCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2); + textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2); int textY = y1 + 2; - _text->printText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0); - _text->printText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 0); + if (_vm->gameFlags().gameID == GI_LOL) { + textY++; + printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 8); + } else { + printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0); + printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 0); + } } void GUI::redrawHighlight(const Menu &menu) { @@ -231,11 +270,17 @@ void GUI::redrawHighlight(const Menu &menu) { if (menu.item[i].titleX != -1) textX = x1 + menu.item[i].titleX + 3; else - textX = _text->getCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2); + textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2); int textY = y1 + 2; - _text->printText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0); - _text->printText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 0); + + if (_vm->gameFlags().gameID == GI_LOL) { + textY++; + printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 8); + } else { + printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0); + printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 0); + } } void GUI::updateAllMenuButtons() { @@ -296,7 +341,7 @@ int GUI::redrawShadedButtonCallback(Button *button) { return 0; } -void GUI::updateSaveList() { +void GUI::updateSaveList(bool excludeQuickSaves) { Common::String pattern = _vm->_targetName + ".???"; Common::StringList saveFileList = _vm->_saveFileMan->listSavefiles(pattern); _saveSlots.clear(); @@ -311,6 +356,8 @@ void GUI::updateSaveList() { s1 -= '0'; s2 -= '0'; s3 -= '0'; + if (excludeQuickSaves && s1 == 9 && s2 == 9) + continue; _saveSlots.push_back(s1*100+s2*10+s3); } @@ -383,6 +430,14 @@ void GUI::checkTextfieldInput() { _vm->_system->delayMillis(3); } +void GUI::printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2, Screen::FontId font) { + _text->printText(str, x, y, c0, c1, c2, font); +} + +int GUI::getMenuCenterStringX(const char *str, int x1, int x2) { + return _text->getCenterStringX(str, x1, x2); +} + #pragma mark - MainMenu::MainMenu(KyraEngine_v1 *vm) : _vm(vm), _screen(0) { @@ -404,7 +459,7 @@ void MainMenu::updateAnimation() { if (now > _nextUpdate) { _nextUpdate = now + _anim.delay * _vm->tickLength(); - _anim.anim->displayFrame(_animIntern.curFrame, 0, 0, 0); + _anim.anim->displayFrame(_animIntern.curFrame, 0, 0, 0, 0, 0, 0); _animIntern.curFrame += _animIntern.direction ; if (_animIntern.curFrame < _anim.startFrame) { _animIntern.curFrame = _anim.startFrame; @@ -421,8 +476,9 @@ void MainMenu::updateAnimation() { bool MainMenu::getInput() { Common::Event event; + Common::EventManager *eventMan = _vm->getEventManager(); - while (_system->getEventManager()->pollEvent(event)) { + while (eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_LBUTTONUP: return true; diff --git a/engines/kyra/gui.h b/engines/kyra/gui.h index f83620c8f9..3989062506 100644 --- a/engines/kyra/gui.h +++ b/engines/kyra/gui.h @@ -114,7 +114,7 @@ struct MenuItem { uint16 labelId; int16 labelX, labelY; - uint16 unk1F; + uint16 keyCode; }; struct Menu { @@ -161,7 +161,7 @@ public: virtual void initMenuLayout(Menu &menu); void initMenu(Menu &menu); - void processHighlights(Menu &menu, int mouseX, int mouseY); + void processHighlights(Menu &menu); // utilities for thumbnail creation virtual void createScreenThumbnail(Graphics::Surface &dst) = 0; @@ -176,6 +176,9 @@ protected: bool _displaySubMenu; bool _cancelSubMenu; + virtual void printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2, Screen::FontId font=Screen::FID_8_FNT); + virtual int getMenuCenterStringX(const char *str, int x1, int x2); + Button::Callback _redrawShadedButtonFunctor; Button::Callback _redrawButtonFunctor; @@ -201,7 +204,7 @@ protected: void redrawHighlight(const Menu &menu); Common::Array<int> _saveSlots; - void updateSaveList(); + void updateSaveList(bool excludeQuickSaves = false); int getNextSavegameSlot(); uint32 _lastScreenUpdate; diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp index a37ac7b306..69e7419757 100644 --- a/engines/kyra/gui_hof.cpp +++ b/engines/kyra/gui_hof.cpp @@ -95,7 +95,11 @@ const char *GUI_HoF::getMenuItemTitle(const MenuItem &menuItem) { if (!menuItem.itemId) return 0; - return _vm->getTableString(menuItem.itemId, _vm->_optionsBuffer, 1); + // Strings 41-45 are menu labels, those must be handled uncompressed! + if (menuItem.itemId >= 41 && menuItem.itemId <= 45) + return _vm->getTableString(menuItem.itemId, _vm->_optionsBuffer, 0); + else + return _vm->getTableString(menuItem.itemId, _vm->_optionsBuffer, 1); } const char *GUI_HoF::getMenuItemLabel(const MenuItem &menuItem) { @@ -272,7 +276,7 @@ void KyraEngine_HoF::redrawInventory(int page) { } void KyraEngine_HoF::scrollInventoryWheel() { - WSAMovie_v2 movie(this, _screen); + WSAMovie_v2 movie(this); movie.open("INVWHEEL.WSA", 0, 0); int frames = movie.opened() ? movie.frames() : 6; memcpy(_screenBuffer, _screen->getCPagePtr(2), 64000); @@ -287,7 +291,7 @@ void KyraEngine_HoF::scrollInventoryWheel() { for (int i = 0; i <= 6 && !breakFlag; ++i) { if (movie.opened()) { _screen->hideMouse(); - movie.displayFrame(i % frames, 0, 0, 0, 0); + movie.displayFrame(i % frames, 0, 0, 0, 0, 0, 0); _screen->showMouse(); _screen->updateScreen(); } @@ -361,9 +365,9 @@ int KyraEngine_HoF::bookButton(Button *button) { _screen->showMouse(); } - memcpy(_screen->getPalette(2), _screen->getPalette(0), 768); + _screen->copyPalette(2, 0); _screen->fadeToBlack(7, &_updateFunctor); - _res->loadFileToBuf("_BOOK.COL", _screen->getPalette(0), 768); + _screen->loadPalette("_BOOK.COL", _screen->getPalette(0)); loadBookBkgd(); showBookPage(); _screen->copyRegion(0, 0, 0, 0, 0x140, 0xC8, 2, 0, Screen::CR_NO_P_CHECK); @@ -389,7 +393,7 @@ int KyraEngine_HoF::bookButton(Button *button) { } setHandItem(_itemInHand); - memcpy(_screen->getPalette(0), _screen->getPalette(2), 768); + _screen->copyPalette(0, 2); _screen->fadePalette(_screen->getPalette(0), 7, &_updateFunctor); _screen->showMouse(); @@ -700,7 +704,6 @@ int GUI_HoF::optionsButton(Button *button) { int oldHandItem = _vm->_itemInHand; _screen->setMouseCursor(0, 0, _vm->getShapePtr(0)); _vm->displayInvWsaLastFrame(); - //XXX _displayMenu = true; for (uint i = 0; i < ARRAYSIZE(_menuButtons); ++i) { @@ -763,7 +766,7 @@ int GUI_HoF::optionsButton(Button *button) { } while (_displayMenu) { - processHighlights(*_currentMenu, _vm->_mouseX, _vm->_mouseY); + processHighlights(*_currentMenu); getInput(); } @@ -796,16 +799,11 @@ void GUI_HoF::createScreenThumbnail(Graphics::Surface &dst) { } void GUI_HoF::setupPalette() { - memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); - - uint8 *palette = _screen->getPalette(0); - for (int i = 0; i < 768; ++i) - palette[i] >>= 1; - - static const uint8 guiPal[] = { 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFc, 0xFD, 0xFE }; + _screen->copyPalette(1, 0); - for (uint i = 0; i < ARRAYSIZE(guiPal); ++i) - memcpy(_screen->getPalette(0)+guiPal[i]*3, _screen->getPalette(1)+guiPal[i]*3, 3); + Palette &pal = _screen->getPalette(0); + for (int i = 0; i < 741; ++i) + pal[i] >>= 1; if (_isDeathMenu) _screen->fadePalette(_screen->getPalette(0), 0x64); @@ -814,7 +812,7 @@ void GUI_HoF::setupPalette() { } void GUI_HoF::restorePalette() { - memcpy(_screen->getPalette(0), _screen->getPalette(1), 768); + _screen->copyPalette(0, 1); _screen->setScreenPalette(_screen->getPalette(0)); } @@ -851,8 +849,7 @@ void GUI_HoF::drawSliderBar(int slider, const uint8 *shape) { position = _vm->_configTextspeed; } - position = MAX(2, position); - position = MIN(97, position); + position = CLIP(position, 2, 97); _screen->drawShape(0, shape, x+position, y, 0, 0); } @@ -908,7 +905,7 @@ int GUI_HoF::audioOptions(Button *caller) { updateAllMenuButtons(); bool speechEnabled = _vm->speechEnabled(); while (_isOptionsMenu) { - processHighlights(_audioOptions, _vm->_mouseX, _vm->_mouseY); + processHighlights(_audioOptions); getInput(); } @@ -956,7 +953,7 @@ int GUI_HoF::gameOptions(Button *caller) { } while (_isOptionsMenu) { - processHighlights(_gameOptions, _vm->_mouseX, _vm->_mouseY); + processHighlights(_gameOptions); getInput(); } @@ -983,7 +980,7 @@ int GUI_HoF::gameOptionsTalkie(Button *caller) { _isOptionsMenu = true; while (_isOptionsMenu) { - processHighlights(_gameOptions, _vm->_mouseX, _vm->_mouseY); + processHighlights(_gameOptions); getInput(); } @@ -1094,8 +1091,7 @@ int GUI_HoF::sliderHandler(Button *caller) { else newVolume = _vm->_mouseX - caller->x - 7; - newVolume = MAX(2, newVolume); - newVolume = MIN(97, newVolume); + newVolume = CLIP(newVolume, 2, 97); if (newVolume == oldVolume) return 0; @@ -1175,7 +1171,7 @@ int GUI_HoF::loadMenu(Button *caller) { _screen->updateScreen(); while (_isLoadMenu) { - processHighlights(_loadMenu, _vm->_mouseX, _vm->_mouseY); + processHighlights(_loadMenu); getInput(); } diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 560bc6c2f2..9f42697ec7 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -31,6 +31,7 @@ #include "kyra/sound.h" #include "kyra/gui_lok.h" #include "kyra/timer.h" +#include "kyra/util.h" #include "common/config-manager.h" #include "common/savefile.h" @@ -86,7 +87,6 @@ int KyraEngine_LoK::buttonInventoryCallback(Button *caller) { } } _screen->updateScreen(); - // XXX clearKyrandiaButtonIO return 0; } @@ -182,7 +182,6 @@ int KyraEngine_LoK::buttonAmuletCallback(Button *caller) { break; } _unkAmuletVar = 0; - // XXX clearKyrandiaButtonIO (!used before every return in this function!) return 1; } @@ -479,7 +478,7 @@ int GUI_LoK::buttonMenuCallback(Button *caller) { } while (_displayMenu && !_vm->shouldQuit()) { - processHighlights(_menu[_toplevelMenu], _vm->_mouseX, _vm->_mouseY); + processHighlights(_menu[_toplevelMenu]); getInput(); } @@ -538,6 +537,9 @@ void GUI_LoK::setupSavegames(Menu &menu, int num) { if ((in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i + _savegameOffset]), header))) { strncpy(savenames[i], header.description.c_str(), ARRAYSIZE(savenames[0])); savenames[i][34] = 0; + + Util::convertISOToDOS(savenames[i]); + menu.item[i].itemString = savenames[i]; menu.item[i].enabled = 1; menu.item[i].saveSlot = _saveSlots[i + _savegameOffset]; @@ -570,7 +572,7 @@ int GUI_LoK::saveGameMenu(Button *button) { _cancelSubMenu = false; while (_displaySubMenu && !_vm->shouldQuit()) { - processHighlights(_menu[2], _vm->_mouseX, _vm->_mouseY); + processHighlights(_menu[2]); getInput(); } @@ -616,7 +618,7 @@ int GUI_LoK::loadGameMenu(Button *button) { _vm->_gameToLoad = -1; while (_displaySubMenu && !_vm->shouldQuit()) { - processHighlights(_menu[2], _vm->_mouseX, _vm->_mouseY); + processHighlights(_menu[2]); getInput(); } @@ -654,9 +656,12 @@ void GUI_LoK::updateSavegameString() { if (_keyPressed.keycode) { length = strlen(_savegameName); - if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127) { + char inputKey = _keyPressed.ascii; + Util::convertISOToDOS(inputKey); + + if ((uint8)inputKey > 31 && (uint8)inputKey < 226) { if (length < ARRAYSIZE(_savegameName)-1) { - _savegameName[length] = _keyPressed.ascii; + _savegameName[length] = inputKey; _savegameName[length+1] = 0; redrawTextfield(); } @@ -703,7 +708,7 @@ int GUI_LoK::saveGame(Button *button) { while (_displaySubMenu && !_vm->shouldQuit()) { checkTextfieldInput(); updateSavegameString(); - processHighlights(_menu[3], _vm->_mouseX, _vm->_mouseY); + processHighlights(_menu[3]); } if (_cancelSubMenu) { @@ -715,6 +720,8 @@ int GUI_LoK::saveGame(Button *button) { if (_savegameOffset == 0 && _vm->_gameToLoad == 0) _vm->_gameToLoad = getNextSavegameSlot(); if (_vm->_gameToLoad > 0) { + Util::convertDOSToISO(_savegameName); + Graphics::Surface thumb; createScreenThumbnail(thumb); _vm->saveGameState(_vm->_gameToLoad, _savegameName, &thumb); @@ -773,7 +780,7 @@ bool GUI_LoK::quitConfirm(const char *str) { _cancelSubMenu = true; while (_displaySubMenu && !_vm->shouldQuit()) { - processHighlights(_menu[1], _vm->_mouseX, _vm->_mouseY); + processHighlights(_menu[1]); getInput(); } @@ -833,7 +840,7 @@ int GUI_LoK::gameControlsMenu(Button *button) { _cancelSubMenu = false; while (_displaySubMenu && !_vm->shouldQuit()) { - processHighlights(_menu[5], _vm->_mouseX, _vm->_mouseY); + processHighlights(_menu[5]); getInput(); } @@ -1015,25 +1022,25 @@ void GUI_LoK::fadePalette() { static const int16 menuPalIndexes[] = {248, 249, 250, 251, 252, 253, 254, -1}; int index = 0; - memcpy(_screen->getPalette(2), _screen->_currentPalette, 768); + _screen->copyPalette(2, 0); for (int i = 0; i < 768; i++) - _screen->_currentPalette[i] >>= 1; + _screen->getPalette(0)[i] >>= 1; while (menuPalIndexes[index] != -1) { - memcpy(&_screen->_currentPalette[menuPalIndexes[index]*3], &_screen->getPalette(2)[menuPalIndexes[index]*3], 3); - index++; + _screen->getPalette(0).copy(_screen->getPalette(2), menuPalIndexes[index], 1); + ++index; } - _screen->fadePalette(_screen->_currentPalette, 2); + _screen->fadePalette(_screen->getPalette(0), 2); } void GUI_LoK::restorePalette() { if (_vm->gameFlags().platform == Common::kPlatformAmiga) return; - memcpy(_screen->_currentPalette, _screen->getPalette(2), 768); - _screen->fadePalette(_screen->_currentPalette, 2); + _screen->copyPalette(0, 2); + _screen->fadePalette(_screen->getPalette(0), 2); } #pragma mark - diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h index eec57f5546..5982ef1ce2 100644 --- a/engines/kyra/gui_lok.h +++ b/engines/kyra/gui_lok.h @@ -89,7 +89,7 @@ namespace Kyra { item.labelString = r; \ item.labelX = s; \ item.labelY = t; \ - item.unk1F = v; \ + item.keyCode = v; \ } while (0) class KyraEngine_LoK; diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp index af8bc6aa97..5e03f3d9bb 100644 --- a/engines/kyra/gui_lol.cpp +++ b/engines/kyra/gui_lol.cpp @@ -28,6 +28,14 @@ #include "kyra/lol.h" #include "kyra/screen_lol.h" #include "kyra/gui_lol.h" +#include "kyra/resource.h" +#include "kyra/util.h" + +#include "common/savefile.h" +#include "common/config-manager.h" +#include "graphics/scaler.h" + +#include "base/version.h" namespace Kyra { @@ -577,7 +585,7 @@ void LoLEngine::gui_drawCompass() { } int LoLEngine::gui_enableControls() { - _floatingMouseArrowControl = 0; + _floatingCursorControl = 0; if (!_currentControlMode) { for (int i = 76; i < 85; i++) @@ -592,7 +600,7 @@ int LoLEngine::gui_disableControls(int controlMode) { if (_currentControlMode) return 0; - _floatingMouseArrowControl = (controlMode & 2) ? 2 : 1; + _floatingCursorControl = (controlMode & 2) ? 2 : 1; gui_toggleFightButtons(true); @@ -1364,7 +1372,7 @@ int LoLEngine::clickedInventorySlot(Button *button) { (_itemsInPlay[hItem].itemPropertyIndex == 220 || _itemsInPlay[slotItem].itemPropertyIndex == 220)) { // merge ruby of truth - WSAMovie_v2 *wsa = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *wsa = new WSAMovie_v2(this); wsa->open("truth.wsa", 0, 0); _screen->hideMouse(); @@ -1377,7 +1385,7 @@ int LoLEngine::clickedInventorySlot(Button *button) { for (int i = 0; i < 25; i++) { uint32 delayTimer = _system->getMillis() + 7 * _tickLength; _screen->copyRegion(button->x, button->y - 3, 0, 0, 25, 27, 2, 2); - wsa->displayFrame(i, 2, 0, 0, 0x4000); + wsa->displayFrame(i, 2, 0, 0, 0x4000, 0, 0); _screen->copyRegion(0, 0, button->x, button->y - 3, 25, 27, 2, 0); _screen->updateScreen(); delayUntil(delayTimer); @@ -1536,10 +1544,43 @@ int LoLEngine::clickedSceneThrowItem(Button *button) { } int LoLEngine::clickedOptions(Button *button) { + removeInputTop(); gui_toggleButtonDisplayMode(76, 1); + _updateFlags |= 4; + + Button b; + b.data0Val2 = b.data1Val2 = b.data2Val2 = 0xfe; + b.data0Val3 = b.data1Val3 = b.data2Val3 = 0x01; + + if (_weaponsDisabled) + clickedExitCharInventory(&b); + + initTextFading(0, 1); + updatePortraits(); + setLampMode(true); + setMouseCursorToIcon(0); + disableSysTimer(2); + gui_toggleButtonDisplayMode(76, 0); + bool speechWasEnabled = speechEnabled(); + _gui->runMenu(_gui->_mainMenu); + + _updateFlags &= 0xfffb; + setMouseCursorToItemInHand(); + resetLampStatus(); + gui_enableDefaultPlayfieldButtons(); + enableSysTimer(2); + updateDrawPage2(); + + gui_drawPlayField(); + + if (speechWasEnabled && !textEnabled() && (!speechEnabled() || getVolume(kVolumeSpeech) == 2)) + _configVoice = 0; + + writeSettings(); + return 1; } @@ -1773,7 +1814,7 @@ int LoLEngine::clickedAutomap(Button *button) { displayAutomap(); gui_drawPlayField(); - setPaletteBrightness(_screen->_currentPalette, _brightness, _lampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); return 1; } @@ -1801,7 +1842,7 @@ int LoLEngine::clickedLamp(Button *button) { } if (_brightness) - setPaletteBrightness(_screen->_currentPalette, _brightness, _lampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); return 1; } @@ -1826,9 +1867,13 @@ int LoLEngine::clickedStatusIcon(Button *button) { GUI_LoL::GUI_LoL(LoLEngine *vm) : GUI(vm), _vm(vm), _screen(vm->_screen) { _scrollUpFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::scrollUp); _scrollDownFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::scrollDown); + _redrawButtonFunctor = BUTTON_FUNCTOR(GUI, this, &GUI::redrawButtonCallback); + _redrawShadedButtonFunctor = BUTTON_FUNCTOR(GUI, this, &GUI::redrawShadedButtonCallback); + _specialProcessButton = _backUpButtonList = 0; _flagsModifier = 0; _mouseClick = 0; + _sliderSfx = 11; _buttonListChanged = false; } @@ -2164,6 +2209,624 @@ int GUI_LoL::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseW return returnValue; } +int GUI_LoL::redrawButtonCallback(Button *button) { + if (!_displayMenu) + return 0; + + _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 225); + return 0; +} + +int GUI_LoL::redrawShadedButtonCallback(Button *button) { + if (!_displayMenu) + return 0; + + _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 223, 227, Screen::kShadeTypeLol); + return 0; +} + +int GUI_LoL::runMenu(Menu &menu) { + _currentMenu = &menu; + _lastMenu = _currentMenu; + _newMenu = 0; + _displayMenu = true; + _menuResult = 1; + _savegameOffset = 0; + backupPage0(); + + const ScreenDim *d = _screen->getScreenDim(8); + uint32 textCursorTimer = 0; + uint8 textCursorStatus = 1; + int wW = _screen->getCharWidth('W'); + int fW = (d->w << 3) - wW; + int fC = 0; + + // LoL doesnt't have default higlighted items. No item should be + // highlighted when entering a new menu. + // Instead, the respevtive struct entry is used to determine whether + // a menu has scroll buttons or slider bars. + uint8 hasSpecialButtons = 0; + + while (_displayMenu) { + _vm->_mouseX = _vm->_mouseY = 0; + + if (_currentMenu == &_loadMenu || _currentMenu == &_saveMenu || _currentMenu == &_deleteMenu) { + updateSaveList(true); + Common::sort(_saveSlots.begin(), _saveSlots.end(), Common::Greater<int>()); + setupSavegameNames(*_currentMenu, 4); + } + + hasSpecialButtons = _currentMenu->highlightedItem; + _currentMenu->highlightedItem = 255; + + if (_currentMenu == &_gameOptions) { + char *s = (char *)_vm->_tempBuffer5120; + strncpy(s, _vm->getLangString(0x406f + _vm->_monsterDifficulty), 30); + s[29] = 0; + _currentMenu->item[0].itemString = s; + s += (strlen(s) + 1); + + strncpy(s, _vm->getLangString(_vm->_smoothScrollingEnabled ? 0x4068 : 0x4069), 30); + s[29] = 0; + _currentMenu->item[1].itemString = s; + s += (strlen(s) + 1); + + strncpy(s, _vm->getLangString(_vm->_floatingCursorsEnabled ? 0x4068 : 0x4069), 30); + s[29] = 0; + _currentMenu->item[2].itemString = s; + s += (strlen(s) + 1); + + strncpy(s, _vm->getLangString(0x42d6 + _vm->_lang), 30); + s[29] = 0; + _currentMenu->item[3].itemString = s; + s += (strlen(s) + 1); + + strncpy(s, _vm->getLangString(_vm->textEnabled() ? 0x4068 : 0x4069), 30); + s[29] = 0; + _currentMenu->item[4].itemString = s; + s += (strlen(s) + 1); + } + + if (hasSpecialButtons == 1) { + if (_savegameOffset == 0) { + _scrollUpButton.data0ShapePtr = _scrollUpButton.data1ShapePtr = _scrollUpButton.data2ShapePtr = 0; + } else { + _scrollUpButton.data0ShapePtr = _vm->_gameShapes[17]; + _scrollUpButton.data1ShapePtr = _scrollUpButton.data2ShapePtr = _vm->_gameShapes[19]; + } + if ((uint)_savegameOffset == _saveSlots.size() - 4) { + _scrollDownButton.data0ShapePtr = _scrollDownButton.data1ShapePtr = _scrollDownButton.data2ShapePtr = 0; + } else { + _scrollDownButton.data0ShapePtr = _vm->_gameShapes[18]; + _scrollDownButton.data1ShapePtr = _scrollDownButton.data2ShapePtr = _vm->_gameShapes[20]; + } + } + + for (uint i = 0; i < _currentMenu->numberOfItems; ++i) { + _menuButtons[i].data0Val1 = _menuButtons[i].data1Val1 = _menuButtons[i].data2Val1 = 4; + _menuButtons[i].data0Callback = _redrawShadedButtonFunctor; + _menuButtons[i].data1Callback = _menuButtons[i].data2Callback = _redrawButtonFunctor; + _menuButtons[i].flags = 0x4487; + _menuButtons[i].flags2 = 0; + } + + initMenu(*_currentMenu); + + if (hasSpecialButtons == 2) { + static const uint8 oX[] = { 0, 10, 124 }; + static const uint8 oW[] = { 10, 114, 10 }; + + for (int i = 1; i < 4; ++i) { + int tX = _currentMenu->x + _currentMenu->item[i].x; + int tY = _currentMenu->y + _currentMenu->item[i].y; + + for (int ii = 0; ii < 3; ++ii) { + Button *b = getButtonListData() + 1 + (i - 1) * 3 + ii; + b->nextButton = 0; + b->data0Val2 = b->data1Val2 = b->data2Val2 = 0xfe; + b->data0Val3 = b->data1Val3 = b->data2Val3 = 0x01; + + b->index = ii; + b->keyCode = b->keyCode2 = 0; + + b->x = tX + oX[ii]; + b->y = tY; + b->width = oW[ii]; + b->height = _currentMenu->item[i].height; + + b->data0Val1 = b->data1Val1 = b->data2Val1 = 0; + b->flags = (ii == 1) ? 0x6606 : 0x4406; + + b->dimTableIndex = 0; + + b->buttonCallback = _currentMenu->item[i].callback; + b->arg = _currentMenu->item[i].itemId; + + _menuButtonList = addButtonToList(_menuButtonList, b); + + processButton(b); + updateButton(b); + } + + _currentMenu->item[i].labelX = _currentMenu->item[i].x - 5; + _currentMenu->item[i].labelY = _currentMenu->item[i].y + 3; + + printMenuText(getMenuItemLabel(_currentMenu->item[i]), _currentMenu->x + _currentMenu->item[i].labelX, _currentMenu->y + _currentMenu->item[i].labelY, _currentMenu->item[i].textColor, 0, 10); + + int volume = _vm->getVolume((KyraEngine_v1::kVolumeEntry)(i - 1)); + _screen->drawShape(_screen->_curPage, _vm->_gameShapes[85], tX , tY, 0, 0x10); + _screen->drawShape(_screen->_curPage, _vm->_gameShapes[87], tX + 2 + oX[1], tY, 0, 0x10); + _screen->drawShape(_screen->_curPage, _vm->_gameShapes[86], tX + oX[1] + volume, tY, 0, 0x10); + } + + _screen->updateScreen(); + } + + if (_currentMenu == &_mainMenu) { + Screen::FontId f = _screen->setFont(Screen::FID_6_FNT); + _screen->fprintString("%s", menu.x + 8, menu.y + menu.height - 12, 204, 0, 8, gScummVMVersion); + _screen->setFont(f); + _screen->updateScreen(); + } + + if (_currentMenu == &_savenameMenu) { + int mx = (d->sx << 3) - 1; + int my = d->sy - 1; + int mw = (d->w << 3) + 1; + int mh = d->h + 1; + _screen->drawShadedBox(mx, my, mx + mw, my + mh, 227, 223, Screen::kShadeTypeLol); + int pg = _screen->setCurPage(0); + _vm->_txt->clearDim(8); + textCursorTimer = 0; + textCursorStatus = 0; + + fC = _screen->getTextWidth(_saveDescription); + while (fC >= fW) { + _saveDescription[strlen(_saveDescription) - 1] = 0; + fC = _screen->getTextWidth(_saveDescription); + } + + _screen->fprintString(_saveDescription, (d->sx << 3), d->sy + 2, d->unk8, d->unkA, 0); + _screen->fillRect((d->sx << 3) + fC, d->sy, (d->sx << 3) + fC + wW, d->sy + d->h - 1, d->unk8, 0); + _screen->setCurPage(pg); + } + + while (!_newMenu && _displayMenu) { + processHighlights(*_currentMenu); + + if (_currentMenu == &_savenameMenu) { + if (textCursorTimer <= _vm->_system->getMillis()) { + fC = _screen->getTextWidth(_saveDescription); + textCursorStatus ^= 1; + textCursorTimer = _vm->_system->getMillis() + 20 * _vm->_tickLength; + _screen->fillRect((d->sx << 3) + fC, d->sy, (d->sx << 3) + fC + wW, d->sy + d->h - 1, textCursorStatus ? d->unk8 : d->unkA, 0); + _screen->updateScreen(); + } + } + + if (getInput()) { + if (!_newMenu) + _newMenu = (_currentMenu != &_audioOptions) ? _currentMenu : 0; + else + _lastMenu = _menuResult == -1 ? _lastMenu : _currentMenu; + } + + if (!_menuResult) + _displayMenu = false; + } + + if (_newMenu != _currentMenu || !_displayMenu) + restorePage0(); + + _currentMenu->highlightedItem = hasSpecialButtons; + + if (_newMenu) + _currentMenu = _newMenu; + + _newMenu = 0; + } + + return _menuResult; +} + +void GUI_LoL::createScreenThumbnail(Graphics::Surface &dst) { + uint8 *screenPal = new uint8[768]; + _screen->getRealPalette(1, screenPal); + ::createThumbnail(&dst, _screen->getCPagePtr(7), Screen::SCREEN_W, Screen::SCREEN_H, screenPal); + delete[] screenPal; +} + +void GUI_LoL::backupPage0() { + _screen->copyPage(0, 7); +} + +void GUI_LoL::restorePage0() { + _screen->copyPage(7, 0); + _screen->updateScreen(); +} + +void GUI_LoL::setupSavegameNames(Menu &menu, int num) { + char *s = (char *)_vm->_tempBuffer5120; + + for (int i = 0; i < num; ++i) { + menu.item[i].saveSlot = -1; + menu.item[i].enabled = false; + } + + int startSlot = 0; + if (&menu == &_saveMenu && _savegameOffset == 0) + startSlot = 1; + + KyraEngine_v1::SaveHeader header; + Common::InSaveFile *in; + for (int i = startSlot; i < num && uint(_savegameOffset + i) < _saveSlots.size(); ++i) { + if ((in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i + _savegameOffset - startSlot]), header)) != 0) { + strncpy(s, header.description.c_str(), 80); + s[79] = 0; + + Util::convertISOToDOS(s); + + menu.item[i].itemString = s; + s += (strlen(s) + 1); + menu.item[i].saveSlot = _saveSlots[i + _savegameOffset]; + menu.item[i].enabled = true; + delete in; + } + } + + if (_savegameOffset == 0) { + if (&menu == &_saveMenu) { + strcpy(s, _vm->getLangString(0x4010)); + menu.item[0].itemString = s; + menu.item[0].saveSlot = -3; + menu.item[0].enabled = true; + } + } +} + +void GUI_LoL::printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 flags, Screen::FontId font) { + _screen->fprintString(str, x, y, c0, c1, flags); +} + +int GUI_LoL::getMenuCenterStringX(const char *str, int x1, int x2) { + if (!str) + return 0; + + int strWidth = _screen->getTextWidth(str); + int w = x2 - x1 + 1; + return x1 + (w - strWidth) / 2; +} + +int GUI_LoL::getInput() { + if (!_displayMenu) + return 0; + + Common::Point p = _vm->getMousePos(); + _vm->_mouseX = p.x; + _vm->_mouseY = p.y; + + if (_currentMenu == &_savenameMenu) { + _vm->updateInput(); + + for (Common::List<KyraEngine_v1::Event>::const_iterator evt = _vm->_eventList.begin(); evt != _vm->_eventList.end(); evt++) { + if (evt->event.type == Common::EVENT_KEYDOWN) + _keyPressed = evt->event.kbd; + } + } + + int inputFlag = _vm->checkInput(_menuButtonList); + + if (_currentMenu == &_savenameMenu && _keyPressed.ascii){ + char inputKey = _keyPressed.ascii; + Util::convertISOToDOS(inputKey); + + if ((uint8)inputKey > 31 && (uint8)inputKey < 226) { + _saveDescription[strlen(_saveDescription) + 1] = 0; + _saveDescription[strlen(_saveDescription)] = inputKey; + inputFlag |= 0x8000; + } else if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE && strlen(_saveDescription)) { + _saveDescription[strlen(_saveDescription) - 1] = 0; + inputFlag |= 0x8000; + } + } + + _vm->removeInputTop(); + _keyPressed.reset(); + + if (_vm->shouldQuit()) + _displayMenu = false; + + _vm->delay(8); + return inputFlag & 0x8000 ? 1 : 0; +} + +int GUI_LoL::clickedMainMenu(Button *button) { + updateMenuButton(button); + switch (button->arg) { + case 0x4001: + _savegameOffset = 0; + _newMenu = &_loadMenu; + break; + case 0x4002: + _savegameOffset = 0; + _newMenu = &_saveMenu; + break; + case 0x4003: + _savegameOffset = 0; + _newMenu = &_deleteMenu; + break; + case 0x4004: + _newMenu = &_gameOptions; + break; + case 0x42D9: + _newMenu = &_audioOptions; + break; + case 0x4006: + _choiceMenu.menuNameId = 0x400a; + _newMenu = &_choiceMenu; + break; + case 0x4005: + _displayMenu = false; + break; + } + return 1; +} + +int GUI_LoL::clickedLoadMenu(Button *button) { + updateMenuButton(button); + + if (button->arg == 0x4011) { + if (_currentMenu != _lastMenu) + _newMenu = _lastMenu; + else + _menuResult = 0; + return 1; + } + + int16 s = (int16)button->arg; + _vm->_gameToLoad = _loadMenu.item[-s - 2].saveSlot; + _displayMenu = false; + + return 1; +} + +int GUI_LoL::clickedSaveMenu(Button *button) { + updateMenuButton(button); + + if (button->arg == 0x4011) { + _newMenu = &_mainMenu; + return 1; + } + + _newMenu = &_savenameMenu; + int16 s = (int16)button->arg; + _menuResult = _saveMenu.item[-s - 2].saveSlot + 1; + _saveDescription = (char*)_vm->_tempBuffer5120 + 1000; + _saveDescription[0] = 0; + if (_saveMenu.item[-s - 2].saveSlot != -3) + strcpy(_saveDescription, _saveMenu.item[-s - 2].itemString); + + return 1; +} + +int GUI_LoL::clickedDeleteMenu(Button *button) { + updateMenuButton(button); + + if (button->arg == 0x4011) { + _newMenu = &_mainMenu; + return 1; + } + + _choiceMenu.menuNameId = 0x400b; + _newMenu = &_choiceMenu; + int16 s = (int16)button->arg; + _menuResult = _deleteMenu.item[-s - 2].saveSlot + 1; + + return 1; +} + +int GUI_LoL::clickedOptionsMenu(Button *button) { + updateMenuButton(button); + + switch (button->arg) { + case 0xfff7: + _vm->_monsterDifficulty = ++_vm->_monsterDifficulty % 3; + break; + case 0xfff6: + _vm->_smoothScrollingEnabled ^= true; + break; + case 0xfff5: + _vm->_floatingCursorsEnabled ^= true; + break; + case 0xfff4: + _vm->_lang = ++_vm->_lang % 3; + break; + case 0xfff3: + _vm->_configVoice ^= 1; + break; + case 0x4072: + char filename[13]; + snprintf(filename, sizeof(filename), "LEVEL%02d.%s", _vm->_currentLevel, _vm->_languageExt[_vm->_lang]); + if (_vm->_levelLangFile) + delete[] _vm->_levelLangFile; + _vm->_levelLangFile = _vm->resource()->fileData(filename, 0); + snprintf(filename, sizeof(filename), "LANDS.%s", _vm->_languageExt[_vm->_lang]); + if (_vm->_landsFile) + delete[] _vm->_landsFile; + _vm->_landsFile = _vm->resource()->fileData(filename, 0); + _newMenu = _lastMenu; + break; + } + + return 1; +} + +int GUI_LoL::clickedAudioMenu(Button *button) { + updateMenuButton(button); + + if (button->arg == 0x4072) { + _newMenu = _lastMenu; + return 1; + } + + int tX = button->x; + const int oldVolume = _vm->getVolume((KyraEngine_v1::kVolumeEntry)(button->arg - 3)); + int newVolume = oldVolume; + + if (button->index == 0) { + newVolume -= 10; + tX += 10; + } else if (button->index == 1) { + newVolume = _vm->_mouseX - (tX + 7); + } else if (button->index == 2) { + newVolume += 10; + tX -= 114; + } + + newVolume = CLIP(newVolume, 2, 102); + + if (newVolume == oldVolume) { + _screen->updateScreen(); + return 0; + } + + _screen->drawShape(0, _vm->_gameShapes[87], tX + oldVolume, button->y, 0, 0x10); + // Temporary HACK + const int volumeDrawX = _vm->convertVolumeFromMixer(_vm->convertVolumeToMixer(newVolume)); + _screen->drawShape(0, _vm->_gameShapes[86], tX + volumeDrawX, button->y, 0, 0x10); + _screen->updateScreen(); + + _vm->snd_stopSpeech(0); + + _vm->setVolume((KyraEngine_v1::kVolumeEntry)(button->arg - 3), newVolume); + + if (newVolume) { + if (button->arg == 4) { + _vm->snd_playSoundEffect(_sliderSfx, -1); + int16 vocIndex = (int16)READ_LE_UINT16(&_vm->_ingameSoundIndex[_sliderSfx * 2]); + do { + ++_sliderSfx; + if (_sliderSfx < 47) + _sliderSfx++; + if (vocIndex == 199) + _sliderSfx = 11; + vocIndex = (int16)READ_LE_UINT16(&_vm->_ingameSoundIndex[_sliderSfx * 2]); + if (vocIndex == -1) + continue; + if (!scumm_stricmp(_vm->_ingameSoundList[vocIndex], "EMPTY")) + continue; + break; + } while (1); + } else if (button->arg == 5) { + _vm->_lastSpeechId = -1; + _vm->snd_playCharacterSpeech(0x42e0, 0, 0); + } + } + + return 1; +} + +int GUI_LoL::clickedDeathMenu(Button *button) { + updateMenuButton(button); + if (button->arg == _deathMenu.item[0].itemId) { + _vm->quitGame(); + } else if (button->arg == _deathMenu.item[1].itemId) { + _newMenu = &_loadMenu; + } + return 1; +} + +int GUI_LoL::clickedSavenameMenu(Button *button) { + updateMenuButton(button); + if (button->arg == _savenameMenu.item[0].itemId) { + + Util::convertDOSToISO(_saveDescription); + + int slot = _menuResult == -2 ? getNextSavegameSlot() : _menuResult; + Graphics::Surface thumb; + createScreenThumbnail(thumb); + _vm->saveGameState(slot, _saveDescription, &thumb); + thumb.free(); + + _displayMenu = false; + + } else if (button->arg == _savenameMenu.item[1].itemId) { + _newMenu = &_saveMenu; + } + + return 1; +} + +int GUI_LoL::clickedChoiceMenu(Button *button) { + updateMenuButton(button); + if (button->arg == _choiceMenu.item[0].itemId) { + if (_lastMenu == &_mainMenu) { + _vm->quitGame(); + } else if (_lastMenu == &_deleteMenu) { + _vm->_saveFileMan->removeSavefile(_vm->getSavegameFilename(_menuResult - 1)); + Common::Array<int>::iterator i = Common::find(_saveSlots.begin(), _saveSlots.end(), _menuResult); + while (i != _saveSlots.end()) { + ++i; + if (i == _saveSlots.end()) + break; + // We are only renaming all savefiles until we get some slots missing + // Also not rename quicksave slot filenames + if (*(i-1) != *i || *i >= 990) + break; + Common::String oldName = _vm->getSavegameFilename(*i); + Common::String newName = _vm->getSavegameFilename(*i-1); + _vm->_saveFileMan->renameSavefile(oldName, newName); + } + _newMenu = &_mainMenu; + } + } else if (button->arg == _choiceMenu.item[1].itemId) { + _newMenu = &_mainMenu; + } + return 1; +} + +int GUI_LoL::scrollUp(Button *button) { + updateButton(button); + if (_savegameOffset > 0) { + _savegameOffset--; + _newMenu = _currentMenu; + _menuResult = -1; + } + return 1; +} + +int GUI_LoL::scrollDown(Button *button) { + updateButton(button); + if ((uint)_savegameOffset < _saveSlots.size() - 4) { + _savegameOffset++; + _newMenu = _currentMenu; + _menuResult = -1; + } + return 1; +} + +const char *GUI_LoL::getMenuTitle(const Menu &menu) { + if (!menu.menuNameId) + return 0; + return _vm->getLangString(menu.menuNameId); +} + +const char *GUI_LoL::getMenuItemTitle(const MenuItem &menuItem) { + if (menuItem.itemId & 0x8000 && menuItem.itemString) + return menuItem.itemString; + else if (menuItem.itemId & 0x8000 || !menuItem.itemId) + return 0; + return _vm->getLangString(menuItem.itemId); +} + +const char *GUI_LoL::getMenuItemLabel(const MenuItem &menuItem) { + if (menuItem.labelId & 0x8000 && menuItem.labelString) + return menuItem.labelString; + else if (menuItem.labelId & 0x8000 || !menuItem.labelId) + return 0; + return _vm->getLangString(menuItem.labelId); +} + } // end of namespace Kyra #endif // ENABLE_LOL diff --git a/engines/kyra/gui_lol.h b/engines/kyra/gui_lol.h index 631e29bd3b..832199f23e 100644 --- a/engines/kyra/gui_lol.h +++ b/engines/kyra/gui_lol.h @@ -31,6 +31,50 @@ #include "kyra/gui.h" namespace Kyra { +#define GUI_LOL_MENU(menu, a, b, c, d, e, f, g, i) \ + do { \ + const ScreenDim *dim = _screen->getScreenDim(a); \ + menu.x = (dim->sx << 3); \ + menu.y = (dim->sy); \ + menu.width = (dim->w << 3); \ + menu.height = (dim->h); \ + menu.bkgdColor = 225; \ + menu.color1 = 223; \ + menu.color2 = 227; \ + menu.menuNameId = b; \ + menu.highlightedItem = c; \ + menu.numberOfItems = d; \ + menu.titleX = (dim->sx << 3) + (dim->w << 2); \ + menu.titleY = 6; \ + menu.textColor = 254; \ + menu.scrollUpButtonX = e; \ + menu.scrollUpButtonY = f; \ + menu.scrollDownButtonX = g; \ + menu.scrollDownButtonY = i; \ + } while (0) + + #define GUI_LOL_MENU_ITEM(item, a, b, c, d, e, f, g) \ + do { \ + item.enabled = 1; \ + item.itemId = a; \ + item.itemString = 0; \ + item.x = b; \ + item.y = c; \ + item.width = d; \ + item.height = e; \ + item.textColor = 204; \ + item.highlightColor = 254; \ + item.titleX = -1; \ + item.bkgdColor = 225; \ + item.color1 = 223; \ + item.color2 = 227; \ + item.saveSlot = 0; \ + item.labelId = f; \ + item.labelString = 0; \ + item.labelX = 0; \ + item.labelY = 0; \ + item.keyCode = g; \ + } while (0) class LoLEngine; class Screen_LoL; @@ -40,14 +84,67 @@ class GUI_LoL : public GUI { public: GUI_LoL(LoLEngine *vm); + void initStaticData(); + // button specific void processButton(Button *button); int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel); + int redrawShadedButtonCallback(Button *button); + int redrawButtonCallback(Button *button); + + int runMenu(Menu &menu); + // utilities for thumbnail creation - void createScreenThumbnail(Graphics::Surface &dst) {} + void createScreenThumbnail(Graphics::Surface &dst); private: + void backupPage0(); + void restorePage0(); + + void setupSavegameNames(Menu &menu, int num); + + void printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 flags, Screen::FontId font=Screen::FID_9_FNT); + int getMenuCenterStringX(const char *str, int x1, int x2); + + int getInput(); + + int clickedMainMenu(Button *button); + int clickedLoadMenu(Button *button); + int clickedSaveMenu(Button *button); + int clickedDeleteMenu(Button *button); + int clickedOptionsMenu(Button *button); + int clickedAudioMenu(Button *button); + int clickedDeathMenu(Button *button); + int clickedSavenameMenu(Button *button); + int clickedChoiceMenu(Button *button); + + int scrollUp(Button *button); + int scrollDown(Button *button); + + Button *getButtonListData() { return _menuButtons; } + Button *getScrollUpButton() { return &_scrollUpButton; } + Button *getScrollDownButton() { return &_scrollDownButton; } + + + Button::Callback getScrollUpButtonHandler() const { return _scrollUpFunctor; } + Button::Callback getScrollDownButtonHandler() const { return _scrollDownFunctor; } + + uint8 defaultColor1() const { return 0xFE; } + uint8 defaultColor2() const { return 0x00; } + + const char *getMenuTitle(const Menu &menu); + const char *getMenuItemTitle(const MenuItem &menuItem); + const char *getMenuItemLabel(const MenuItem &menuItem); + + Button _menuButtons[10]; + Button _scrollUpButton; + Button _scrollDownButton; + Menu _mainMenu, _gameOptions, _audioOptions, _choiceMenu, _loadMenu, _saveMenu, _deleteMenu, _savenameMenu, _deathMenu; + Menu *_currentMenu, *_lastMenu, *_newMenu; + int _menuResult; + char *_saveDescription; + LoLEngine *_vm; Screen_LoL *_screen; @@ -59,24 +156,11 @@ private: uint16 _flagsModifier; uint8 _mouseClick; - int scrollUp(Button *button) { return 0; } - int scrollDown(Button *button) { return 0; } - - Button *getButtonListData() { return 0; } - Button *getScrollUpButton() { return 0; } - Button *getScrollDownButton() { return 0; } + int _savegameOffset; + int _sliderSfx; Button::Callback _scrollUpFunctor; Button::Callback _scrollDownFunctor; - Button::Callback getScrollUpButtonHandler() const { return _scrollUpFunctor; } - Button::Callback getScrollDownButtonHandler() const { return _scrollDownFunctor; } - - uint8 defaultColor1() const { return 0; } - uint8 defaultColor2() const { return 0; } - - const char *getMenuTitle(const Menu &menu) { return 0; } - const char *getMenuItemTitle(const MenuItem &menuItem) { return 0; } - const char *getMenuItemLabel(const MenuItem &menuItem) { return 0; } }; } // end of namespace Kyra diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp index c4d804c14d..e7001ed31f 100644 --- a/engines/kyra/gui_mr.cpp +++ b/engines/kyra/gui_mr.cpp @@ -352,10 +352,10 @@ void KyraEngine_MR::drawMalcolmsMoodPointer(int frame, int page) { frame = 13; if (page == 0) { - _invWsa->displayFrame(frame, 0, 0, 0, 0); + _invWsa->displayFrame(frame, 0, 0, 0, 0, 0, 0); _screen->updateScreen(); } else if (page == 30) { - _invWsa->displayFrame(frame, 2, 0, -144, 0); + _invWsa->displayFrame(frame, 2, 0, -144, 0, 0, 0); } _invWsaFrame = frame; @@ -674,21 +674,21 @@ void KyraEngine_MR::showAlbum() { _screen->copyRegionToBuffer(0, 0, 0, 320, 200, _screenBuffer); _screen->copyRegionToBuffer(4, 0, 0, 320, 200, _album.backUpPage); - memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); + _screen->copyPalette(1, 0); _screen->fadeToBlack(9); int itemInHand = _itemInHand; removeHandItem(); - _res->loadFileToBuf("ALBUM.COL", _screen->getPalette(0), 768); + _screen->loadPalette("ALBUM.COL", _screen->getPalette(0)); loadAlbumPage(); loadAlbumPageWSA(); if (_album.leftPage.wsa->opened()) - _album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000); + _album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000, 0, 0); if (_album.rightPage.wsa->opened()) - _album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000); + _album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000, 0, 0); printAlbumPageText(); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); @@ -707,7 +707,7 @@ void KyraEngine_MR::showAlbum() { _screen->copyBlockToPage(0, 0, 0, 320, 200, _screenBuffer); _screen->copyBlockToPage(4, 0, 0, 320, 200, _album.backUpPage); - memcpy(_screen->getPalette(0), _screen->getPalette(1), 768); + _screen->copyPalette(0, 1); _screen->fadePalette(_screen->getPalette(0), 9); delete[] _album.backUpRect; @@ -843,10 +843,10 @@ void KyraEngine_MR::processAlbum() { loadAlbumPageWSA(); if (_album.leftPage.wsa->opened()) - _album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000); + _album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000, 0, 0); if (_album.rightPage.wsa->opened()) - _album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000); + _album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000, 0, 0); printAlbumPageText(); @@ -899,7 +899,7 @@ void KyraEngine_MR::albumUpdateAnims() { nextRun = _album.leftPage.timer + 5 * _tickLength; if (nextRun < _system->getMillis() && _album.leftPage.wsa->opened()) { - _album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000); + _album.leftPage.wsa->displayFrame(_album.leftPage.curFrame, 2, _albumWSAX[_album.nextPage+0], _albumWSAY[_album.nextPage+0], 0x4000, 0, 0); _screen->copyRegion(40, 17, 40, 17, 87, 73, 2, 0, Screen::CR_NO_P_CHECK); ++_album.leftPage.curFrame; @@ -918,7 +918,7 @@ void KyraEngine_MR::albumUpdateAnims() { nextRun = _album.rightPage.timer + 5 * _tickLength; if (nextRun < _system->getMillis() && _album.rightPage.wsa->opened()) { - _album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000); + _album.rightPage.wsa->displayFrame(_album.rightPage.curFrame, 2, _albumWSAX[_album.nextPage+1], _albumWSAY[_album.nextPage+1], 0x4000, 0, 0); _screen->copyRegion(194, 20, 194, 20, 85, 69, 2, 0, Screen::CR_NO_P_CHECK); ++_album.rightPage.curFrame; @@ -936,13 +936,13 @@ void KyraEngine_MR::albumUpdateAnims() { void KyraEngine_MR::albumAnim1() { for (int i = 6; i >= 3; --i) { albumRestoreRect(); - _album.wsa->displayFrame(i, 2, -100, 90, 0x4000); + _album.wsa->displayFrame(i, 2, -100, 90, 0x4000, 0, 0); albumUpdateRect(); delayWithTicks(1); } albumRestoreRect(); - _album.wsa->displayFrame(14, 2, -100, 90, 0x4000); + _album.wsa->displayFrame(14, 2, -100, 90, 0x4000, 0, 0); albumUpdateRect(); delayWithTicks(1); } @@ -950,7 +950,7 @@ void KyraEngine_MR::albumAnim1() { void KyraEngine_MR::albumAnim2() { for (int i = 3; i <= 6; ++i) { albumRestoreRect(); - _album.wsa->displayFrame(i, 2, -100, 90, 0x4000); + _album.wsa->displayFrame(i, 2, -100, 90, 0x4000, 0, 0); albumUpdateRect(); delayWithTicks(1); } @@ -1269,7 +1269,7 @@ int GUI_MR::optionsButton(Button *button) { } while (_displayMenu) { - processHighlights(*_currentMenu, _vm->_mouseX, _vm->_mouseY); + processHighlights(*_currentMenu); getInput(); } @@ -1312,7 +1312,7 @@ int GUI_MR::loadMenu(Button *caller) { _screen->updateScreen(); while (_isLoadMenu) { - processHighlights(_loadMenu, _vm->_mouseX, _vm->_mouseY); + processHighlights(_loadMenu); getInput(); } @@ -1362,7 +1362,7 @@ int GUI_MR::gameOptions(Button *caller) { _isOptionsMenu = true; while (_isOptionsMenu) { - processHighlights(_gameOptions, _vm->_mouseX, _vm->_mouseY); + processHighlights(_gameOptions); getInput(); } @@ -1525,7 +1525,7 @@ int GUI_MR::audioOptions(Button *caller) { updateAllMenuButtons(); bool speechEnabled = _vm->speechEnabled(); while (_isOptionsMenu) { - processHighlights(_audioOptions, _vm->_mouseX, _vm->_mouseY); + processHighlights(_audioOptions); getInput(); } @@ -1554,7 +1554,7 @@ int GUI_MR::sliderHandler(Button *caller) { assert(button >= 0 && button <= 3); - int oldVolume = _vm->getVolume(KyraEngine_v1::kVolumeEntry(button)); + const int oldVolume = _vm->getVolume(KyraEngine_v1::kVolumeEntry(button)); int newVolume = oldVolume; if (caller->index >= 24 && caller->index <= 27) @@ -1564,8 +1564,7 @@ int GUI_MR::sliderHandler(Button *caller) { else newVolume = _vm->_mouseX - caller->x - 7; - newVolume = MAX(2, newVolume); - newVolume = MIN(97, newVolume); + newVolume = CLIP(newVolume, 2, 97); if (newVolume == oldVolume) return 0; @@ -1621,8 +1620,7 @@ void GUI_MR::drawSliderBar(int slider, const uint8 *shape) { int position = _vm->getVolume(KyraEngine_v1::kVolumeEntry(slider)); - position = MAX(2, position); - position = MIN(97, position); + position = CLIP(position, 2, 97); _screen->drawShape(0, shape, x+position, y, 0, 0); } diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index 7e3d2b5afb..e5c8637fb5 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -27,6 +27,7 @@ #include "kyra/kyra_v2.h" #include "kyra/screen_v2.h" #include "kyra/text.h" +#include "kyra/util.h" #include "common/savefile.h" @@ -158,8 +159,9 @@ int GUI_v2::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseWh } } - int mouseX = _vm->_mouseX; - int mouseY = _vm->_mouseY; + Common::Point p = _vm->getMousePos(); + int mouseX = _vm->_mouseX = p.x; + int mouseY = _vm->_mouseY = p.y; uint16 flags = 0; @@ -454,8 +456,11 @@ void GUI_v2::setupSavegameNames(Menu &menu, int num) { Common::InSaveFile *in; 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; + char *s = getTableString(menu.item[i].itemId); + strncpy(s, header.description.c_str(), 80); + s[79] = 0; + Util::convertISOToDOS(s); + menu.item[i].saveSlot = _saveSlots[i + _savegameOffset]; menu.item[i].enabled = true; delete in; @@ -601,7 +606,7 @@ int GUI_v2::saveMenu(Button *caller) { updateAllMenuButtons(); while (_isSaveMenu) { - processHighlights(_saveMenu, _vm->_mouseX, _vm->_mouseY); + processHighlights(_saveMenu); getInput(); } @@ -620,6 +625,7 @@ int GUI_v2::saveMenu(Button *caller) { Graphics::Surface thumb; createScreenThumbnail(thumb); + Util::convertDOSToISO(_saveDescription); _vm->saveGameState(_saveSlot, _saveDescription, &thumb); thumb.free(); @@ -697,7 +703,7 @@ int GUI_v2::deleteMenu(Button *caller) { updateAllMenuButtons(); while (_isDeleteMenu) { - processHighlights(_saveMenu, _vm->_mouseX, _vm->_mouseY); + processHighlights(_saveMenu); getInput(); } @@ -749,7 +755,11 @@ const char *GUI_v2::nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 _cancelNameInput = _finishNameInput = false; while (running && !_vm->shouldQuit()) { checkTextfieldInput(); - processHighlights(_savenameMenu, _vm->_mouseX, _vm->_mouseY); + processHighlights(_savenameMenu); + + char inputKey = _keyPressed.ascii; + Util::convertISOToDOS(inputKey); + if (_keyPressed.keycode == Common::KEYCODE_RETURN || _keyPressed.keycode == Common::KEYCODE_KP_ENTER || _finishNameInput) { if (checkSavegameDescription(buffer, curPos)) { buffer[curPos] = 0; @@ -767,12 +777,12 @@ const char *GUI_v2::nameInputProcess(char *buffer, int x, int y, uint8 c1, uint8 drawTextfieldBlock(x2, y2, c3); _screen->updateScreen(); _lastScreenUpdate = _vm->_system->getMillis(); - } else if (_keyPressed.ascii > 31 && _keyPressed.ascii < 127 && curPos < bufferSize) { - if (x2 + getCharWidth(_keyPressed.ascii) + 7 < 0x11F) { - buffer[curPos] = _keyPressed.ascii; + } else if ((uint8)inputKey > 31 && (uint8)inputKey < 226 && curPos < bufferSize) { + if (x2 + getCharWidth(inputKey) + 7 < 0x11F) { + buffer[curPos] = inputKey; const char text[2] = { buffer[curPos], 0 }; _text->printText(text, x2, y2, c1, c2, c2); - x2 += getCharWidth(_keyPressed.ascii); + x2 += getCharWidth(inputKey); drawTextfieldBlock(x2, y2, c3); ++curPos; _screen->updateScreen(); @@ -840,7 +850,7 @@ bool GUI_v2::choiceDialog(int name, bool type) { _choice = false; while (_isChoiceMenu) { - processHighlights(_choiceMenu, _vm->_mouseX, _vm->_mouseY); + processHighlights(_choiceMenu); getInput(); } diff --git a/engines/kyra/gui_v2.h b/engines/kyra/gui_v2.h index ec30640b88..9af4572e4d 100644 --- a/engines/kyra/gui_v2.h +++ b/engines/kyra/gui_v2.h @@ -96,7 +96,7 @@ namespace Kyra { item.labelId = n; \ item.labelX = o; \ item.labelY = p; \ - item.unk1F = q; \ + item.keyCode = q; \ } while (0) class KyraEngine_v2; diff --git a/engines/kyra/items_hof.cpp b/engines/kyra/items_hof.cpp index 9d18829252..13e269f363 100644 --- a/engines/kyra/items_hof.cpp +++ b/engines/kyra/items_hof.cpp @@ -238,9 +238,7 @@ void KyraEngine_HoF::itemDropDown(int startX, int startY, int dstX, int dstY, in _screen->drawShape(0, itemShape, curX, curY-16, 0, 0); _screen->updateScreen(); - // XXX: original doesn't update game state while delaying - // our implementation *could* do it, so maybe check this again - delayUntil(endDelay); + delayUntil(endDelay, false, true); } if (dstX != dstY || (dstY - startY > 16)) { @@ -275,9 +273,7 @@ void KyraEngine_HoF::itemDropDown(int startX, int startY, int dstX, int dstY, in _screen->drawShape(0, itemShape, x, y, 0, 0); _screen->updateScreen(); - // XXX: original doesn't update game state while delaying - // our implementation *could* do it, so maybe check this again - delayUntil(endDelay); + delayUntil(endDelay, false, true); } restoreGfxRect24x24(x, y); diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp index e75a13c870..c0ddd0c860 100644 --- a/engines/kyra/items_lol.cpp +++ b/engines/kyra/items_lol.cpp @@ -477,7 +477,7 @@ void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int objec r = getNearestPartyMemberFromPos(x, y); runItemScript(t->attackerId, t->item, 0x8000, r, 0); } - } + } } void LoLEngine::updateFlyingObject(FlyingObject *t) { diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp index c2c36dcc95..5c41989713 100644 --- a/engines/kyra/kyra_hof.cpp +++ b/engines/kyra/kyra_hof.cpp @@ -381,10 +381,10 @@ void KyraEngine_HoF::startup() { memset(_sceneAnims, 0, sizeof(_sceneAnims)); for (int i = 0; i < ARRAYSIZE(_sceneAnimMovie); ++i) - _sceneAnimMovie[i] = new WSAMovie_v2(this, _screen); + _sceneAnimMovie[i] = new WSAMovie_v2(this); memset(_wsaSlots, 0, sizeof(_wsaSlots)); for (int i = 0; i < ARRAYSIZE(_wsaSlots); ++i) - _wsaSlots[i] = new WSAMovie_v2(this, _screen); + _wsaSlots[i] = new WSAMovie_v2(this); _screen->_curPage = 0; @@ -415,7 +415,7 @@ void KyraEngine_HoF::startup() { setupLangButtonShapes(); loadInventoryShapes(); - _res->loadFileToBuf("PALETTE.COL", _screen->_currentPalette, 0x300); + _screen->loadPalette("PALETTE.COL", _screen->getPalette(0)); _screen->loadBitmap("_PLAYFLD.CPS", 3, 3, 0); _screen->copyPage(3, 0); _screen->showMouse(); @@ -451,7 +451,6 @@ void KyraEngine_HoF::startup() { (*_inventoryButtons[0].buttonCallback)(&_inventoryButtons[0]); setNextIdleAnimTimer(); - //XXX setWalkspeed(_configWalkspeed); } @@ -643,8 +642,6 @@ bool KyraEngine_HoF::handleInputUnkSub(int x, int y) { while (_emc->isValid(&_sceneScriptState)) _emc->run(&_sceneScriptState); - //XXXsys_unkKeyboad (flush? wait? whatever...) - if (queryGameFlag(0x1ED)) { _sound->beginFadeOut(); _screen->fadeToBlack(); @@ -919,9 +916,9 @@ void KyraEngine_HoF::showMessage(const char *string, int16 palIndex) { if (string) { if (palIndex != -1 || _fadeMessagePalette) { palIndex *= 3; - memcpy(_messagePal, _screen->_currentPalette + palIndex, 3); - memmove(_screen->_currentPalette + 765, _screen->_currentPalette + palIndex, 3); - _screen->setScreenPalette(_screen->_currentPalette); + memcpy(_messagePal, _screen->getPalette(0).getData() + palIndex, 3); + _screen->getPalette(0).copy(_screen->getPalette(0), palIndex / 3, 1, 255); + _screen->setScreenPalette(_screen->getPalette(0)); } int x = _text->getCenterStringX(string, 0, 320); @@ -978,7 +975,7 @@ void KyraEngine_HoF::fadeMessagePalette() { } if (updatePalette) { - memcpy(_screen->getPalette(0) + 765, _messagePal, 3); + _screen->getPalette(0).copy(_messagePal, 0, 1, 255); _screen->setScreenPalette(_screen->getPalette(0)); } else { _fadeMessagePalette = false; @@ -1139,7 +1136,7 @@ void KyraEngine_HoF::updateCharPal(int unk1) { if (palEntry != _charPalEntry && unk1) { const uint8 *src = &_scenePal[(palEntry << 4) * 3]; - uint8 *ptr = _screen->getPalette(0) + 336; + uint8 *ptr = _screen->getPalette(0).getData() + 336; for (int i = 0; i < 48; ++i) { *ptr -= (*ptr - *src) >> 1; ++ptr; @@ -1149,7 +1146,7 @@ void KyraEngine_HoF::updateCharPal(int unk1) { unkVar1 = true; _charPalEntry = palEntry; } else if (unkVar1 || !unk1) { - memcpy(_screen->getPalette(0) + 336, &_scenePal[(palEntry << 4) * 3], 48); + _screen->getPalette(0).copy(_scenePal, palEntry << 4, 16, 112); _screen->setScreenPalette(_screen->getPalette(0)); unkVar1 = false; } @@ -1550,7 +1547,7 @@ void KyraEngine_HoF::loadInvWsa(const char *filename, int run_, int delayTime, i wsaFlags |= 2; if (!_invWsa.wsa) - _invWsa.wsa = new WSAMovie_v2(this, _screen); + _invWsa.wsa = new WSAMovie_v2(this); if (!_invWsa.wsa->open(filename, wsaFlags, 0)) error("Couldn't open inventory WSA file '%s'", filename); @@ -1656,12 +1653,12 @@ void KyraEngine_HoF::displayInvWsaLastFrame() { #pragma mark - void KyraEngine_HoF::setCauldronState(uint8 state, bool paletteFade) { - memcpy(_screen->getPalette(2), _screen->getPalette(0), 768); + _screen->copyPalette(2, 0); Common::SeekableReadStream *file = _res->createReadStream("_POTIONS.PAL"); if (!file) error("Couldn't load cauldron palette"); file->seek(state*18, SEEK_SET); - file->read(_screen->getPalette(2)+723, 18); + _screen->getPalette(0).loadVGAPalette(*file, 241, 6); delete file; file = 0; @@ -1673,7 +1670,7 @@ void KyraEngine_HoF::setCauldronState(uint8 state, bool paletteFade) { _screen->updateScreen(); } - memcpy(_screen->getPalette(0)+723, _screen->getPalette(2)+723, 18); + _screen->getPalette(0).copy(_screen->getPalette(2), 241, 6); _cauldronState = state; _cauldronUseCount = 0; //if (state == 5) @@ -1833,11 +1830,11 @@ void KyraEngine_HoF::cauldronRndPaletteFade() { if (!file) error("Couldn't load cauldron palette"); file->seek(index*18, SEEK_SET); - file->read(_screen->getPalette(0)+723, 18); + _screen->getPalette(0).loadVGAPalette(*file, 241, 6); snd_playSoundEffect(0x6A); _screen->fadePalette(_screen->getPalette(0), 0x1E, &_updateFunctor); file->seek(0, SEEK_SET); - file->read(_screen->getPalette(0)+723, 18); + _screen->getPalette(0).loadVGAPalette(*file, 241, 6); delete file; _screen->fadePalette(_screen->getPalette(0), 0x1E, &_updateFunctor); } diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp index fcd35e7282..e5ca52abcc 100644 --- a/engines/kyra/kyra_lok.cpp +++ b/engines/kyra/kyra_lok.cpp @@ -157,7 +157,10 @@ KyraEngine_LoK::~KyraEngine_LoK() { } Common::Error KyraEngine_LoK::init() { - _screen = new Screen_LoK(this, _system); + if (_flags.platform == Common::kPlatformPC98 && _flags.useHiResOverlay && ConfMan.getBool("16_color")) + _screen = new Screen_LoK_16(this, _system); + else + _screen = new Screen_LoK(this, _system); assert(_screen); _screen->setResolution(); @@ -358,7 +361,7 @@ void KyraEngine_LoK::startup() { loadButtonShapes(); initMainButtonList(); loadMainScreen(); - _screen->loadPalette("PALETTE.COL", _screen->_currentPalette); + _screen->loadPalette("PALETTE.COL", _screen->getPalette(0)); // XXX _animator->initAnimStateList(); @@ -906,6 +909,9 @@ void KyraEngine_LoK::registerDefaultSettings() { // Most settings already have sensible defaults. This one, however, is // specific to the Kyra engine. ConfMan.registerDefault("walkspeed", 2); + + if (_flags.platform == Common::kPlatformPC98 && _flags.useHiResOverlay) + ConfMan.registerDefault("16_color", false); } void KyraEngine_LoK::readSettings() { diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h index a0f38c3acc..a905c5521b 100644 --- a/engines/kyra/kyra_lok.h +++ b/engines/kyra/kyra_lok.h @@ -113,7 +113,6 @@ public: KyraEngine_LoK(OSystem *system, const GameFlags &flags); ~KyraEngine_LoK(); - //TODO: proper extended implementation of KyraEngine_v1::pauseEngineIntern. // _sprites and _seqplayer should be paused here too, to avoid some animation glitches, // also parts of the hardcoded Malcolm fight might need some special handling. diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp index f2ea0c91df..871edd578d 100644 --- a/engines/kyra/kyra_mr.cpp +++ b/engines/kyra/kyra_mr.cpp @@ -230,7 +230,7 @@ Common::Error KyraEngine_MR::init() { _screen->setAnimBlockPtr(3500); _screen->setScreenDim(0); - _res->loadFileToBuf("PALETTE.COL", _screen->getPalette(0), 768); + _screen->loadPalette("PALETTE.COL", _screen->getPalette(0)); _screen->setScreenPalette(_screen->getPalette(0)); return Common::kNoError; @@ -269,19 +269,18 @@ Common::Error KyraEngine_MR::go() { _screen->setScreenPalette(_screen->getPalette(0)); - // XXX playMenuAudioFile(); for (int i = 0; i < 64 && !shouldQuit(); ++i) { uint32 nextRun = _system->getMillis() + 3 * _tickLength; - _menuAnim->displayFrame(i, 0, 0, 0, 0); + _menuAnim->displayFrame(i, 0, 0, 0, 0, 0, 0); _screen->updateScreen(); delayUntil(nextRun); } for (int i = 64; i > 29 && !shouldQuit(); --i) { uint32 nextRun = _system->getMillis() + 3 * _tickLength; - _menuAnim->displayFrame(i, 0, 0, 0, 0); + _menuAnim->displayFrame(i, 0, 0, 0, 0, 0, 0); _screen->updateScreen(); delayUntil(nextRun); } @@ -327,9 +326,9 @@ Common::Error KyraEngine_MR::go() { } void KyraEngine_MR::initMainMenu() { - _menuAnim = new WSAMovie_v2(this, _screen); - _menuAnim->open("REVENGE.WSA", 1, _screen->getPalette(0)); - memset(_screen->getPalette(0), 0, 3); + _menuAnim = new WSAMovie_v2(this); + _menuAnim->open("REVENGE.WSA", 1, &_screen->getPalette(0)); + _screen->getPalette(0).fill(0, 1, 0); _menu = new MainMenu(this); MainMenu::StaticData data = { @@ -378,7 +377,7 @@ void KyraEngine_MR::playVQA(const char *name) { } _screen->hideMouse(); - memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); + _screen->copyPalette(1, 0); fadeOutMusic(60); _screen->fadeToBlack(60); _screen->clearPage(0); @@ -390,12 +389,11 @@ void KyraEngine_MR::playVQA(const char *name) { _soundDigital->stopAllSounds(); _screen->showMouse(); - uint8 pal[768]; // Taken from original, it used '1' here too - memset(pal, 1, sizeof(pal)); - _screen->setScreenPalette(pal); + _screen->getPalette(0).fill(0, 256, 1); + _screen->setScreenPalette(_screen->getPalette(0)); _screen->clearPage(0); - memcpy(_screen->getPalette(0), _screen->getPalette(1), 768); + _screen->copyPalette(0, 1); _wasPlayingVQA = true; } } @@ -541,11 +539,11 @@ void KyraEngine_MR::initMouseShapes() { } void KyraEngine_MR::startup() { - _album.wsa = new WSAMovie_v2(this, _screen); + _album.wsa = new WSAMovie_v2(this); assert(_album.wsa); - _album.leftPage.wsa = new WSAMovie_v2(this, _screen); + _album.leftPage.wsa = new WSAMovie_v2(this); assert(_album.leftPage.wsa); - _album.rightPage.wsa = new WSAMovie_v2(this, _screen); + _album.rightPage.wsa = new WSAMovie_v2(this); assert(_album.rightPage.wsa); musicUpdate(0); @@ -559,9 +557,7 @@ void KyraEngine_MR::startup() { _screen->setFont(Screen::FID_6_FNT); _stringBuffer = new char[500]; - //XXX musicUpdate(0); - //XXX allocAnimObjects(1, 16, 50); musicUpdate(0); @@ -586,19 +582,16 @@ void KyraEngine_MR::startup() { error("couldn't load _ACTOR"); musicUpdate(0); - //XXX - musicUpdate(0); openTalkFile(0); musicUpdate(0); _currentTalkFile = 0; openTalkFile(1); - //XXX loadCostPal(); musicUpdate(0); for (int i = 0; i < 16; ++i) { _sceneAnims[i].flags = 0; - _sceneAnimMovie[i] = new WSAMovie_v2(this, _screen); + _sceneAnimMovie[i] = new WSAMovie_v2(this); assert(_sceneAnimMovie[i]); } @@ -627,7 +620,7 @@ void KyraEngine_MR::startup() { loadInterfaceShapes(); musicUpdate(0); - _res->loadFileToBuf("PALETTE.COL", _screen->getPalette(0), 768); + _screen->loadPalette("PALETTE.COL", _screen->getPalette(0)); _paletteOverlay = new uint8[256]; _screen->generateOverlay(_screen->getPalette(0), _paletteOverlay, 0xF0, 0x19); @@ -655,7 +648,7 @@ void KyraEngine_MR::startup() { musicUpdate(0); runStartupScript(1, 0); _res->exists("MOODOMTR.WSA", true); - _invWsa = new WSAMovie_v2(this, _screen); + _invWsa = new WSAMovie_v2(this); assert(_invWsa); _invWsa->open("MOODOMTR.WSA", 1, 0); _invWsaFrame = 6; @@ -899,40 +892,30 @@ void KyraEngine_MR::updateCharAnimFrame(int character, int *table) { void KyraEngine_MR::updateCharPal(int unk1) { int layer = _screen->getLayer(_mainCharacter.x1, _mainCharacter.y1) - 1; const uint8 *src = _costPalBuffer + _characterShapeFile * 72; - uint8 *dst = _screen->getPalette(0) + 432; + Palette &dst = _screen->getPalette(0); const int8 *sceneDatPal = &_sceneDatPalette[layer * 3]; if (layer != _lastCharPalLayer && unk1) { - for (int i = 0, j = 0; i < 72; ++i) { - uint8 col = *dst; - int8 addCol = *src + *sceneDatPal; - addCol = MAX<int8>(0, MIN<int8>(addCol, 63)); - addCol = (col - addCol) >> 1; - *dst -= addCol; - ++dst; - ++src; - ++sceneDatPal; - ++j; - if (j > 3) { - sceneDatPal = &_sceneDatPalette[layer * 3]; - j = 0; + for (int i = 144; i < 168; ++i) { + for (int j = 0; j < 3; ++j) { + uint8 col = dst[i * 3 + j]; + int subCol = src[(i - 144) * 3 + j] + sceneDatPal[j]; + subCol = CLIP(subCol, 0, 63); + subCol = (col - subCol) / 2; + dst[i * 3 + j] -= subCol; } } + _charPalUpdate = true; _screen->setScreenPalette(_screen->getPalette(0)); _lastCharPalLayer = layer; } else if (_charPalUpdate || !unk1) { - memcpy(dst, src, 72); - - for (int i = 0, j = 0; i < 72; ++i) { - uint8 col = *dst + *sceneDatPal; - *dst = MAX<int8>(0, MIN<int8>(col, 63)); - ++dst; - ++sceneDatPal; - ++j; - if (j >= 3) { - sceneDatPal = &_sceneDatPalette[layer * 3]; - j = 0; + dst.copy(_costPalBuffer, _characterShapeFile * 24, 24, 144); + + for (int i = 144; i < 168; ++i) { + for (int j = 0; j < 3; ++j) { + int col = dst[i * 3 + j] + sceneDatPal[j]; + dst[i * 3 + j] = CLIP(col, 0, 63); } } diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h index 6c06a84433..88bfb8c89b 100644 --- a/engines/kyra/kyra_mr.h +++ b/engines/kyra/kyra_mr.h @@ -50,7 +50,6 @@ public: KyraEngine_MR(OSystem *system, const GameFlags &flags); ~KyraEngine_MR(); - //TODO: proper extended implementation of KyraEngine_v2::pauseEngineIntern. // Idle animation time, item animations and album animations should be taken // care of, but since those would just produce minor glitches it's not that // important. diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index d9fc8f9d66..80872877d5 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -81,7 +81,7 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags) Common::addDebugChannel(kDebugLevelMovie, "Movie", "Movie debug level"); Common::addDebugChannel(kDebugLevelTimer, "Timer", "Timer debug level"); - system->getEventManager()->registerRandomSource(_rnd, "kyra"); + _eventMan->registerRandomSource(_rnd, "kyra"); } ::GUI::Debugger *KyraEngine_v1::getDebugger() { @@ -94,8 +94,6 @@ void KyraEngine_v1::pauseEngineIntern(bool pause) { } Common::Error KyraEngine_v1::init() { - registerDefaultSettings(); - // Setup mixer _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); @@ -278,10 +276,10 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag) } else { switch(event.kbd.keycode) { case Common::KEYCODE_SPACE: - keys = 43; + keys = 61; break; case Common::KEYCODE_RETURN: - keys = 61; + keys = 43; break; case Common::KEYCODE_UP: case Common::KEYCODE_KP8: @@ -594,27 +592,27 @@ bool KyraEngine_v1::textEnabled() { return !_flags.isTalkie || (_configVoice == 0 || _configVoice == 2); } -inline int convertValueToMixer(int value) { +int KyraEngine_v1::convertVolumeToMixer(int value) { value -= 2; return (value * Audio::Mixer::kMaxMixerVolume) / 95; } -inline int convertValueFromMixer(int value) { +int KyraEngine_v1::convertVolumeFromMixer(int value) { return (value * 95) / Audio::Mixer::kMaxMixerVolume + 2; } void KyraEngine_v1::setVolume(kVolumeEntry vol, uint8 value) { switch (vol) { case kVolumeMusic: - ConfMan.setInt("music_volume", convertValueToMixer(value)); + ConfMan.setInt("music_volume", convertVolumeToMixer(value)); break; case kVolumeSfx: - ConfMan.setInt("sfx_volume", convertValueToMixer(value)); + ConfMan.setInt("sfx_volume", convertVolumeToMixer(value)); break; case kVolumeSpeech: - ConfMan.setInt("speech_volume", convertValueToMixer(value)); + ConfMan.setInt("speech_volume", convertVolumeToMixer(value)); break; } @@ -629,16 +627,16 @@ void KyraEngine_v1::setVolume(kVolumeEntry vol, uint8 value) { uint8 KyraEngine_v1::getVolume(kVolumeEntry vol) { switch (vol) { case kVolumeMusic: - return convertValueFromMixer(ConfMan.getInt("music_volume")); + return convertVolumeFromMixer(ConfMan.getInt("music_volume")); break; case kVolumeSfx: - return convertValueFromMixer(ConfMan.getInt("sfx_volume")); + return convertVolumeFromMixer(ConfMan.getInt("sfx_volume")); break; case kVolumeSpeech: if (speechEnabled()) - return convertValueFromMixer(ConfMan.getInt("speech_volume")); + return convertVolumeFromMixer(ConfMan.getInt("speech_volume")); else return 2; break; diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index b45f21dd89..5ece70e3f1 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -153,7 +153,7 @@ public: kVolumeSpeech = 2 }; - // volume reaches from 2 to 97 + // volume reaches per default from 2 to 97 void setVolume(kVolumeEntry vol, uint8 value); uint8 getVolume(kVolumeEntry vol); @@ -181,13 +181,16 @@ protected: // Engine APIs virtual Common::Error init(); virtual Common::Error go() = 0; + virtual Common::Error run() { Common::Error err; + registerDefaultSettings(); err = init(); if (err != Common::kNoError) return err; return go(); } + virtual ::GUI::Debugger *getDebugger(); virtual bool hasFeature(EngineFeature f) const; virtual void pauseEngineIntern(bool pause); @@ -289,6 +292,9 @@ protected: const int8 *_trackMap; int _trackMapSize; + virtual int convertVolumeToMixer(int value); + virtual int convertVolumeFromMixer(int value); + // pathfinder virtual int findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize); int findSubPath(int x, int y, int toX, int toY, int *moveTable, int start, int end); diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 3461fa5da9..020e1ea3ea 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -82,7 +82,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _curTlkFile = -1; _lastSpeaker = _lastSpeechId = _nextSpeechId = _nextSpeaker = -1; - memset(_moneyColumnHeight, 0, 5); + memset(_moneyColumnHeight, 0, sizeof(_moneyColumnHeight)); _credits = 0; _itemsInPlay = 0; @@ -200,7 +200,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _partyPosX = _partyPosY = 0; _shpDmX = _shpDmY = _dmScaleW = _dmScaleH = 0; - _floatingMouseArrowControl = 0; + _floatingCursorControl = _currentFloatingCursor = 0; memset(_activeTim, 0, sizeof(_activeTim)); memset(_openDoorState, 0, sizeof(_openDoorState)); @@ -222,10 +222,6 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _preserveEvents = false; _buttonList1 = _buttonList2 = _buttonList3 = _buttonList4 = _buttonList5 = _buttonList6 = _buttonList7 = _buttonList8 = 0; - _monsterDifficulty = 1; - _smoothScrollingEnabled = true; - _floatingCursorsEnabled = false; - memset(_lvlTempData, 0, sizeof(_lvlTempData)); _mapOverlay = 0; @@ -436,6 +432,7 @@ Common::Error LoLEngine::init() { _gui = new GUI_LoL(this); assert(_gui); + _gui->initStaticData(); _txt = new TextDisplayer_LoL(this, _screen); @@ -456,8 +453,6 @@ Common::Error LoLEngine::init() { if (!_sound->init()) error("Couldn't init sound"); - _speechFlag = speechEnabled() ? 0x48 : 0; - _wllVmpMap = new uint8[80]; memset(_wllVmpMap, 0, 80); _wllShapeMap = new int8[80]; @@ -561,7 +556,7 @@ Common::Error LoLEngine::go() { // Usually fonts etc. would be setup by the prologue code, if we skip // the prologue code we need to setup them manually here. - if (_gameToLoad != -1) { + if (_gameToLoad != -1 && action != 3) { preInit(); _screen->setFont(Screen::FID_9_FNT); } @@ -591,8 +586,6 @@ Common::Error LoLEngine::go() { if (loadGameState(_gameToLoad) != Common::kNoError) error("Couldn't load game slot %d on startup", _gameToLoad); _gameToLoad = -1; - } else if (action == 3) { - // XXX } _screen->_fadeFlag = 3; @@ -639,6 +632,15 @@ void LoLEngine::loadItemIconShapes() { _itemIconShapes[i] = _screen->makeShapeCopy(shp, i); _screen->setMouseCursor(0, 0, _itemIconShapes[0]); + + if (!_gameShapes) { + _screen->loadBitmap("GAMESHP.SHP", 3, 3, 0); + shp = _screen->getCPagePtr(3); + _numGameShapes = READ_LE_UINT16(shp); + _gameShapes = new uint8*[_numGameShapes]; + for (int i = 0; i < _numGameShapes; i++) + _gameShapes[i] = _screen->makeShapeCopy(shp, i); + } } void LoLEngine::setMouseCursorToIcon(int icon) { @@ -661,6 +663,53 @@ bool LoLEngine::posWithinRect(int mouseX, int mouseY, int x1, int y1, int x2, in return true; } +void LoLEngine::checkFloatingPointerRegions() { + if (!_floatingCursorsEnabled) + return; + + int t = -1; + + Common::Point p = getMousePos(); + + if (!(_updateFlags & 4) & !_floatingCursorControl) { + if (posWithinRect(p.x, p.y, 96, 0, 303, 136)) { + if (!posWithinRect(p.x, p.y, 128, 16, 271, 119)) { + if (posWithinRect(p.x, p.y, 112, 0, 287, 15)) + t = 0; + if (posWithinRect(p.x, p.y, 272, 88, 303, 319)) + t = 1; + if (posWithinRect(p.x, p.y, 112, 110, 287, 135)) + t = 2; + if (posWithinRect(p.x, p.y, 96, 88, 127, 119)) + t = 3; + if (posWithinRect(p.x, p.y, 96, 16, 127, 87)) + t = 4; + if (posWithinRect(p.x, p.y, 272, 16, 303, 87)) + t = 5; + + if (t < 4) { + int d = (_currentDirection + t) & 3; + if (!checkBlockPassability(calcNewBlockPosition(_currentBlock, d), d)) + t = 6; + } + } + } + } + + if (t == _currentFloatingCursor) + return; + + if (t == -1) { + setMouseCursorToItemInHand(); + } else { + static const uint8 floatingPtrX[] = { 7, 13, 7, 0, 0, 15, 7 }; + static const uint8 floatingPtrY[] = { 0, 7, 12, 7, 6, 6, 7 }; + _screen->setMouseCursor(floatingPtrX[t], floatingPtrY[t], _gameShapes[10 + t]); + } + + _currentFloatingCursor = t; +} + uint8 *LoLEngine::getItemIconShapePtr(int index) { int ix = _itemProperties[_itemsInPlay[index].itemPropertyIndex].shpIndex; if (_itemProperties[_itemsInPlay[index].itemPropertyIndex].flags & 0x200) @@ -714,7 +763,7 @@ int LoLEngine::mainMenu() { assert(menu); menu->init(data[dataIndex], MainMenu::Animation()); - int selection = menu->handle(_flags.isTalkie ? (hasSave ? 17 : 6) : (hasSave ? 6 : 18)); + int selection = menu->handle(_flags.isTalkie ? (hasSave ? 19 : 6) : (hasSave ? 6 : 20)); delete menu; _screen->setScreenDim(0); @@ -729,20 +778,20 @@ int LoLEngine::mainMenu() { void LoLEngine::startup() { _screen->clearPage(0); - _screen->loadBitmap("PLAYFLD.CPS", 3, 3, _screen->_currentPalette); - uint8 *tmpPal = new uint8[0x300]; - memcpy(tmpPal, _screen->_currentPalette, 0x300); - memset(_screen->_currentPalette, 0x3f, 0x180); - memcpy(_screen->_currentPalette + 3, tmpPal + 3, 3); - memset(_screen->_currentPalette + 0x240, 0x3f, 12); - _screen->generateOverlay(_screen->_currentPalette, _screen->_paletteOverlay1, 1, 96); - _screen->generateOverlay(_screen->_currentPalette, _screen->_paletteOverlay2, 144, 65); - memcpy(_screen->_currentPalette, tmpPal, 0x300); - delete[] tmpPal; + Palette &pal = _screen->getPalette(0); + _screen->loadBitmap("PLAYFLD.CPS", 3, 3, &pal); - memset(_screen->getPalette(1), 0, 0x300); - memset(_screen->getPalette(2), 0, 0x300); + _screen->copyPalette(1, 0); + pal.fill(0, 1, 0x3F); + pal.fill(2, 126, 0x3F); + pal.fill(192, 4, 0x3F); + _screen->generateOverlay(pal, _screen->_paletteOverlay1, 1, 96); + _screen->generateOverlay(pal, _screen->_paletteOverlay2, 144, 65); + _screen->copyPalette(0, 1); + + _screen->getPalette(1).clear(); + _screen->getPalette(2).clear(); loadItemIconShapes(); _screen->setMouseCursor(0, 0, _itemIconShapes[0x85]); @@ -754,13 +803,6 @@ void LoLEngine::startup() { for (int i = 0; i < _numItemShapes; i++) _itemShapes[i] = _screen->makeShapeCopy(shp, i); - _screen->loadBitmap("GAMESHP.SHP", 3, 3, 0); - shp = _screen->getCPagePtr(3); - _numGameShapes = READ_LE_UINT16(shp); - _gameShapes = new uint8*[_numGameShapes]; - for (int i = 0; i < _numGameShapes; i++) - _gameShapes[i] = _screen->makeShapeCopy(shp, i); - _screen->loadBitmap("THROWN.SHP", 3, 3, 0); shp = _screen->getCPagePtr(3); _numThrownShapes = READ_LE_UINT16(shp); @@ -808,9 +850,6 @@ void LoLEngine::startup() { _loadSuppFilesFlag = 1; - _txt->setAnimParameters("<MORE>", 10, 31, 0); - _txt->setAnimFlag(true); - _sound->loadSfxFile("LORESFX"); setMouseCursorToItemInHand(); @@ -822,12 +861,6 @@ void LoLEngine::startupNew() { _compassDirection = _compassDirectionIndex = -1; _lastMouseRegion = -1; - - /* - _unk5 = 1; - _unk6 = 1; - _unk7 = 1 - _unk8 = 1*/ _currentLevel = 1; giveCredits(41, 0); @@ -858,6 +891,12 @@ void LoLEngine::runLoop() { _flagsTable[73] |= 0x08; while (!shouldQuit() && _runFlag) { + if (_gameToLoad != -1) { + if (loadGameState(_gameToLoad) != Common::kNoError) + error("Couldn't load game slot %d", _gameToLoad); + _gameToLoad = -1; + } + if (_nextScriptFunc) { runLevelScript(_nextScriptFunc, 2); _nextScriptFunc = 0; @@ -865,7 +904,7 @@ void LoLEngine::runLoop() { _timer->update(); - //checkFloatingPointerRegions(); + checkFloatingPointerRegions(); gui_updateInput(); update(); @@ -884,6 +923,55 @@ void LoLEngine::runLoop() { } } +void LoLEngine::registerDefaultSettings() { + KyraEngine_v1::registerDefaultSettings(); + + // Most settings already have sensible defaults. This one, however, is + // specific to the LoL engine. + ConfMan.registerDefault("floating_cursors", false); + ConfMan.registerDefault("smooth_scrolling", true); + ConfMan.registerDefault("monster_difficulty", 1); +} + +void LoLEngine::writeSettings() { + ConfMan.setInt("monster_difficulty", _monsterDifficulty); + ConfMan.setBool("floating_cursors", _floatingCursorsEnabled); + ConfMan.setBool("smooth_scrolling", _smoothScrollingEnabled); + + switch (_lang) { + case 1: + _flags.lang = Common::FR_FRA; + break; + + case 2: + _flags.lang = Common::DE_DEU; + break; + + case 3: + _flags.lang = Common::JA_JPN; + break; + + case 0: + default: + _flags.lang = Common::EN_ANY; + } + + if (_flags.lang == _flags.replacedLang && _flags.fanLang != Common::UNK_LANG) + _flags.lang = _flags.fanLang; + + ConfMan.set("language", Common::getLanguageCode(_flags.lang)); + + KyraEngine_v1::writeSettings(); +} + +void LoLEngine::readSettings() { + _monsterDifficulty = ConfMan.getInt("monster_difficulty"); + _smoothScrollingEnabled = ConfMan.getBool("smooth_scrolling"); + _floatingCursorsEnabled = ConfMan.getBool("floating_cursors"); + + KyraEngine_v1::readSettings(); +} + void LoLEngine::update() { updateSequenceBackgroundAnimations(); @@ -1095,7 +1183,7 @@ void LoLEngine::updatePortraitSpeechAnim() { f -= 5; f += 7; - if (_speechFlag) { + if (speechEnabled()) { if (snd_updateCharacterSpeech() == 2) _updatePortraitSpeechAnimDuration = 2; else @@ -1233,7 +1321,7 @@ void LoLEngine::setCharacterMagicOrHitPoints(int charNum, int type, int points, if (charNum > 3) return; - + LoLCharacter *c = &_characters[charNum]; if (!(c->flags & 1)) return; @@ -1421,7 +1509,7 @@ void LoLEngine::gui_specialSceneSuspendControls(int controlMode) { _specialSceneFlag = 1; _currentControlMode = controlMode; calcCharPortraitXpos(); - //checkMouseRegions(); + checkFloatingPointerRegions(); } void LoLEngine::gui_specialSceneRestoreControls(int restoreLamp) { @@ -1431,7 +1519,7 @@ void LoLEngine::gui_specialSceneRestoreControls(int restoreLamp) { } _updateFlags &= 0xfffe; _specialSceneFlag = 0; - //checkMouseRegions(); + checkFloatingPointerRegions(); } void LoLEngine::restoreAfterSceneWindowDialogue(int redraw) { @@ -1450,7 +1538,7 @@ void LoLEngine::restoreAfterSceneWindowDialogue(int redraw) { if (_screen->_fadeFlag != 2) _screen->fadeClearSceneWindow(10); gui_drawPlayField(); - setPaletteBrightness(_screen->_currentPalette, _brightness, _lampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); _screen->_fadeFlag = 0; } @@ -1584,15 +1672,16 @@ void LoLEngine::transformRegion(int x1, int y1, int x2, int y2, int w, int h, in } } -void LoLEngine::setPaletteBrightness(uint8 *palette, int brightness, int modifier) { - generateBrightnessPalette(palette, _screen->getPalette(1), brightness, modifier); +void LoLEngine::setPaletteBrightness(const Palette &srcPal, int brightness, int modifier) { + generateBrightnessPalette(srcPal, _screen->getPalette(1), brightness, modifier); _screen->fadePalette(_screen->getPalette(1), 5, 0); _screen->_fadeFlag = 0; } -void LoLEngine::generateBrightnessPalette(uint8 *src, uint8 *dst, int brightness, int modifier) { - memcpy(dst, src, 0x300); +void LoLEngine::generateBrightnessPalette(const Palette &src, Palette &dst, int brightness, int modifier) { + dst.copy(src); _screen->loadSpecialColors(dst); + brightness = (8 - brightness) << 5; if (modifier >= 0 && modifier < 8 && (_flagsTable[31] & 0x08)) { brightness = 256 - ((((modifier & 0xfffe) << 5) * (256 - brightness)) >> 8); @@ -1606,26 +1695,21 @@ void LoLEngine::generateBrightnessPalette(uint8 *src, uint8 *dst, int brightness } } -void LoLEngine::generateFlashPalette(uint8 *src, uint8 *dst, int colorFlags) { - if (!src || !dst) - return; - - memcpy(dst, src, 6); - - uint8 *s = src + 6; - uint8 *d = dst + 6; +void LoLEngine::generateFlashPalette(const Palette &src, Palette &dst, int colorFlags) { + dst.copy(src, 0, 2); for (int i = 2; i < 128; i++) { for (int ii = 0; ii < 3; ii++) { - uint8 t = *s++ & 0x3f; + uint8 t = src[i * 3 + ii] & 0x3f; if (colorFlags & (1 << ii)) t += ((0x3f - t) >> 1); else t -= (t >> 1); - *d++ = t; + dst[i * 3 + ii] = t; } } - memcpy(d, s, 384); + + dst.copy(src, 128); } void LoLEngine::updateSequenceBackgroundAnimations() { @@ -1790,32 +1874,6 @@ void LoLEngine::delay(uint32 millis, bool doUpdate, bool) { } } -uint8 LoLEngine::getRandomNumberSpecial() { - uint8 a = _rndSpecial & 0xff; - uint8 b = (_rndSpecial >> 8) & 0xff; - uint8 c = (_rndSpecial >> 16) & 0xff; - - a >>= 1; - - uint as = a & 1; - uint bs = (b >> 7) ? 0 : 1; - uint cs = c >> 7; - - a >>= 1; - c = (c << 1) | as; - b = (b << 1) | cs; - - a -= ((_rndSpecial & 0xff) - bs); - as = a & 1; - a >>= 1; - - a = ((_rndSpecial & 0xff) >> 1) | (as << 7); - - _rndSpecial = (_rndSpecial & 0xff000000) | (c << 16) | (b << 8) | a; - - return a ^ b; -} - void LoLEngine::updateEnvironmentalSfx(int soundId) { snd_processEnvironmentalSoundEffect(soundId, _currentBlock); } @@ -1919,7 +1977,7 @@ int LoLEngine::castHealOnSingleCharacter(ActiveSpell *a) { } int LoLEngine::processMagicSpark(int charNum, int spellLevel) { - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); _screen->copyPage(0, 12); mov->open("spark1.wsa", 0, 0); @@ -2120,25 +2178,24 @@ int LoLEngine::processMagicIce(int charNum, int spellLevel) { gui_drawScene(0); _screen->copyPage(0, 12); - uint8 *tpal = new uint8[768]; - uint8 *swampCol = new uint8[768]; + Palette tpal(768), swampCol(768); if (_currentLevel == 11 && !(_flagsTable[52] & 0x04)) { - uint8 *sc = _screen->_currentPalette; - uint8 *dc = _screen->getPalette(2); + uint8 *sc = _screen->getPalette(0).getData(); + uint8 *dc = _screen->getPalette(2).getData(); for (int i = 1; i < 768; i++) SWAP(sc[i], dc[i]); + _flagsTable[52] |= 0x04; static const uint8 freezeTimes[] = { 20, 28, 40, 60 }; setCharacterUpdateEvent(charNum, 8, freezeTimes[spellLevel], 1); } - uint8 *sc = _res->fileData("swampice.col", 0); - memcpy(swampCol, sc, 384); - uint8 *s = _screen->getPalette(1); - for (int i = 384; i < 768; i++) - swampCol[i] = tpal[i] = s[i] & 0x3f; + _screen->loadPalette("SWAMPICE.COL", swampCol); + tpal.copy(_screen->getPalette(1), 128); + swampCol.copy(_screen->getPalette(1), 128); + Palette &s = _screen->getPalette(1); for (int i = 1; i < 128; i++) { tpal[i * 3] = 0; uint16 v = (s[i * 3] + s[i * 3 + 1] + s[i * 3 + 2]) / 3; @@ -2148,24 +2205,25 @@ int LoLEngine::processMagicIce(int charNum, int spellLevel) { if (tpal[i * 3 + 2] > 0x3f) tpal[i * 3 + 2] = 0x3f; } + generateBrightnessPalette(tpal, tpal, _brightness, _lampEffect); generateBrightnessPalette(swampCol, swampCol, _brightness, _lampEffect); swampCol[0] = swampCol[1] = swampCol[2] = tpal[0] = tpal[1] = tpal[2] = 0; - generateBrightnessPalette(_screen->_currentPalette, s, _brightness, _lampEffect); + generateBrightnessPalette(_screen->getPalette(0), s, _brightness, _lampEffect); int sX = 112; int sY = 0; - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); if (spellLevel == 0) { sX = 0; } if (spellLevel == 1 || spellLevel == 2) { - mov->open("snow.wsa", 1, 0); + mov->open("SNOW.WSA", 1, 0); if (!mov->opened()) error("Ice: Unable to load snow.wsa"); } if (spellLevel == 3) { - mov->open("ice.wsa", 1, 0); + mov->open("ICE.WSA", 1, 0); if (!mov->opened()) error("Ice: Unable to load ice.wsa"); sX = 136; @@ -2174,9 +2232,9 @@ int LoLEngine::processMagicIce(int charNum, int spellLevel) { snd_playSoundEffect(71, -1); - playSpellAnimation(0, 0, 0, 2, 0, 0, 0, s, tpal, 40, false); + playSpellAnimation(0, 0, 0, 2, 0, 0, 0, s.getData(), tpal.getData(), 40, false); - _screen->fadePaletteStep(s, tpal, _system->getMillis(), _tickLength); + _screen->fadePaletteStep(s.getData(), tpal.getData(), _system->getMillis(), _tickLength); if (mov->opened()) { int r = true; if (spellLevel > 2) { @@ -2241,22 +2299,19 @@ int LoLEngine::processMagicIce(int charNum, int spellLevel) { enableSysTimer(2); if (_currentLevel != 11) - generateBrightnessPalette(_screen->_currentPalette, swampCol, _brightness, _lampEffect); + generateBrightnessPalette(_screen->getPalette(0), swampCol, _brightness, _lampEffect); - playSpellAnimation(0, 0, 0, 2, 0, 0, 0, tpal, swampCol, 40, 0); + playSpellAnimation(0, 0, 0, 2, 0, 0, 0, tpal.getData(), swampCol.getData(), 40, 0); - _screen->fadePaletteStep(tpal, swampCol, _system->getMillis(), _tickLength); + _screen->fadePaletteStep(tpal.getData(), swampCol.getData(), _system->getMillis(), _tickLength); if (breakWall) - breakIceWall(tpal, swampCol); + breakIceWall(tpal.getData(), swampCol.getData()); static const uint8 freezeTime[] = { 20, 28, 40, 60 }; if (_currentLevel == 11) setCharacterUpdateEvent(charNum, 8, freezeTime[spellLevel], 1); - delete[] sc; - delete[] swampCol; - delete[] tpal; _screen->setCurPage(cp); return 1; } @@ -2417,7 +2472,7 @@ int LoLEngine::processMagicHandOfFate(int spellLevel) { int cp = _screen->setCurPage(2); _screen->copyPage(0, 12); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); mov->open("hand.wsa", 1, 0); if (!mov->opened()) error("Hand: Unable to load HAND.WSA"); @@ -2495,8 +2550,8 @@ int LoLEngine::processMagicHandOfFate(int spellLevel) { int LoLEngine::processMagicMistOfDoom(int charNum, int spellLevel) { static const uint8 mistDamage[] = { 30, 70, 110, 200 }; - - _envSfxUseQueue = true; + + _envSfxUseQueue = true; inflictMagicalDamageForBlock(calcNewBlockPosition(_currentBlock, _currentDirection), charNum, mistDamage[spellLevel], 0x80); _envSfxUseQueue = false; @@ -2509,7 +2564,7 @@ int LoLEngine::processMagicMistOfDoom(int charNum, int spellLevel) { char wsafile[13]; snprintf(wsafile, 13, "mists%0d.wsa", spellLevel + 1); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); mov->open(wsafile, 1, 0); if (!mov->opened()) error("Mist: Unable to load mists.wsa"); @@ -2541,7 +2596,7 @@ int LoLEngine::processMagicLightning(int charNum, int spellLevel) { char wsafile[13]; snprintf(wsafile, 13, "litning%d.wsa", spellLevel + 1); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); mov->open(wsafile, 1, 0); if (!mov->opened()) error("Litning: Unable to load litning.wsa"); @@ -2570,7 +2625,7 @@ int LoLEngine::processMagicFog() { int cp = _screen->setCurPage(2); _screen->copyPage(0, 12); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); int numFrames = mov->open("fog.wsa", 0, 0); if (!mov->opened()) error("Fog: Unable to load fog.wsa"); @@ -2646,7 +2701,7 @@ int LoLEngine::processMagicSwarm(int charNum, int damage) { _monsters[destIds[i]].fightCurTick = destTicks[i]; } - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); mov->open("swarm.wsa", 0, 0); if (!mov->opened()) @@ -2671,7 +2726,7 @@ int LoLEngine::processMagicSwarm(int charNum, int damage) { int LoLEngine::processMagicVaelansCube() { uint8 *tmpPal1 = new uint8[768]; uint8 *tmpPal2 = new uint8[768]; - uint8 *sp1 = _screen->getPalette(1); + uint8 *sp1 = _screen->getPalette(1).getData(); memcpy(tmpPal1, sp1, 768); memcpy(tmpPal2, sp1, 768); @@ -2734,7 +2789,7 @@ int LoLEngine::processMagicGuardian(int charNum) { _screen->copyPage(0, 2); _screen->copyPage(2, 12); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); mov->open("guardian.wsa", 0, 0); if (!mov->opened()) error("Guardian: Unable to load guardian.wsa"); @@ -2742,7 +2797,7 @@ int LoLEngine::processMagicGuardian(int charNum) { playSpellAnimation(mov, 0, 37, 2, 112, 0, 0, 0, 0, 0, false); _screen->copyPage(2, 12); - + uint16 bl = calcNewBlockPosition(_currentBlock, _currentDirection); int res = (_levelBlockProperties[bl].assignedObjects & 0x8000) ? 1 : 0; inflictMagicalDamageForBlock(bl, charNum, 200, 0x80); @@ -2754,7 +2809,7 @@ int LoLEngine::processMagicGuardian(int charNum) { _screen->copyPage(2, 12); snd_playSoundEffect(176, -1); playSpellAnimation(mov, 38, 48, 8, 112, 0, 0, 0, 0, 0, false); - + mov->close(); delete mov; @@ -2771,20 +2826,22 @@ void LoLEngine::callbackProcessMagicSwarm(WSAMovie_v2 *mov, int x, int y) { } void LoLEngine::callbackProcessMagicLightning(WSAMovie_v2 *mov, int x, int y) { - uint8 *tpal = new uint8[768]; if (_lightningDiv == 2) shakeScene(1, 2, 3, 0); - uint8 *p1 = _screen->getPalette(1); + const Palette &p1 = _screen->getPalette(1); if (_lightningSfxFrame % _lightningDiv) { _screen->setScreenPalette(p1); } else { - memcpy(tpal, p1, 768); + Palette tpal(p1.getNumColors()); + tpal.copy(p1); + for (int i = 6; i < 384; i++) { uint16 v = (tpal[i] * 120) / 64; tpal[i] = (v < 64) ? v : 63; } + _screen->setScreenPalette(tpal); } @@ -2799,7 +2856,55 @@ void LoLEngine::callbackProcessMagicLightning(WSAMovie_v2 *mov, int x, int y) { } _lightningSfxFrame++; - delete[] tpal; +} + +void LoLEngine::drinkBezelCup(int numUses, int charNum) { + int cp = _screen->setCurPage(2); + snd_playSoundEffect(73, -1); + + WSAMovie_v2 *mov = new WSAMovie_v2(this); + mov->open("bezel.wsa", 0, 0); + if (!mov->opened()) + error("Bezel: Unable to load bezel.wsa"); + + int x = _activeCharsXpos[charNum] - 11; + int y = 124; + int w = mov->width(); + int h = mov->height(); + + _screen->copyRegion(x, y, 0, 0, w, h, 0, 2, Screen::CR_NO_P_CHECK); + + static const uint8 bezelAnimData[] = { 0, 26, 20, 27, 61, 55, 62, 92, 86, 93, 131, 125 }; + int frm = bezelAnimData[numUses * 3]; + int hpDiff = _characters[charNum].hitPointsMax - _characters[charNum].hitPointsCur; + uint16 step = 0; + + do { + step = (step & 0xff) + (hpDiff * 256) / (bezelAnimData[numUses * 3 + 2]); + increaseCharacterHitpoints(charNum, step / 256, true); + gui_drawCharPortraitWithStats(charNum); + + uint32 etime = _system->getMillis() + 4 * _tickLength; + + _screen->copyRegion(0, 0, x, y, w, h, 2, 2, Screen::CR_NO_P_CHECK); + mov->displayFrame(frm, 2, x, y, 0x5000, _trueLightTable1, _trueLightTable2); + _screen->copyRegion(x, y, x, y, w, h, 2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + + delayUntil(etime); + } while (++frm < bezelAnimData[numUses * 3 + 1]); + + _characters[charNum].hitPointsCur = _characters[charNum].hitPointsMax; + _screen->copyRegion(0, 0, x, y, w, h, 2, 2, Screen::CR_NO_P_CHECK); + removeCharacterEffects(&_characters[charNum], 4, 4); + gui_drawCharPortraitWithStats(charNum); + _screen->copyRegion(x, y, x, y, w, h, 2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + + mov->close(); + delete mov; + + _screen->setCurPage(cp); } void LoLEngine::addSpellToScroll(int spell, int charNum) { @@ -2871,7 +2976,7 @@ void LoLEngine::transferSpellToScollAnimation(int charNum, int spell, int slot) snd_playSoundEffect(_updateSpellBookAnimData[(spell << 2) + 3], -1); snd_playSoundEffect(95, -1); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); mov->open("getspell.wsa", 0, 0); if (!mov->opened()) @@ -3282,6 +3387,52 @@ int LoLEngine::calcInflictableDamagePerItem(int16 attacker, int16 target, uint16 } void LoLEngine::checkForPartyDeath() { + Button b; + b.data0Val2 = b.data1Val2 = b.data2Val2 = 0xfe; + b.data0Val3 = b.data1Val3 = b.data2Val3 = 0x01; + + for (int i = 0; i < 4; i++) { + if (!(_characters[i].flags & 1) || _characters[i].hitPointsCur <= 0) + continue; + return; + } + + if (_weaponsDisabled) + clickedExitCharInventory(&b); + + gui_drawAllCharPortraitsWithStats(); + + if (_partyDamageFlags & 0x40) { + _screen->fadeToBlack(40); + for (int i = 0; i < 4; i++) { + if (_characters[i].flags & 1) + increaseCharacterHitpoints(i, 1, true); + } + gui_drawAllCharPortraitsWithStats(); + _screen->fadeToPalette1(40); + + } else { + _screen->fadeClearSceneWindow(10); + restoreAfterSpecialScene(0, 1, 1, 0); + + snd_playTrack(325); + updatePortraits(); + initTextFading(0, 1); + setMouseCursorToIcon(0); + _updateFlags |= 4; + setLampMode(true); + disableSysTimer(2); + + _gui->runMenu(_gui->_deathMenu); + + setMouseCursorToItemInHand(); + _updateFlags &= 0xfffb; + resetLampStatus(); + + gui_enableDefaultPlayfieldButtons(); + enableSysTimer(2); + updateDrawPage2(); + } } void LoLEngine::applyMonsterAttackSkill(MonsterInPlay *monster, int16 target, int16 damage) { @@ -3499,16 +3650,16 @@ void LoLEngine::restoreSwampPalette() { if (_currentLevel != 11) return; - uint8 *s = _screen->getPalette(2); - uint8 *d = _screen->_currentPalette; - uint8 *d2 = _screen->getPalette(1); + uint8 *s = _screen->getPalette(2).getData(); + uint8 *d = _screen->getPalette(0).getData(); + uint8 *d2 = _screen->getPalette(1).getData(); for (int i = 1; i < 768; i++) SWAP(s[i], d[i]); - generateBrightnessPalette(d, d2, _brightness, _lampEffect); - _screen->loadSpecialColors(s); - _screen->loadSpecialColors(d2); + generateBrightnessPalette(_screen->getPalette(0), _screen->getPalette(1), _brightness, _lampEffect); + _screen->loadSpecialColors(_screen->getPalette(2)); + _screen->loadSpecialColors(_screen->getPalette(1)); playSpellAnimation(0, 0, 0, 2, 0, 0, 0, s, d2, 40, 0); } @@ -3529,7 +3680,7 @@ void LoLEngine::launchMagicViper() { _screen->copyPage(0, 12); snd_playSoundEffect(148, -1); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); int numFrames = mov->open("viper.wsa", 1, 0); if (!mov->opened()) error("Viper: Unable to load viper.wsa"); @@ -3579,7 +3730,7 @@ void LoLEngine::breakIceWall(uint8 *pal1, uint8 *pal2) { gui_drawScene(2); _screen->copyPage(2, 10); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); int numFrames = mov->open("shatter.wsa", 1, 0); if (!mov->opened()) error("Shatter: Unable to load shatter.wsa"); @@ -3681,7 +3832,7 @@ void LoLEngine::displayAutomap() { uint8 *tmpWll = new uint8[80]; memcpy(tmpWll, _wllBuffer4, 80); - _screen->loadBitmap("parch.cps", 2, 2, _screen->getPalette(3)); + _screen->loadBitmap("parch.cps", 2, 2, &_screen->getPalette(3)); _screen->loadBitmap("autobut.shp", 3, 5, 0); const uint8 *shp = _screen->getCPagePtr(5); @@ -3848,12 +3999,17 @@ void LoLEngine::loadMapLegendData(int level) { } void LoLEngine::drawMapPage(int pageNum) { + // WORKAROUND for French version. The Text does not always properly fit the screen there. + int8 textOffset = (_lang == 1) ? -2 : 0; + for (int i = 0; i < 2; i++) { - _screen->loadBitmap("parch.cps", pageNum, pageNum, _screen->getPalette(3)); + _screen->loadBitmap("parch.cps", pageNum, pageNum, &_screen->getPalette(3)); + if (_lang == 1) + _screen->copyRegion(236, 16, 236 + textOffset, 16, -textOffset, 1, pageNum, pageNum, Screen::CR_NO_P_CHECK); int cp = _screen->setCurPage(pageNum); Screen::FontId of = _screen->setFont(Screen::FID_9_FNT); - _screen->printText(getLangString(_autoMapStrings[_currentMapLevel]), 236, 8, 1, 0); + _screen->printText(getLangString(_autoMapStrings[_currentMapLevel]), 236 + textOffset, 8, 1, 0); uint16 blX = mapGetStartPosX(); uint16 bl = (mapGetStartPosY() << 5) + blX; @@ -3932,7 +4088,7 @@ void LoLEngine::drawMapPage(int pageNum) { if (l[2] == 0xffff) continue; - printMapText(l[2], 244, (tY << 3) + 22); + printMapText(l[2], 244 + textOffset, (tY << 3) + 22); if (l[5] == 0xffff) { tY++; @@ -3942,7 +4098,7 @@ void LoLEngine::drawMapPage(int pageNum) { uint16 cbl2 = l[3] + (l[4] << 5); _levelBlockProperties[cbl2].flags |= 7; _screen->drawShape(2, _automapShapes[l[5] << 2], (l[3] - sx) * 7 + _automapTopLeftX - 3, (l[4] - sy) * 6 + _automapTopLeftY - 3, 0, 0); - _screen->drawShape(2, _automapShapes[l[5] << 2], 231, (tY << 3) + 19, 0, 0); + _screen->drawShape(2, _automapShapes[l[5] << 2], 231 + textOffset, (tY << 3) + 19, 0, 0); tY++; } @@ -3951,9 +4107,9 @@ void LoLEngine::drawMapPage(int pageNum) { for (int ii = 0; ii < 11; ii++) { if (!_defaultLegendData[ii].enable) continue; - _screen->copyBlockAndApplyOverlay(_screen->_curPage, 235, (tY << 3) + 21, _screen->_curPage, 235, (tY << 3) + 21, 7, 6, 0, _mapOverlay); - _screen->drawShape(_screen->_curPage, _automapShapes[_defaultLegendData[ii].shapeIndex << 2], 232, (tY << 3) + 18 + _defaultLegendData[ii].x, 0, 0); - printMapText(_defaultLegendData[ii].stringId, 244, (tY << 3) + 22); + _screen->copyBlockAndApplyOverlay(_screen->_curPage, 235, (tY << 3) + 21, _screen->_curPage, 235 + textOffset, (tY << 3) + 21, 7, 6, 0, _mapOverlay); + _screen->drawShape(_screen->_curPage, _automapShapes[_defaultLegendData[ii].shapeIndex << 2], 232 + textOffset, (tY << 3) + 18 + _defaultLegendData[ii].x, 0, 0); + printMapText(_defaultLegendData[ii].stringId, 244 + textOffset, (tY << 3) + 22); tY++; } diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index 45795a7cab..12000c31fa 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -307,6 +307,7 @@ public: Screen *screen(); GUI *gui() const; + private: Screen_LoL *_screen; GUI_LoL *_gui; @@ -326,6 +327,10 @@ private: void startup(); void startupNew(); + void registerDefaultSettings(); + void writeSettings(); + void readSettings(); + // options int _monsterDifficulty; bool _smoothScrollingEnabled; @@ -342,7 +347,9 @@ private: uint8 *getItemIconShapePtr(int index); bool posWithinRect(int mouseX, int mouseY, int x1, int y1, int x2, int y2); - int _floatingMouseArrowControl; + void checkFloatingPointerRegions(); + int _floatingCursorControl; + int _currentFloatingCursor; // intro + character selection int processPrologue(); @@ -441,6 +448,9 @@ private: int _timer3Para; // sound + int convertVolumeToMixer(int value); + int convertVolumeFromMixer(int value); + void loadTalkFile(int index); void snd_playVoiceFile(int track) {} bool snd_playCharacterSpeech(int id, int8 speaker, int); @@ -473,7 +483,6 @@ private: Common::List<Audio::AudioStream*> _speechList; int _curTlkFile; - int _speechFlag; char **_ingameSoundList; int _ingameSoundListSize; @@ -772,11 +781,12 @@ private: int olol_getNextActiveCharacter(EMCState *script); int olol_paralyzePoisonCharacter(EMCState *script); int olol_drawCharPortrait(EMCState *script); - int olol_removeInventoryItem(EMCState *script); + int olol_removeInventoryItem(EMCState *script); int olol_getAnimationLastPart(EMCState *script); int olol_assignSpecialGuiShape(EMCState *script); int olol_findInventoryItem(EMCState *script); int olol_restoreFadePalette(EMCState *script); + int olol_drinkBezelCup(EMCState *script); int olol_changeItemTypeOrFlag(EMCState *script); int olol_placeInventoryItemInHand(EMCState *script); int olol_castSpell(EMCState *script); @@ -862,9 +872,9 @@ private: void toggleSelectedCharacterFrame(bool mode); void fadeText(); void transformRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage); - void setPaletteBrightness(uint8 *palette, int brightness, int modifier); - void generateBrightnessPalette(uint8 *src, uint8 *dst, int brightness, int modifier); - void generateFlashPalette(uint8 *src, uint8 *dst, int colorFlags); + void setPaletteBrightness(const Palette &srcPal, int brightness, int modifier); + void generateBrightnessPalette(const Palette &src, Palette &dst, int brightness, int modifier); + void generateFlashPalette(const Palette &src, Palette &dst, int colorFlags); void updateSequenceBackgroundAnimations(); bool _dialogueField; @@ -905,7 +915,7 @@ private: void setCharacterMagicOrHitPoints(int charNum, int type, int points, int mode); void increaseExperience(int charNum, int skill, uint32 points); - void increaseCharacterHitpoints(int charNum, int points, bool unk); + void increaseCharacterHitpoints(int charNum, int points, bool ignoreDeath); LoLCharacter *_characters; uint16 _activeCharsXpos[3]; @@ -1303,7 +1313,6 @@ private: // misc void delay(uint32 millis, bool doUpdate = false, bool isMainLoop = false); - uint8 getRandomNumberSpecial(); uint8 _compassBroken; uint8 _drainMagic; @@ -1349,6 +1358,8 @@ private: void callbackProcessMagicSwarm(WSAMovie_v2 *mov, int x, int y); void callbackProcessMagicLightning(WSAMovie_v2 *mov, int x, int y); + void drinkBezelCup(int a, int charNum); + void addSpellToScroll(int spell, int charNum); void transferSpellToScollAnimation(int charNum, int spell, int slot); diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index 79665068f6..ecd6bbe450 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -29,6 +29,7 @@ #include "graphics/thumbnail.h" #include "kyra/kyra_v1.h" +#include "kyra/util.h" #define CURRENT_SAVE_VERSION 16 @@ -65,6 +66,8 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab in->read(descriptionBuffer, descriptionSize[i]); descriptionBuffer[descriptionSize[i]] = 0; + Util::convertDOSToISO(descriptionBuffer); + type = in->readUint32BE(); header.version = in->readUint16LE(); if (type == MKID_BE('MBL3') && header.version == 100) { diff --git a/engines/kyra/scene_hof.cpp b/engines/kyra/scene_hof.cpp index fed7877c0b..2d15af92fd 100644 --- a/engines/kyra/scene_hof.cpp +++ b/engines/kyra/scene_hof.cpp @@ -330,9 +330,6 @@ int KyraEngine_HoF::trySceneChange(int *moveTable, int unk1, int updateChar) { updateCharacterAnim(0); refreshAnimObjectsIfNeed(); - if (!changedScene && !_unk4) { - //XXX - } return changedScene; } @@ -396,14 +393,14 @@ void KyraEngine_HoF::unloadScene() { void KyraEngine_HoF::loadScenePal() { uint16 sceneId = _mainCharacter.sceneId; - memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); + _screen->copyPalette(1, 0); char filename[14]; strcpy(filename, _sceneList[sceneId].filename1); strcat(filename, ".COL"); _screen->loadBitmap(filename, 3, 3, 0); - memcpy(_screen->getPalette(1), _screen->getCPagePtr(3), 384); - memset(_screen->getPalette(1), 0, 3); + _screen->getPalette(1).copy(_screen->getCPagePtr(3), 0, 128); + _screen->getPalette(1).fill(0, 1, 0); memcpy(_scenePal, _screen->getCPagePtr(3)+336, 432); } @@ -669,7 +666,7 @@ void KyraEngine_HoF::initSceneScreen(int unk1) { } if (_noScriptEnter) { - memset(_screen->getPalette(0), 0, 384); + _screen->getPalette(0).fill(0, 128, 0); _screen->setScreenPalette(_screen->getPalette(0)); } @@ -677,7 +674,7 @@ void KyraEngine_HoF::initSceneScreen(int unk1) { if (_noScriptEnter) { _screen->setScreenPalette(_screen->getPalette(1)); - memcpy(_screen->getPalette(0), _screen->getPalette(1), 384); + _screen->getPalette(0).copy(_screen->getPalette(1), 0, 128); } updateCharPal(0); @@ -695,10 +692,7 @@ void KyraEngine_HoF::freeSceneShapePtrs() { } void KyraEngine_HoF::fadeScenePal(int srcIndex, int delayTime) { - uint8 *dst = _screen->getPalette(0) + 336; - const uint8 *src = _scenePal + (srcIndex << 4)*3; - memcpy(dst, src, 48); - + _screen->getPalette(0).copy(_scenePal, srcIndex << 4, 16, 112); _screen->fadePalette(_screen->getPalette(0), delayTime, &_updateFunctor); } diff --git a/engines/kyra/scene_lok.cpp b/engines/kyra/scene_lok.cpp index 345998e40e..fc1ca41189 100644 --- a/engines/kyra/scene_lok.cpp +++ b/engines/kyra/scene_lok.cpp @@ -406,7 +406,7 @@ void KyraEngine_LoK::startSceneScript(int brandonAlive) { _screen->clearPage(3); _res->exists(fileNameBuffer, true); // FIXME: check this hack for amiga version - _screen->loadBitmap(fileNameBuffer, 3, 3, (_flags.platform == Common::kPlatformAmiga ? _screen->getPalette(0) : 0)); + _screen->loadBitmap(fileNameBuffer, 3, 3, (_flags.platform == Common::kPlatformAmiga ? &_screen->getPalette(0) : 0)); _sprites->loadSceneShapes(); _exitListPtr = 0; @@ -770,7 +770,7 @@ void KyraEngine_LoK::initSceneObjectList(int brandonAlive) { void KyraEngine_LoK::initSceneScreen(int brandonAlive) { if (_flags.platform == Common::kPlatformAmiga) { if (_unkScreenVar1 && !queryGameFlag(0xF0)) { - memset(_screen->getPalette(2), 0, 32*3); + _screen->getPalette(2).clear(); if (_currentCharacter->sceneId != 117 || !queryGameFlag(0xB3)) _screen->setScreenPalette(_screen->getPalette(2)); } @@ -782,10 +782,10 @@ void KyraEngine_LoK::initSceneScreen(int brandonAlive) { if (_unkScreenVar1 && !queryGameFlag(0xA0)) { if (_currentCharacter->sceneId == 45 && _paletteChanged) - memcpy(_screen->getPalette(0) + 12*3, _screen->getPalette(4) + 12*3, 2); + _screen->getPalette(0).copy(_screen->getPalette(4), 12, 1); if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245 && (_brandonStatusBit & 1)) - memcpy(_screen->getPalette(0), _screen->getPalette(0) + 320*3, 64); + _screen->copyPalette(0, 10); _screen->setScreenPalette(_screen->getPalette(0)); } @@ -807,10 +807,10 @@ void KyraEngine_LoK::initSceneScreen(int brandonAlive) { if (_unkScreenVar1 && _paletteChanged) { if (!queryGameFlag(0xA0)) { - memcpy(_screen->getPalette(0) + 684, _screen->getPalette(1) + 684, 60); + _screen->getPalette(0).copy(_screen->getPalette(1), 228, 20); _screen->setScreenPalette(_screen->getPalette(0)); } else { - memset(_screen->getPalette(0), 0, 768); + _screen->getPalette(0).clear(); } } } diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp index 0236e4fa7d..945495517f 100644 --- a/engines/kyra/scene_lol.cpp +++ b/engines/kyra/scene_lol.cpp @@ -86,7 +86,7 @@ void LoLEngine::loadLevel(int index) { addLevelItems(); deleteMonstersFromBlock(_currentBlock); - _screen->generateGrayOverlay(_screen->_currentPalette, _screen->_grayOverlay, 32, 16, 0, 0, 128, true); + _screen->generateGrayOverlay(_screen->getPalette(0), _screen->_grayOverlay, 32, 16, 0, 0, 128, true); _sceneDefaultUpdate = 0; if (_screen->_fadeFlag == 3) @@ -94,7 +94,7 @@ void LoLEngine::loadLevel(int index) { gui_drawPlayField(); - setPaletteBrightness(_screen->_currentPalette, _brightness, _lampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); setMouseCursorToItemInHand(); snd_playTrack(_curMusicTheme); @@ -379,28 +379,24 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight v += 128; if (_lastOverridePalFilePtr) { - uint8 *tpal = _res->fileData(_lastOverridePalFilePtr, 0); - memcpy(_screen->_currentPalette, tpal, 384); - delete[] tpal; + _res->loadFileToBuf(_lastOverridePalFilePtr, _screen->getPalette(0).getData(), 384); } else { - memcpy(_screen->_currentPalette, v, 384); + _screen->getPalette(0).copy(v, 0, 128); } v += 384; /*uint8 tmpPal = new uint8[384]; - memcpy(tmpPal, _screen->_currentPalette + 384, 384); - memset(_screen->_currentPalette + 384, 0xff, 384); - memcpy(_screen->_currentPalette + 384, tmpPal, 384);*/ + memcpy(tmpPal, _screen->getPalette(0) + 384, 384); + memset(_screen->getPalette(0) + 384, 0xff, 384); + memcpy(_screen->getPalette(0) + 384, tmpPal, 384);*/ if (_currentLevel == 11) { - uint8 *swampPal = _res->fileData("SWAMPICE.COL", 0); - memcpy(_screen->getPalette(2), swampPal, 384); - memcpy(_screen->getPalette(2) + 384, _screen->_currentPalette + 384, 384); - delete[] swampPal; + _screen->loadPalette("SWAMPICE.COL", _screen->getPalette(2)); + _screen->getPalette(2).copy(_screen->getPalette(0), 128); if (_flagsTable[52] & 0x04) { - uint8 *pal0 = _screen->_currentPalette; - uint8 *pal2 = _screen->getPalette(2); + uint8 *pal0 = _screen->getPalette(0).getData(); + uint8 *pal2 = _screen->getPalette(2).getData(); for (int i = 1; i < 768; i++) SWAP(pal0[i], pal2[i]); } @@ -427,7 +423,7 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight for (int i = 0; i < 7; i++) { weight = 100 - (i * _lastSpecialColorWeight); weight = (weight > 0) ? (weight * 255) / 100 : 0; - _screen->generateLevelOverlay(_screen->_currentPalette, _screen->getLevelOverlay(i), _lastSpecialColor, weight); + _screen->generateLevelOverlay(_screen->getPalette(0), _screen->getLevelOverlay(i), _lastSpecialColor, weight); for (int ii = 0; ii < 128; ii++) { if (_screen->getLevelOverlay(i)[ii] == 255) @@ -442,7 +438,7 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight _screen->getLevelOverlay(7)[i] = i & 0xff; _loadSuppFilesFlag = 0; - generateBrightnessPalette(_screen->_currentPalette, _screen->getPalette(1), _brightness, _lampEffect); + generateBrightnessPalette(_screen->getPalette(0), _screen->getPalette(1), _brightness, _lampEffect); char tname[13]; snprintf(tname, sizeof(tname), "LEVEL%.02d.TLC", _currentLevel); @@ -548,14 +544,14 @@ void LoLEngine::updateLampStatus() { if (!_brightness || !_lampOilStatus) { newLampEffect = 8; if (newLampEffect != _lampEffect && _screen->_fadeFlag == 0) - setPaletteBrightness(_screen->_currentPalette, _brightness, newLampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, newLampEffect); } else { tmpOilStatus = (_lampOilStatus < 100) ? _lampOilStatus : 100; newLampEffect = (3 - ((tmpOilStatus - 1) / 25)) << 1; if (_lampEffect == -1) { if (_screen->_fadeFlag == 0) - setPaletteBrightness(_screen->_currentPalette, _brightness, newLampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, newLampEffect); _lampStatusTimer = _system->getMillis() + (10 + _rnd.getRandomNumberRng(1, 30)) * _tickLength; } else { if ((_lampEffect & 0xfe) == (newLampEffect & 0xfe)) { @@ -567,7 +563,7 @@ void LoLEngine::updateLampStatus() { } } else { if (_screen->_fadeFlag == 0) - setPaletteBrightness(_screen->_currentPalette, _lampEffect, newLampEffect); + setPaletteBrightness(_screen->getPalette(0), _lampEffect, newLampEffect); } } } @@ -604,7 +600,7 @@ void LoLEngine::updateCompass() { if (_compassStep) _compassStep -= (((ABS(_compassStep) >> 4) + 2) * dir); - int16 d = _compassBroken ? ((int8)getRandomNumberSpecial() - _compassDirection) : (_currentDirection << 6) - _compassDirection; + int16 d = _compassBroken ? (int8(_rnd.getRandomNumber(255)) - _compassDirection) : (_currentDirection << 6) - _compassDirection; if (d <= -128) d += 256; if (d >= 128) @@ -1261,8 +1257,8 @@ void LoLEngine::shakeScene(int duration, int width, int height, int restore) { while (endTime > _system->getMillis()) { uint32 delayTimer = _system->getMillis() + 2 * _tickLength; - int s1 = width ? (getRandomNumberSpecial() % (width << 1)) - width : 0; - int s2 = height ? (getRandomNumberSpecial() % (height << 1)) - height : 0; + int s1 = width ? (_rnd.getRandomNumber(255) % (width << 1)) - width : 0; + int s2 = height ? (_rnd.getRandomNumber(255) % (height << 1)) - height : 0; int x1, y1, x2, y2, w, h; if (s1 >= 0) { @@ -1308,11 +1304,11 @@ void LoLEngine::processGasExplosion(int soundId) { uint16 targetBlock = 0; int dist = getSpellTargetBlock(_currentBlock, _currentDirection, 3, targetBlock); - uint8 *p1 = _screen->getPalette(1); - uint8 *p2 = _screen->getPalette(3); + uint8 *p1 = _screen->getPalette(1).getData(); + uint8 *p2 = _screen->getPalette(3).getData(); if (dist) { - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); char file[13]; snprintf(file, 13, "gasexp%0d.wsa", dist); mov->open(file, 1, 0); @@ -1331,11 +1327,11 @@ void LoLEngine::processGasExplosion(int soundId) { p2[i * 3] = 0x3f; uint32 ctime = _system->getMillis(); - while (_screen->fadePaletteStep(_screen->_currentPalette, p2, _system->getMillis() - ctime, 10)) + while (_screen->fadePaletteStep(_screen->getPalette(0).getData(), p2, _system->getMillis() - ctime, 10)) updateInput(); ctime = _system->getMillis(); - while (_screen->fadePaletteStep(p2, _screen->_currentPalette, _system->getMillis() - ctime, 50)) + while (_screen->fadePaletteStep(p2, _screen->getPalette(0).getData(), _system->getMillis() - ctime, 50)) updateInput(); } @@ -1437,7 +1433,7 @@ void LoLEngine::prepareSpecialScene(int fieldType, int hasDialogue, int suspendG gui_disableControls(controlMode); if (fadeFlag) { - memcpy(_screen->getPalette(3) + 384, _screen->_currentPalette + 384, 384); + _screen->getPalette(3).copy(_screen->getPalette(0), 128); _screen->loadSpecialColors(_screen->getPalette(3)); _screen->fadePalette(_screen->getPalette(3), 10); _screen->_fadeFlag = 0; @@ -1495,7 +1491,7 @@ int LoLEngine::restoreAfterSpecialScene(int fadeFlag, int redrawPlayField, int r if (redrawPlayField) gui_drawPlayField(); - setPaletteBrightness(_screen->_currentPalette, _brightness, _lampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); } else { _currentControlMode = 0; @@ -1517,6 +1513,7 @@ void LoLEngine::setSequenceButtons(int x, int y, int w, int h, int enableFlags) _seqWindowY2 = y + h; int offs = _itemInHand ? 10 : 0; _screen->setMouseCursor(offs, offs, getItemIconShapePtr(_itemInHand)); + _currentFloatingCursor = -1; if (w == 320) { setLampMode(0); _lampStatusSuspended = true; diff --git a/engines/kyra/scene_mr.cpp b/engines/kyra/scene_mr.cpp index 07a7aa0d07..a68dcfb394 100644 --- a/engines/kyra/scene_mr.cpp +++ b/engines/kyra/scene_mr.cpp @@ -48,10 +48,8 @@ void KyraEngine_MR::enterNewScene(uint16 sceneId, int facing, int unk1, int unk2 } musicUpdate(0); - if (!unk3) { - //XXX + if (!unk3) musicUpdate(0); - } if (unk1) { int x = _mainCharacter.x1; @@ -88,7 +86,7 @@ void KyraEngine_MR::enterNewScene(uint16 sceneId, int facing, int unk1, int unk2 newSoundFile = true; } - //XXX + _chatAltFlag = false; if (!unk3) { _emc->init(&_sceneScriptState, &_sceneScriptData); @@ -328,25 +326,23 @@ void KyraEngine_MR::freeSceneShapes() { void KyraEngine_MR::loadScenePal() { char filename[16]; - memcpy(_screen->getPalette(2), _screen->getPalette(0), 768); + _screen->copyPalette(2, 0); strcpy(filename, _sceneList[_mainCharacter.sceneId].filename1); strcat(filename, ".COL"); _screen->loadBitmap(filename, 3, 3, 0); - memcpy(_screen->getPalette(2), _screen->getCPagePtr(3), 432); - memset(_screen->getPalette(2), 0, 3); + _screen->getPalette(2).copy(_screen->getCPagePtr(3), 0, 144); + _screen->getPalette(2).fill(0, 1, 0); for (int i = 144; i <= 167; ++i) { - uint8 *palette = _screen->getPalette(2) + i * 3; + uint8 *palette = _screen->getPalette(2).getData() + i * 3; palette[0] = palette[2] = 63; palette[1] = 0; } _screen->generateOverlay(_screen->getPalette(2), _paletteOverlay, 0xF0, 0x19); - uint8 *palette = _screen->getPalette(2) + 432; - const uint8 *costPal = _costPalBuffer + _characterShapeFile * 72; - memcpy(palette, costPal, 24*3); + _screen->getPalette(2).copy(_costPalBuffer, _characterShapeFile * 24, 24, 144); } void KyraEngine_MR::loadSceneMsc() { @@ -609,7 +605,7 @@ void KyraEngine_MR::initSceneScreen(int unk1) { } if (_noScriptEnter) { - memset(_screen->getPalette(0), 0, 432); + _screen->getPalette(0).fill(0, 144, 0); if (!_wasPlayingVQA) _screen->setScreenPalette(_screen->getPalette(0)); } @@ -619,7 +615,7 @@ void KyraEngine_MR::initSceneScreen(int unk1) { if (_noScriptEnter) { if (!_wasPlayingVQA) _screen->setScreenPalette(_screen->getPalette(2)); - memcpy(_screen->getPalette(0), _screen->getPalette(2), 432); + _screen->getPalette(0).copy(_screen->getPalette(2), 0, 144); if (_wasPlayingVQA) { _screen->fadeFromBlack(0x3C); _wasPlayingVQA = false; diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 2b3a9366e6..fa54bffa98 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -34,9 +34,15 @@ namespace Kyra { Screen::Screen(KyraEngine_v1 *vm, OSystem *system) - : _system(system), _vm(vm), _sjisInvisibleColor(0) { + : _system(system), _vm(vm), _sjisInvisibleColor(0), + _cursorColorKey((vm->gameFlags().gameID == GI_KYRA1) ? 0xFF : 0x00) { _debugEnabled = false; _maskMinY = _maskMaxY = -1; + + _drawShapeVar1 = 0; + _drawShapeVar3 = 1; + _drawShapeVar4 = 0; + _drawShapeVar5 = 0; } Screen::~Screen() { @@ -52,15 +58,13 @@ Screen::~Screen() { delete[] _sjisFontData; delete[] _sjisTempPage; - delete[] _currentPalette; - delete[] _screenPalette; + delete _screenPalette; + delete _internFadePalette; delete[] _decodeShapeBuffer; delete[] _animBlockPtr; - if (_vm->gameFlags().platform != Common::kPlatformAmiga) { - for (int i = 0; i < ARRAYSIZE(_palettes); ++i) - delete[] _palettes[i]; - } + for (uint i = 0; i < _palettes.size(); ++i) + delete _palettes[i]; CursorMan.popAllCursors(); } @@ -123,30 +127,38 @@ bool Screen::init() { memset(_shapePages, 0, sizeof(_shapePages)); - memset(_palettes, 0, sizeof(_palettes)); - _screenPalette = new uint8[768]; + const int paletteCount = (_vm->gameFlags().platform == Common::kPlatformAmiga) ? 12 : 4; + const int numColors = _use16ColorMode ? 16 : ((_vm->gameFlags().platform == Common::kPlatformAmiga) ? 32 : 256); + + _screenPalette = new Palette(numColors); assert(_screenPalette); - memset(_screenPalette, 0, 768); - if (_vm->gameFlags().platform == Common::kPlatformAmiga) { - _currentPalette = new uint8[1248]; - assert(_currentPalette); - memset(_currentPalette, 0, 1248); + _palettes.resize(paletteCount); + for (int i = 0; i < paletteCount; ++i) { + _palettes[i] = new Palette(numColors); + assert(_palettes[i]); + } - for (int i = 0; i < 6; ++i) - _palettes[i] = _currentPalette + (i+1)*96; - } else { - _currentPalette = new uint8[768]; - assert(_currentPalette); - memset(_currentPalette, 0, 768); - for (int i = 0; i < 3; ++i) { - _palettes[i] = new uint8[768]; - assert(_palettes[i]); - memset(_palettes[i], 0, 768); + _internFadePalette = new Palette(numColors); + assert(_internFadePalette); + + setScreenPalette(getPalette(0)); + + // We setup the PC98 text mode palette at [16, 24], since that will be used + // for KANJI characters in Lands of Lore. + if (_use16ColorMode && _vm->gameFlags().platform == Common::kPlatformPC98) { + uint8 palette[8 * 4]; + + for (int i = 0; i < 8; ++i) { + palette[i * 4 + 0] = ((i >> 1) & 1) * 0xFF; + palette[i * 4 + 1] = ((i >> 2) & 1) * 0xFF; + palette[i * 4 + 2] = ((i >> 0) & 1) * 0xFF; + palette[i * 4 + 3] = 0; + + _system->setPalette(palette, 16, 8); } } - setScreenPalette(_currentPalette); _curDim = 0; _charWidth = 0; _charOffset = 0; @@ -339,6 +351,148 @@ void Screen::clearCurPage() { clearOverlayPage(_curPage); } +void Screen::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); + uint8 *origDst = dstPtr; + + const ScreenDim *dim = getScreenDim(dimState); + int dimX1 = dim->sx << 3; + int dimX2 = dim->w << 3; + dimX2 += dimX1; + + int dimY1 = dim->sy; + int dimY2 = dim->h; + dimY2 += dimY1; + + int temp = y - dimY1; + if (temp < 0) { + if ((temp += h) <= 0) + return; + else { + SWAP(temp, h); + y += temp - h; + src += (temp - h) * w; + } + } + + temp = dimY2 - y; + if (temp <= 0) + return; + + if (temp < h) + h = temp; + + int srcOffset = 0; + temp = x - dimX1; + if (temp < 0) { + temp = -temp; + srcOffset = temp; + x += temp; + w -= temp; + } + + int srcAdd = 0; + + temp = dimX2 - x; + if (temp <= 0) + return; + + if (temp < w) { + SWAP(w, temp); + temp -= w; + srcAdd = temp; + } + + dstPtr += y * SCREEN_W + x; + uint8 *dst = dstPtr; + + if (_curPage == 0 || _curPage == 1) + addDirtyRect(x, y, w, h); + + clearOverlayRect(_curPage, x, y, w, h); + + temp = h; + int curY = y; + while (h--) { + src += srcOffset; + ++curY; + int cW = w; + + switch (plotFunc) { + case 0: + memcpy(dst, src, cW); + dst += cW; src += cW; + break; + + case 1: + while (cW--) { + uint8 d = *src++; + uint8 t = unkPtr1[d]; + if (t != 0xFF) + d = unkPtr2[*dst + (t << 8)]; + *dst++ = d; + } + break; + + case 4: + while (cW--) { + uint8 d = *src++; + if (d) + *dst = d; + ++dst; + } + break; + + case 5: + while (cW--) { + uint8 d = *src++; + if (d) { + uint8 t = unkPtr1[d]; + if (t != 0xFF) + d = unkPtr2[*dst + (t << 8)]; + *dst = d; + } + ++dst; + } + break; + + case 8: + case 9: + while (cW--) { + uint8 d = *src++; + uint8 t = _shapePages[0][dst - origDst] & 7; + if (unk1 < t && (curY > _maskMinY && curY < _maskMaxY)) + d = _shapePages[1][dst - origDst]; + *dst++ = d; + } + break; + + case 12: + case 13: + while (cW--) { + uint8 d = *src++; + if (d) { + uint8 t = _shapePages[0][dst - origDst] & 7; + if (unk1 < t && (curY > _maskMinY && curY < _maskMaxY)) + d = _shapePages[1][dst - origDst]; + *dst++ = d; + } else { + d = _shapePages[1][dst - origDst]; + *dst++ = d; + } + } + break; + + default: + break; + } + + dst = (dstPtr += SCREEN_W); + src += srcAdd; + } +} + uint8 Screen::getPagePixel(int pageNum, int x, int y) { assert(pageNum < SCREEN_PAGE_NUM); assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H); @@ -354,26 +508,25 @@ void Screen::setPagePixel(int pageNum, int x, int y, uint8 color) { } void Screen::fadeFromBlack(int delay, const UpdateFunctor *upFunc) { - fadePalette(_currentPalette, delay, upFunc); + fadePalette(getPalette(0), delay, upFunc); } void Screen::fadeToBlack(int delay, const UpdateFunctor *upFunc) { - uint8 blackPal[768]; - memset(blackPal, 0, 768); - fadePalette(blackPal, delay, upFunc); + Palette pal(getPalette(0).getNumColors()); + fadePalette(pal, delay, upFunc); } -void Screen::fadePalette(const uint8 *palData, int delay, const UpdateFunctor *upFunc) { +void Screen::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc) { updateScreen(); int diff = 0, delayInc = 0; - getFadeParams(palData, delay, delayInc, diff); + getFadeParams(pal, delay, delayInc, diff); int delayAcc = 0; while (!_vm->shouldQuit()) { delayAcc += delayInc; - int refreshed = fadePalStep(palData, diff); + int refreshed = fadePalStep(pal, diff); if (upFunc && upFunc->isValid()) (*upFunc)(); @@ -388,7 +541,7 @@ void Screen::fadePalette(const uint8 *palData, int delay, const UpdateFunctor *u } if (_vm->shouldQuit()) { - setScreenPalette(palData); + setScreenPalette(pal); if (upFunc && upFunc->isValid()) (*upFunc)(); else @@ -396,12 +549,11 @@ void Screen::fadePalette(const uint8 *palData, int delay, const UpdateFunctor *u } } -void Screen::getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff) { +void Screen::getFadeParams(const Palette &pal, int delay, int &delayInc, int &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]); + for (int i = 0; i < pal.getNumColors() * 3; ++i) { + diff = ABS(pal[i] - (*_screenPalette)[i]); maxDiff = MAX<uint8>(maxDiff, diff); } @@ -417,17 +569,14 @@ void Screen::getFadeParams(const uint8 *palette, int delay, int &delayInc, int & } } -int Screen::fadePalStep(const uint8 *palette, int diff) { - const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : (_use16ColorMode ? 16 : 256)) * 3; - - uint8 fadePal[768]; - memcpy(fadePal, _screenPalette, colors); +int Screen::fadePalStep(const Palette &pal, int diff) { + _internFadePalette->copy(*_screenPalette); bool needRefresh = false; - for (int i = 0; i < colors; ++i) { - int c1 = palette[i]; - int c2 = fadePal[i]; + for (int i = 0; i < pal.getNumColors() * 3; ++i) { + int c1 = pal[i]; + int c2 = (*_internFadePalette)[i]; if (c1 != c2) { needRefresh = true; if (c1 > c2) { @@ -442,26 +591,26 @@ int Screen::fadePalStep(const uint8 *palette, int diff) { c2 = c1; } - fadePal[i] = (uint8)c2; + (*_internFadePalette)[i] = (uint8)c2; } } if (needRefresh) - setScreenPalette(fadePal); + setScreenPalette(*_internFadePalette); return needRefresh ? 1 : 0; } void Screen::setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue) { - _currentPalette[index * 3 + 0] = red; - _currentPalette[index * 3 + 1] = green; - _currentPalette[index * 3 + 2] = blue; - setScreenPalette(_currentPalette); + getPalette(0)[index * 3 + 0] = red; + getPalette(0)[index * 3 + 1] = green; + getPalette(0)[index * 3 + 2] = blue; + setScreenPalette(getPalette(0)); } void Screen::getRealPalette(int num, uint8 *dst) { const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256); - const uint8 *palData = getPalette(num); + const uint8 *palData = getPalette(num).getData(); if (!palData) { memset(dst, 0, colors * 3); @@ -469,46 +618,26 @@ void Screen::getRealPalette(int num, uint8 *dst) { } for (int i = 0; i < colors; ++i) { - dst[0] = (palData[0] << 2) | (palData[0] & 3); - dst[1] = (palData[1] << 2) | (palData[1] & 3); - dst[2] = (palData[2] << 2) | (palData[2] & 3); + dst[0] = (palData[0] * 0xFF) / 0x3F; + dst[1] = (palData[1] * 0xFF) / 0x3F; + dst[2] = (palData[2] * 0xFF) / 0x3F; dst += 3; palData += 3; } } -void Screen::setScreenPalette(const uint8 *palData) { - const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256); - +void Screen::setScreenPalette(const Palette &pal) { uint8 screenPal[256 * 4]; - if (palData != _screenPalette) - memcpy(_screenPalette, palData, colors*3); + _screenPalette->copy(pal); - if (_use16ColorMode && _vm->gameFlags().platform == Common::kPlatformPC98) { - for (int l = 0; l < 1024; l += 64) { - const uint8 *tp = palData; - for (int i = 0; i < 16; ++i) { - screenPal[l + 4 * i + 0] = palData[1]; - screenPal[l + 4 * i + 1] = palData[0]; - screenPal[l + 4 * i + 2] = palData[2]; - screenPal[l + 4 * i + 3] = 0; - palData += 3; - } - palData = tp; - } - } else { - if (palData != _screenPalette) - memcpy(_screenPalette, palData, colors*3); - for (int i = 0; i < colors; ++i) { - screenPal[4 * i + 0] = (palData[0] << 2) | (palData[0] & 3); - screenPal[4 * i + 1] = (palData[1] << 2) | (palData[1] & 3); - screenPal[4 * i + 2] = (palData[2] << 2) | (palData[2] & 3); - screenPal[4 * i + 3] = 0; - palData += 3; - } + for (int i = 0; i < pal.getNumColors(); ++i) { + screenPal[4 * i + 0] = (pal[i * 3 + 0] * 0xFF) / 0x3F; + screenPal[4 * i + 1] = (pal[i * 3 + 1] * 0xFF) / 0x3F; + screenPal[4 * i + 2] = (pal[i * 3 + 2] * 0xFF) / 0x3F; + screenPal[4 * i + 3] = 0; } - _system->setPalette(screenPal, 0, colors); + _system->setPalette(screenPal, 0, pal.getNumColors()); } void Screen::copyToPage0(int y, int h, uint8 page, uint8 *seqBuf) { @@ -656,63 +785,6 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint } } -void Screen::copyFromCurPageBlock(int x, int y, int w, int h, const uint8 *src) { - if (x < 0) - x = 0; - else if (x >= 40) - return; - - if (x + w > 40) - w = 40 - x; - - if (y < 0) - y = 0; - else if (y >= 200) - return; - - if (y + h > 200) - h = 200 - y; - - uint8 *dst = getPagePtr(_curPage) + y * SCREEN_W + x * 8; - - if (_curPage == 0 || _curPage == 1) - addDirtyRect(x*8, y, w*8, h); - - clearOverlayRect(_curPage, x*8, y, w*8, h); - - while (h--) { - memcpy(dst, src, w*8); - dst += SCREEN_W; - src += w*8; - } -} - -void Screen::copyCurPageBlock(int x, int y, int w, int h, uint8 *dst) { - assert(dst); - if (x < 0) - x = 0; - else if (x >= 40) - return; - - if (x + w > 40) - w = 40 - x; - - if (y < 0) - y = 0; - else if (y >= 200) - return; - - if (y + h > 200) - h = 200 - y; - - const uint8 *src = getPagePtr(_curPage) + y * SCREEN_W + x * 8; - while (h--) { - memcpy(dst, src, w*8); - dst += w*8; - src += SCREEN_W; - } -} - void Screen::shuffleScreen(int sx, int sy, int w, int h, int srcPage, int dstPage, int ticks, bool transparent) { assert(sx >= 0 && w <= SCREEN_W); int x; @@ -802,17 +874,26 @@ void Screen::drawBox(int x1, int y1, int x2, int y2, int color) { drawClippedLine(x1, y2, x2, y2, color); } -void Screen::drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2) { +void Screen::drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2, ShadeType shadeType) { assert(x1 >= 0 && y1 >= 0); hideMouse(); fillRect(x1, y1, x2, y1 + 1, color1); - fillRect(x2 - 1, y1, x2, y2, color1); + if (shadeType == kShadeTypeLol) + fillRect(x1, y1, x1 + 1, y2, color1); + else + fillRect(x2 - 1, y1, x2, y2, color1); - drawClippedLine(x1, y1, x1, y2, color2); - drawClippedLine(x1 + 1, y1 + 1, x1 + 1, y2 - 1, color2); + if (shadeType == kShadeTypeLol) { + drawClippedLine(x2, y1, x2, y2, color2); + drawClippedLine(x2 - 1, y1 + 1, x2 - 1, y2 - 1, color2); + drawClippedLine(x1 + 1, y2 - 1, x2, y2 - 1, color2); + } else { + drawClippedLine(x1, y1, x1, y2, color2); + drawClippedLine(x1 + 1, y1 + 1, x1 + 1, y2 - 1, color2); + drawClippedLine(x1, y2 - 1, x2 - 1, y2 - 1, color2); + } drawClippedLine(x1, y2, x2, y2, color2); - drawClippedLine(x1, y2 - 1, x2 - 1, y2 - 1, color2); showMouse(); } @@ -909,11 +990,13 @@ bool Screen::loadFont(FontId fontId, const char *filename) { error("Invalid font data (file '%s', fontSig: %.04X)", filename, fontSig); fnt->charWidthTable = fontData + READ_LE_UINT16(fontData + 8); - fnt->charSizeOffset = READ_LE_UINT16(fontData + 4); + fnt->fontDescOffset = READ_LE_UINT16(fontData + 4); fnt->charBitmapOffset = READ_LE_UINT16(fontData + 6); fnt->charWidthTableOffset = READ_LE_UINT16(fontData + 8); fnt->charHeightTableOffset = READ_LE_UINT16(fontData + 0xC); + fnt->lastGlyph = *(fnt->fontData + fnt->fontDescOffset + 3); + return true; } @@ -927,23 +1010,30 @@ int Screen::getFontHeight() const { // FIXME: add font support for amiga version if (_vm->gameFlags().platform == Common::kPlatformAmiga) return 0; - return *(_fonts[_currentFont].fontData + _fonts[_currentFont].charSizeOffset + 4); + + return *(_fonts[_currentFont].fontData + _fonts[_currentFont].fontDescOffset + 4); } int Screen::getFontWidth() const { // FIXME: add font support for amiga version if (_vm->gameFlags().platform == Common::kPlatformAmiga) return 0; - return *(_fonts[_currentFont].fontData + _fonts[_currentFont].charSizeOffset + 5); + + return *(_fonts[_currentFont].fontData + _fonts[_currentFont].fontDescOffset + 5); } int Screen::getCharWidth(uint16 c) const { // FIXME: add font support for amiga version if (_vm->gameFlags().platform == Common::kPlatformAmiga) return 0; + if (c & 0xFF00) return SJIS_CHARSIZE >> 1; - return (int)_fonts[_currentFont].charWidthTable[c] + _charWidth; + + if (_fonts[_currentFont].lastGlyph < c) + return 0; + else + return (int)_fonts[_currentFont].charWidthTable[c] + _charWidth; } int Screen::getTextWidth(const char *str) const { @@ -986,8 +1076,7 @@ void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2 cmap[1] = color1; setTextColor(cmap, 0, 1); - Font *fnt = &_fonts[_currentFont]; - const uint8 charHeightFnt = *(fnt->fontData + fnt->charSizeOffset + 4); + const uint8 charHeightFnt = getFontHeight(); uint8 charHeight = 0; if (x < 0) @@ -1037,6 +1126,10 @@ void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2 void Screen::drawCharANSI(uint8 c, int x, int y) { Font *fnt = &_fonts[_currentFont]; + + if (c > fnt->lastGlyph) + return; + uint8 *dst = getPagePtr(_curPage) + y * SCREEN_W + x; uint16 bitmapOffset = READ_LE_UINT16(fnt->fontData + fnt->charBitmapOffset + c * 2); @@ -1044,15 +1137,16 @@ void Screen::drawCharANSI(uint8 c, int x, int y) { return; uint8 charWidth = *(fnt->fontData + fnt->charWidthTableOffset + c); - if (charWidth + x > SCREEN_W) + if (!charWidth || charWidth + x > SCREEN_W) return; - uint8 charH0 = *(fnt->fontData + fnt->charSizeOffset + 4); - if (charH0 + y > SCREEN_H) + uint8 charH0 = getFontHeight(); + if (!charH0 || charH0 + y > SCREEN_H) return; uint8 charH1 = *(fnt->fontData + fnt->charHeightTableOffset + c * 2); uint8 charH2 = *(fnt->fontData + fnt->charHeightTableOffset + c * 2 + 1); + charH0 -= charH1 + charH2; const uint8 *src = fnt->fontData + bitmapOffset; @@ -1097,15 +1191,17 @@ void Screen::drawCharANSI(uint8 c, int x, int y) { } if (_curPage == 0 || _curPage == 1) - addDirtyRect(x, y, charWidth, *(fnt->fontData + fnt->charSizeOffset + 4)); + addDirtyRect(x, y, charWidth, getFontHeight()); } void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...) { if (!shapeData) return; - int f = _vm->gameFlags().useAltShapeHeader ? 2 : 0; - if (shapeData[f] & 1) + if (_vm->gameFlags().useAltShapeHeader) + shapeData += 2; + + if (*shapeData & 1) flags |= 0x400; va_list args; @@ -1115,11 +1211,6 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int 1, 3, 2, 5, 4, 3, 2, 1 }; - _drawShapeVar1 = 0; - _drawShapeVar3 = 1; - _drawShapeVar4 = 0; - _drawShapeVar5 = 0; - _dsTable = 0; _dsTableLoopCount = 0; _dsTable2 = 0; @@ -1145,8 +1236,8 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int } if (flags & 0x200) { - _drawShapeVar1 += 1; - _drawShapeVar1 &= 7; + ++_drawShapeVar1; + _drawShapeVar1 &= (_vm->gameFlags().gameID == GI_KYRA1) ? 0x7 : 0xF; _drawShapeVar3 = drawShapeVar2[_drawShapeVar1]; _drawShapeVar4 = 0; _drawShapeVar5 = 256; @@ -1237,12 +1328,12 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int int scaleCounterV = 0; - f = flags & 0x0f; - _dsProcessMargin = dsMarginFunc[f]; - _dsScaleSkip = dsSkipFunc[f]; - _dsProcessLine = dsLineFunc[f]; + const int drawFunc = flags & 0x0f; + _dsProcessMargin = dsMarginFunc[drawFunc]; + _dsScaleSkip = dsSkipFunc[drawFunc]; + _dsProcessLine = dsLineFunc[drawFunc]; - int ppc = (flags >> 8) & 0x3F; + const int ppc = (flags >> 8) & 0x3F; _dsPlot = dsPlotFunc[ppc]; DsPlotFunc dsPlot2 = dsPlotFunc[ppc], dsPlot3 = dsPlotFunc[ppc]; if (flags & 0x800) @@ -1274,8 +1365,6 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int int y2 = y1 + dsDim->h; - if (_vm->gameFlags().useAltShapeHeader) - src += 2; uint16 shapeFlags = READ_LE_UINT16(src); src += 2; int shapeHeight = *src++; @@ -1318,8 +1407,6 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int int t = (flags & 2) ? y2 - y - shapeHeight : y - y1; - const uint8 *s = src; - if (t < 0) { shapeHeight += t; if (shapeHeight <= 0) { @@ -1328,23 +1415,29 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int } t *= -1; - uint8 *tmp = dst; + const uint8 *srcBackUp = 0; do { _dsOffscreenScaleVal1 = 0; + srcBackUp = src; _dsTmpWidth = shapeWidth; + int cnt = shapeWidth; - (this->*_dsScaleSkip)(tmp, s, cnt); + (this->*_dsScaleSkip)(dst, src, cnt); + scaleCounterV += _dsScaleH; - if (!(scaleCounterV & 0xff00)) - continue; - uint8 r = scaleCounterV >> 8; - scaleCounterV &= 0xff; - t -= r; - } while (t > 0); - - if (t < 0) + + if (scaleCounterV & 0xFF00) { + uint8 r = scaleCounterV >> 8; + scaleCounterV &= 0xFF; + t -= r; + } + } while (!(scaleCounterV & 0xFF00) && (t > 0)); + + if (t < 0) { + src = srcBackUp; scaleCounterV += (-t << 8); + } if (!(flags & 2)) y = y1; @@ -1409,6 +1502,9 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int _dsOffscreenLeft /= _dsScaleW; } + if (shapeHeight <= 0 || shpWidthScaled1 <= 0) + return; + if (pageNum == 0 || pageNum == 1) addDirtyRect(x, y, shpWidthScaled1, shapeHeight); clearOverlayRect(pageNum, x, y, shpWidthScaled1, shapeHeight); @@ -1422,28 +1518,28 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int if (!(scaleCounterV & 0xFF00)) { _dsTmpWidth = shapeWidth; int cnt = shapeWidth; - (this->*_dsScaleSkip)(d, s, cnt); + (this->*_dsScaleSkip)(d, src, cnt); } } - const uint8 *b_src = s; + const uint8 *b_src = src; do { - s = b_src; + src = b_src; _dsTmpWidth = shapeWidth; int cnt = _dsOffscreenLeft; - int scaleState = (this->*_dsProcessMargin)(d, s, cnt); + int scaleState = (this->*_dsProcessMargin)(d, src, cnt); if (_dsTmpWidth) { cnt += shpWidthScaled1; if (cnt > 0) { if (flags & 0x800) normalPlot = (curY > _maskMinY && curY < _maskMaxY); _dsPlot = normalPlot ? dsPlot2 : dsPlot3; - (this->*_dsProcessLine)(d, s, cnt, scaleState); + (this->*_dsProcessLine)(d, src, cnt, scaleState); } cnt += _dsOffscreenRight; if (cnt) - (this->*_dsScaleSkip)(d, s, cnt); + (this->*_dsScaleSkip)(d, src, cnt); } dst += dsPitch; d = dst; @@ -2492,9 +2588,14 @@ void Screen::hideMouse() { } void Screen::showMouse() { - if (_mouseLockCount == 1) + if (_mouseLockCount == 1) { CursorMan.showMouse(true); + // We need to call OSystem::updateScreen here, else the mouse cursor + // will only be visible on mouse movment. + _system->updateScreen(); + } + if (_mouseLockCount > 0) _mouseLockCount--; } @@ -2531,12 +2632,11 @@ void Screen::setMouseCursor(int x, int y, const byte *shape) { y <<= 1; mouseWidth <<= 1; mouseHeight <<= 1; - fillRect(mouseWidth, 0, mouseWidth, mouseHeight, 0, 8); } uint8 *cursor = new uint8[mouseHeight * mouseWidth]; - fillRect(0, 0, mouseWidth, mouseHeight, 0, 8); + fillRect(0, 0, mouseWidth, mouseHeight, _cursorColorKey, 8); drawShape(8, shape, 0, 0, 0, 0); int xOffset = 0; @@ -2544,11 +2644,14 @@ void Screen::setMouseCursor(int x, int y, const byte *shape) { if (_vm->gameFlags().useHiResOverlay) { xOffset = mouseWidth; scale2x(getPagePtr(8) + mouseWidth, SCREEN_W, getPagePtr(8), SCREEN_W, mouseWidth, mouseHeight); + postProcessCursor(getPagePtr(8) + mouseWidth, mouseWidth, mouseHeight, SCREEN_W); + } else { + postProcessCursor(getPagePtr(8), mouseWidth, mouseHeight, SCREEN_W); } CursorMan.showMouse(false); copyRegionToBuffer(8, xOffset, 0, mouseWidth, mouseHeight, cursor); - CursorMan.replaceCursor(cursor, mouseWidth, mouseHeight, x, y, 0); + CursorMan.replaceCursor(cursor, mouseWidth, mouseHeight, x, y, _cursorColorKey); if (isMouseVisible()) CursorMan.showMouse(true); delete[] cursor; @@ -2560,12 +2663,13 @@ void Screen::setMouseCursor(int x, int y, const byte *shape) { _system->updateScreen(); } -uint8 *Screen::getPalette(int num) { - assert(num >= 0 && num < (_vm->gameFlags().platform == Common::kPlatformAmiga ? 6 : 4)); - if (num == 0) - return _currentPalette; +Palette &Screen::getPalette(int num) { + assert(num >= 0 && (uint)num < _palettes.size()); + return *_palettes[num]; +} - return _palettes[num-1]; +void Screen::copyPalette(const int dst, const int src) { + getPalette(dst).copy(getPalette(src)); } byte Screen::getShapeFlag1(int x, int y) { @@ -2685,7 +2789,7 @@ void Screen::shakeScreen(int times) { } } -void Screen::loadBitmap(const char *filename, int tempPage, int dstPage, uint8 *palData, bool skip) { +void Screen::loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip) { uint32 fileSize; uint8 *srcData = _vm->resource()->fileData(filename, &fileSize); @@ -2702,9 +2806,8 @@ void Screen::loadBitmap(const char *filename, int tempPage, int dstPage, uint8 * uint32 imgSize = scumm_stricmp(ext, "CMP") ? READ_LE_UINT32(srcData + 4) : READ_LE_UINT16(srcData); uint16 palSize = READ_LE_UINT16(srcData + 8); - if (palData && palSize) { - loadPalette(srcData + 10, palData, palSize); - } + if (pal && palSize) + loadPalette(srcData + 10, *pal, palSize); uint8 *srcPtr = srcData + 10 + palSize; uint8 *dstData = getPagePtr(dstPage); @@ -2738,38 +2841,62 @@ void Screen::loadBitmap(const char *filename, int tempPage, int dstPage, uint8 * delete[] srcData; } -bool Screen::loadPalette(const char *filename, uint8 *palData) { - uint32 fileSize = 0; - uint8 *srcData = _vm->resource()->fileData(filename, &fileSize); - if (!srcData) +bool Screen::loadPalette(const char *filename, Palette &pal) { + Common::SeekableReadStream *stream = _vm->resource()->createReadStream(filename); + + if (!stream) return false; - if (palData && fileSize) { - loadPalette(srcData, palData, fileSize); - } - delete[] srcData; + debugC(3, kDebugLevelScreen, "Screen::loadPalette('%s', %p)", filename, (const void *)&pal); + + if (_vm->gameFlags().platform == Common::kPlatformAmiga) + pal.loadAmigaPalette(*stream, 0, stream->size() / Palette::kAmigaBytesPerColor); + else if (_vm->gameFlags().platform == Common::kPlatformPC98 && _use16ColorMode) + pal.loadPC98Palette(*stream, 0, stream->size() / Palette::kPC98BytesPerColor); + else + pal.loadVGAPalette(*stream, 0, stream->size() / Palette::kVGABytesPerColor); + + delete stream; return true; } -void Screen::loadPalette(const byte *data, uint8 *palData, int bytes) { +bool Screen::loadPaletteTable(const char *filename, int firstPalette) { + Common::SeekableReadStream *stream = _vm->resource()->createReadStream(filename); + + if (!stream) + return false; + + debugC(3, kDebugLevelScreen, "Screen::loadPaletteTable('%s', %d)", filename, firstPalette); + if (_vm->gameFlags().platform == Common::kPlatformAmiga) { - assert(bytes % 2 == 0); - assert(bytes / 2 <= 256); - bytes >>= 1; - const uint16 *src = (const uint16 *)data; - for (int i = 0; i < bytes; ++i) { - uint16 col = READ_BE_UINT16(src); ++src; - palData[2] = (col & 0xF) << 2; col >>= 4; - palData[1] = (col & 0xF) << 2; col >>= 4; - palData[0] = (col & 0xF) << 2; col >>= 4; - palData += 3; - } - } else if (_use16ColorMode) { - for (int i = 0; i < bytes; ++i) - palData[i] = ((data[i] & 0xF) << 4) | (data[i] & 0xF0); + const int numColors = getPalette(firstPalette).getNumColors(); + const int palSize = getPalette(firstPalette).getNumColors() * Palette::kAmigaBytesPerColor; + const int numPals = stream->size() / palSize; + + for (int i = 0; i < numPals; ++i) + getPalette(i + firstPalette).loadAmigaPalette(*stream, 0, numColors); } else { - memcpy(palData, data, bytes); + const int numColors = getPalette(firstPalette).getNumColors(); + const int palSize = getPalette(firstPalette).getNumColors() * Palette::kVGABytesPerColor; + const int numPals = stream->size() / palSize; + + for (int i = 0; i < numPals; ++i) + getPalette(i + firstPalette).loadVGAPalette(*stream, 0, numColors); } + + delete stream; + return true; +} + +void Screen::loadPalette(const byte *data, Palette &pal, int bytes) { + Common::MemoryReadStream stream(data, bytes, false); + + if (_vm->gameFlags().platform == Common::kPlatformAmiga) + pal.loadAmigaPalette(stream, 0, stream.size() / Palette::kAmigaBytesPerColor); + else if (_vm->gameFlags().platform == Common::kPlatformPC98 && _use16ColorMode) + pal.loadPC98Palette(stream, 0, stream.size() / Palette::kPC98BytesPerColor); + else + pal.loadVGAPalette(stream, 0, stream.size() / Palette::kVGABytesPerColor); } // dirty rect handling @@ -2967,8 +3094,17 @@ int SJIStoFMTChunk(int f, int s) { // copied from scumm\charset.cpp } // end of anonymous namespace void Screen::drawCharSJIS(uint16 c, int x, int y) { - int color1 = _textColorsMap[1]; - int color2 = _textColorsMap[0]; + int color1, color2; + + if (_use16ColorMode) { + // PC98 16 color games specify a color value which is for the + // PC98 text mode palette, thus we need to remap it. + color1 = ((_textColorsMap[1] >> 5) & 0x7) + 16; + color2 = ((_textColorsMap[0] >> 5) & 0x7) + 16; + } else { + color1 = _textColorsMap[1]; + color2 = _textColorsMap[0]; + } memset(_sjisTempPage2, _sjisInvisibleColor, 324); memset(_sjisSourceChar, 0, 36); @@ -3139,5 +3275,102 @@ void Screen::drawCharSJIS(uint16 c, int x, int y) { #pragma mark - +Palette::Palette(const int numColors) : _palData(0), _numColors(numColors) { + _palData = new uint8[numColors * 3]; + assert(_palData); + + memset(_palData, 0, numColors * 3); +} + +Palette::~Palette() { + delete[] _palData; + _palData = 0; +} + +void Palette::loadVGAPalette(Common::ReadStream &stream, int startIndex, int colors) { + assert(startIndex + colors <= _numColors); + + stream.read(_palData + startIndex * 3, colors * 3); +} + +void Palette::loadAmigaPalette(Common::ReadStream &stream, int startIndex, int colors) { + assert(startIndex + colors <= _numColors); + + for (int i = 0; i < colors; ++i) { + uint16 col = stream.readUint16BE(); + _palData[(i + startIndex) * 3 + 2] = ((col & 0xF) * 0xFF) / 0x3F; col >>= 4; + _palData[(i + startIndex) * 3 + 1] = ((col & 0xF) * 0xFF) / 0x3F; col >>= 4; + _palData[(i + startIndex) * 3 + 0] = ((col & 0xF) * 0xFF) / 0x3F; col >>= 4; + } +} + +void Palette::loadPC98Palette(Common::ReadStream &stream, int startIndex, int colors) { + assert(startIndex + colors <= _numColors); + + for (int i = 0; i < colors; ++i) { + const byte g = stream.readByte(), r = stream.readByte(), b = stream.readByte(); + + _palData[(i + startIndex) * 3 + 0] = ((r & 0x0F) * 0x3F) / 0x0F; + _palData[(i + startIndex) * 3 + 1] = ((g & 0x0F) * 0x3F) / 0x0F; + _palData[(i + startIndex) * 3 + 2] = ((b & 0x0F) * 0x3F) / 0x0F; + } +} + +void Palette::clear() { + memset(_palData, 0, _numColors * 3); +} + +void Palette::fill(int firstCol, int numCols, uint8 value) { + assert(firstCol >= 0 && firstCol + numCols <= _numColors); + + memset(_palData + firstCol * 3, CLIP<int>(value, 0, 63), numCols * 3); +} + +void Palette::copy(const Palette &source, int firstCol, int numCols, int dstStart) { + if (numCols == -1) + numCols = MIN(source.getNumColors(), _numColors) - firstCol; + if (dstStart == -1) + dstStart = firstCol; + + assert(numCols >= 0 && numCols <= _numColors); + assert(firstCol >= 0 && firstCol <= source.getNumColors()); + assert(dstStart >= 0 && dstStart + numCols <= _numColors); + + memcpy(_palData + dstStart * 3, source._palData + firstCol * 3, numCols * 3); +} + +void Palette::copy(const uint8 *source, int firstCol, int numCols, int dstStart) { + if (source == _palData) + return; + + if (dstStart == -1) + dstStart = firstCol; + + assert(numCols >= 0 && numCols <= _numColors); + assert(firstCol >= 0); + assert(dstStart >= 0 && dstStart + numCols <= _numColors); + + memcpy(_palData + dstStart * 3, source + firstCol * 3, numCols * 3); +} + +uint8 *Palette::fetchRealPalette() const { + uint8 *buffer = new uint8[_numColors * 3]; + assert(buffer); + + uint8 *dst = buffer; + const uint8 *palData = _palData; + + for (int i = 0; i < _numColors; ++i) { + dst[0] = (palData[0] << 2) | (palData[0] & 3); + dst[1] = (palData[1] << 2) | (palData[1] & 3); + dst[2] = (palData[2] << 2) | (palData[2] & 3); + + dst += 3; + palData += 3; + } + + return buffer; +} + } // End of namespace Kyra diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index 1691c73a90..390d058bb8 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -29,7 +29,9 @@ #include "common/util.h" #include "common/func.h" #include "common/list.h" +#include "common/array.h" #include "common/rect.h" +#include "common/stream.h" class OSystem; @@ -53,10 +55,112 @@ struct ScreenDim { struct Font { uint8 *fontData; uint8 *charWidthTable; - uint16 charSizeOffset; + uint16 fontDescOffset; uint16 charBitmapOffset; uint16 charWidthTableOffset; uint16 charHeightTableOffset; + + uint8 lastGlyph; +}; + +/** + * A class that manages KYRA palettes. + * + * This class stores the palette data as VGA RGB internally. + */ +class Palette { +public: + Palette(const int numColors); + ~Palette(); + + enum { + kVGABytesPerColor = 3, + kPC98BytesPerColor = 3, + kAmigaBytesPerColor = 2 + }; + + /** + * Load a VGA palette from the given stream. + */ + void loadVGAPalette(Common::ReadStream &stream, int startIndex, int colors); + + /** + * Load a AMIGA palette from the given stream. + */ + void loadAmigaPalette(Common::ReadStream &stream, int startIndex, int colors); + + /** + * Load a PC98 16 color palette from the given stream. + */ + void loadPC98Palette(Common::ReadStream &stream, int startIndex, int colors); + + /** + * Return the number of colors this palette manages. + */ + int getNumColors() const { return _numColors; } + + /** + * Set all palette colors to black. + */ + void clear(); + + /** + * Fill the given indexes with the given component value. + * + * @param firstCol the first color, which should be overwritten. + * @param numCols number of colors, which schould be overwritten. + * @param value color component value, which should be stored. + */ + void fill(int firstCol, int numCols, uint8 value); + + /** + * Copy data from another palette. + * + * @param source palette to copy data from. + * @param firstCol the first color of the source which should be copied. + * @param numCols number of colors, which should be copied. -1 all remaining colors. + * @param dstStart the first color, which should be ovewritten. If -1 firstCol will be used as start. + */ + void copy(const Palette &source, int firstCol = 0, int numCols = -1, int dstStart = -1); + + /** + * Copy data from a raw VGA palette. + * + * @param source source buffer + * @param firstCol the first color of the source which should be copied. + * @param numCols number of colors, which should be copied. + * @param dstStart the first color, which should be ovewritten. If -1 firstCol will be used as start. + */ + void copy(const uint8 *source, int firstCol, int numCols, int dstStart = -1); + + /** + * Fetch a RGB palette. + * + * @return a pointer to the RGB palette data, the client must delete[] it. + */ + uint8 *fetchRealPalette() const; + + //XXX + uint8 &operator[](const int index) { + assert(index >= 0 && index <= _numColors * 3); + return _palData[index]; + } + + const uint8 &operator[](const int index) const { + assert(index >= 0 && index <= _numColors * 3); + return _palData[index]; + } + + /** + * Gets raw access to the palette. + * + * TODO: Get rid of this. + */ + uint8 *getData() { return _palData; } + const uint8 *getData() const { return _palData; } +private: + uint8 *_palData; + const int _numColors; }; class Screen { @@ -110,12 +214,11 @@ public: // page cur. functions int setCurPage(int pageNum); - - void copyFromCurPageBlock(int x, int y, int w, int h, const uint8 *src); - void copyCurPageBlock(int x, int y, int w, int h, uint8 *dst); - void clearCurPage(); + 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); + // page 0 functions void copyToPage0(int y, int h, uint8 page, uint8 *seqBuf); void shakeScreen(int times); @@ -142,21 +245,25 @@ public: void fadeFromBlack(int delay=0x54, const UpdateFunctor *upFunc = 0); 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); + virtual void fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc = 0); + virtual void getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff); + virtual int fadePalStep(const Palette &pal, int diff); void setPaletteIndex(uint8 index, uint8 red, uint8 green, uint8 blue); - void setScreenPalette(const uint8 *palData); - const uint8 *getScreenPalette() const { return _screenPalette; } + virtual void setScreenPalette(const Palette &pal); void getRealPalette(int num, uint8 *dst); - uint8 *getPalette(int num); + Palette &getPalette(int num); + void copyPalette(const int dst, const int src); // gui specific (processing on _curPage) + enum ShadeType { + kShadeTypeKyra, + kShadeTypeLol + }; void drawLine(bool vertical, int x, int y, int length, int color); void drawClippedLine(int x1, int y1, int x2, int y2, int color); - void drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2); + void drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2, ShadeType shadeType = kShadeTypeKyra); void drawBox(int x1, int y1, int x2, int y2, int color); // font/text handling @@ -199,10 +306,11 @@ public: void rectClip(int &x, int &y, int w, int h); // misc - void loadBitmap(const char *filename, int tempPage, int dstPage, uint8 *palData, bool skip=false); + void loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip=false); - bool loadPalette(const char *filename, uint8 *palData); - void loadPalette(const byte *data, uint8 *palData, int bytes); + bool loadPalette(const char *filename, Palette &pal); + bool loadPaletteTable(const char *filename, int firstPalette); + void loadPalette(const byte *data, Palette &pal, int bytes); void setAnimBlockPtr(int size); @@ -220,7 +328,6 @@ public: int _charWidth; int _charOffset; int _curPage; - uint8 *_currentPalette; uint8 *_shapePages[2]; int _maskMinY, _maskMaxY; FontId _currentFont; @@ -231,6 +338,7 @@ public: static uint decodeFrame4(const uint8 *src, uint8 *dst, uint32 dstSize); static void decodeFrameDelta(uint8 *dst, const uint8 *src, bool noXor = false); static void decodeFrameDeltaPage(uint8 *dst, const uint8 *src, const int pitch, bool noXor); + static void convertAmigaGfx(uint8 *data, int w, int h, bool offscreen = true); static void convertAmigaMsc(uint8 *data); @@ -240,7 +348,7 @@ protected: void updateDirtyRectsOvl(); void scale2x(byte *dst, int dstPitch, const byte *src, int srcPitch, int w, int h); - void mergeOverlay(int x, int y, int w, int h); + virtual void mergeOverlay(int x, int y, int w, int h); // overlay specific byte *getOverlayPtr(int pageNum); @@ -275,8 +383,9 @@ protected: uint8 *_sjisSourceChar; uint8 _sjisInvisibleColor; - uint8 *_screenPalette; - uint8 *_palettes[6]; + Palette *_screenPalette; + Common::Array<Palette *> _palettes; + Palette *_internFadePalette; Font _fonts[FID_NUM]; uint8 _textColorsMap[16]; @@ -287,7 +396,11 @@ protected: uint8 *_animBlockPtr; int _animBlockSize; + // mouse handling int _mouseLockCount; + const uint8 _cursorColorKey; + + virtual void postProcessCursor(uint8 *data, int w, int h, int pitch) {}; enum { kMaxDirtyRects = 50 diff --git a/engines/kyra/screen_hof.cpp b/engines/kyra/screen_hof.cpp index 206f8beb87..516cb5bc41 100644 --- a/engines/kyra/screen_hof.cpp +++ b/engines/kyra/screen_hof.cpp @@ -44,8 +44,8 @@ const ScreenDim *Screen_HoF::getScreenDim(int dim) { return &_screenDimTable[dim]; } -void Screen_HoF::generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag) { - uint8 tmpPal[768]; +void Screen_HoF::generateGrayOverlay(const Palette &srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag) { + Palette tmpPal(lastColor); for (int i = 0; i != lastColor; i++) { if (flag) { @@ -63,7 +63,7 @@ void Screen_HoF::generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, in } for (int i = 0; i < lastColor; i++) - grayOverlay[i] = findLeastDifferentColor(tmpPal + 3 * i, srcPal, lastColor); + grayOverlay[i] = findLeastDifferentColor(tmpPal.getData() + 3 * i, srcPal, 0, lastColor); } void Screen_HoF::cmpFadeFrameStep(int srcPage, int srcW, int srcH, int srcX, int srcY, int dstPage, int dstW, diff --git a/engines/kyra/screen_hof.h b/engines/kyra/screen_hof.h index 088e8b7f55..1c17a424b3 100644 --- a/engines/kyra/screen_hof.h +++ b/engines/kyra/screen_hof.h @@ -41,7 +41,7 @@ public: const ScreenDim *getScreenDim(int dim); // sequence player - void generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag); + void generateGrayOverlay(const Palette &pal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag); void cmpFadeFrameStep(int srcPage, int srcW, int srcH, int srcX, int srcY, int dstPage, int dstW, int dstH, int dstX, int dstY, int cmpW, int cmpH, int cmpPage); void copyPageMemory(int srcPage, int srcPos, int dstPage, int dstPos, int numBytes); void copyRegionEx(int srcPage, int srcW, int srcH, int dstPage, int dstX,int dstY, int dstW, int dstH, const ScreenDim *d, bool flag = false); diff --git a/engines/kyra/screen_lok.cpp b/engines/kyra/screen_lok.cpp index 6d97db2f28..9fdeae1398 100644 --- a/engines/kyra/screen_lok.cpp +++ b/engines/kyra/screen_lok.cpp @@ -26,8 +26,9 @@ #include "kyra/kyra_lok.h" #include "kyra/screen_lok.h" -namespace Kyra { +#include "graphics/cursorman.h" +namespace Kyra { Screen_LoK::Screen_LoK(KyraEngine_LoK *vm, OSystem *system) : Screen(vm, system) { @@ -80,13 +81,15 @@ const ScreenDim *Screen_LoK::getScreenDim(int dim) { void Screen_LoK::fadeSpecialPalette(int palIndex, int startIndex, int size, int fadeTime) { assert(_vm->palTable1()[palIndex]); - assert(_currentPalette); - uint8 tempPal[768]; - memcpy(tempPal, _currentPalette, 768); - memcpy(&tempPal[startIndex*3], _vm->palTable1()[palIndex], size*3); + + Palette tempPal(getPalette(0).getNumColors()); + tempPal.copy(getPalette(0)); + tempPal.copy(_vm->palTable1()[palIndex], 0, size, startIndex); + fadePalette(tempPal, fadeTime*18); - memcpy(&_currentPalette[startIndex*3], &tempPal[startIndex*3], size*3); - setScreenPalette(_currentPalette); + + getPalette(0).copy(tempPal, startIndex, size); + setScreenPalette(getPalette(0)); _system->updateScreen(); } @@ -237,4 +240,200 @@ int Screen_LoK::getRectSize(int x, int y) { return ((x*y) << 3); } +#pragma mark - + +Screen_LoK_16::Screen_LoK_16(KyraEngine_LoK *vm, OSystem *system) : Screen_LoK(vm, system) { + memset(_paletteDither, 0, sizeof(_paletteDither)); +} + +void Screen_LoK_16::setScreenPalette(const Palette &pal) { + _screenPalette->copy(pal); + + for (int i = 0; i < 256; ++i) + paletteMap(i, pal[i * 3 + 0] << 2, pal[i * 3 + 1] << 2, pal[i * 3 + 2] << 2); + + set16ColorPalette(_palette16); +} + +void Screen_LoK_16::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc) { + uint8 notBlackFlag = 0; + for (int i = 0; i < 768; ++i) { + if ((*_screenPalette)[i]) + notBlackFlag |= 1; + if (pal[i]) + notBlackFlag |= 2; + } + + if (notBlackFlag == 1 || notBlackFlag == 2) { + bool upFade = false; + + for (int i = 0; i < 768; ++i) { + if ((*_screenPalette)[i] < pal[i]) { + upFade = true; + break; + } + } + + if (upFade) { + for (int i = 0; i < 256; ++i) + paletteMap(i, pal[i * 3 + 0] << 2, pal[i * 3 + 1] << 2, pal[i * 3 + 2] << 2); + _forceFullUpdate = true; + } + + uint8 color16Palette[16 * 3]; + + if (upFade) + memset(color16Palette, 0, sizeof(color16Palette)); + else + memcpy(color16Palette, _palette16, sizeof(color16Palette)); + + set16ColorPalette(color16Palette); + updateScreen(); + + for (int i = 0; i < 16; ++i) { + set16ColorPalette(color16Palette); + + for (int k = 0; k < 48; ++k) { + if (upFade) { + if (color16Palette[k] < _palette16[k]) + ++color16Palette[k]; + } else { + if (color16Palette[k] > 0) + --color16Palette[k]; + } + } + + if (upFunc && upFunc->isValid()) + (*upFunc)(); + else + _system->updateScreen(); + + _vm->delay((delay >> 5) * _vm->tickLength()); + } + } + + setScreenPalette(pal); +} + +void Screen_LoK_16::getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff) { + error("Screen_LoK_16::getFadeParams called"); +} + +int Screen_LoK_16::fadePalStep(const Palette &pal, int diff) { + error("Screen_LoK_16::fadePalStep called"); + return 0; +} + +void Screen_LoK_16::paletteMap(uint8 idx, int r, int g, int b) { + const int red = r; + const int green = g; + const int blue = b; + + uint16 rgbDiff = 1000; + int rDiff = 0, gDiff = 0, bDiff = 0; + + int index1 = -1; + + for (int i = 0; i < 16; ++i) { + const int realR = _palette16[i * 3 + 0] << 4; + const int realG = _palette16[i * 3 + 1] << 4; + const int realB = _palette16[i * 3 + 2] << 4; + + uint16 diff = ABS(r - realR) + ABS(g - realG) + ABS(b - realB); + + if (diff < rgbDiff) { + rgbDiff = diff; + index1 = i; + + rDiff = r - realR; + gDiff = g - realG; + bDiff = b - realB; + } + } + + r = rDiff / 4 + red; + g = gDiff / 4 + green; + b = bDiff / 4 + blue; + + rgbDiff = 1000; + int index2 = -1; + + for (int i = 0; i < 16; ++i) { + const int realR = _palette16[i * 3 + 0] << 4; + const int realG = _palette16[i * 3 + 1] << 4; + const int realB = _palette16[i * 3 + 2] << 4; + + uint16 diff = ABS(r - realR) + ABS(g - realG) + ABS(b - realB); + + if (diff < rgbDiff) { + rgbDiff = diff; + index2 = i; + } + } + + _paletteDither[idx].bestMatch = index1; + _paletteDither[idx].invertMatch = index2; +} + +void Screen_LoK_16::convertTo16Colors(uint8 *page, int w, int h, int pitch, int keyColor) { + const int rowAdd = pitch * 2 - w; + + uint8 *row1 = page; + uint8 *row2 = page + pitch; + + for (int i = 0; i < h; i += 2) { + for (int k = 0; k < w; k += 2) { + if (keyColor == -1 || keyColor != *row1) { + const PaletteDither &dither = _paletteDither[*row1]; + + *row1++ = dither.bestMatch; + *row1++ = dither.invertMatch; + *row2++ = dither.invertMatch; + *row2++ = dither.bestMatch; + } else { + row1 += 2; + row2 += 2; + } + } + + row1 += rowAdd; + row2 += rowAdd; + } +} + +void Screen_LoK_16::mergeOverlay(int x, int y, int w, int h) { + byte *dst = _sjisOverlayPtrs[0] + y * 640 + x; + + // We do a game screen rect to 16 color dithering here. It is + // important that we do not dither the overlay, since else the + // japanese fonts will look wrong. + convertTo16Colors(dst, w, h, 640); + + const byte *src = _sjisOverlayPtrs[1] + y * 640 + x; + + int add = 640 - w; + + while (h--) { + for (x = 0; x < w; ++x, ++dst) { + byte col = *src++; + if (col != _sjisInvisibleColor) + *dst = _paletteDither[col].bestMatch; + } + dst += add; + src += add; + } +} + +void Screen_LoK_16::set16ColorPalette(const uint8 *pal) { + uint8 palette[16 * 4]; + for (int i = 0; i < 16; ++i) { + palette[i * 4 + 0] = (pal[i * 3 + 0] * 0xFF) / 0x0F; + palette[i * 4 + 1] = (pal[i * 3 + 1] * 0xFF) / 0x0F; + palette[i * 4 + 2] = (pal[i * 3 + 2] * 0xFF) / 0x0F; + palette[i * 4 + 3] = 0; + } + + _system->setPalette(palette, 0, 16); +} + } // end of namespace Kyra diff --git a/engines/kyra/screen_lok.h b/engines/kyra/screen_lok.h index d74da66df5..4eb22df374 100644 --- a/engines/kyra/screen_lok.h +++ b/engines/kyra/screen_lok.h @@ -77,6 +77,38 @@ protected: uint8 *_saveLoadPageOvl[8]; }; +class Screen_LoK_16 : public Screen_LoK { +public: + Screen_LoK_16(KyraEngine_LoK *vm, OSystem *system); + + void setScreenPalette(const Palette &pal); + + void fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc = 0); + void getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff); + int fadePalStep(const Palette &pal, int diff); +private: + void updateDirtyRectsOvl(); + + void convertTo16Colors(uint8 *page, int w, int h, int pitch, int keyColor = -1); + void postProcessCursor(uint8 *data, int width, int height, int pitch) { + convertTo16Colors(data, width, height, pitch, _cursorColorKey); + } + void mergeOverlay(int x, int y, int w, int h); + + void set16ColorPalette(const uint8 *pal); + + void paletteMap(uint8 idx, int r, int g, int b); + + struct PaletteDither { + uint8 bestMatch; + uint8 invertMatch; + }; + + PaletteDither _paletteDither[256]; + + static const uint8 _palette16[48]; +}; + } // end of namespace Kyra #endif diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp index 3f3aef72fe..b9bf9961c5 100644 --- a/engines/kyra/screen_lol.cpp +++ b/engines/kyra/screen_lol.cpp @@ -105,7 +105,7 @@ void Screen_LoL::fprintString(const char *format, int x, int y, uint8 col1, uint va_end(vaList); if (flags & 1) - x -= getTextWidth(string) >> 1; + x -= (getTextWidth(string) >> 1); if (flags & 2) x -= getTextWidth(string); @@ -144,8 +144,8 @@ void Screen_LoL::fprintStringIntro(const char *format, int x, int y, uint8 c1, u printText(buffer, x, y, c1, c2); } -void Screen_LoL::generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors) { - uint8 tmpPal[768]; +void Screen_LoL::generateGrayOverlay(const Palette &srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors) { + Palette tmpPal(lastColor); for (int i = 0; i != lastColor; i++) { int v = (((srcPal[3 * i] & 0x3f) * factor) / 0x40) + addR; @@ -157,11 +157,11 @@ void Screen_LoL::generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, in } for (int i = 0; i < lastColor; i++) - grayOverlay[i] = findLeastDifferentColor(tmpPal + 3 * i, srcPal, lastColor, skipSpecialColors); + grayOverlay[i] = findLeastDifferentColor(tmpPal.getData() + 3 * i, srcPal, 0, lastColor, skipSpecialColors); } -uint8 *Screen_LoL::generateLevelOverlay(const uint8 *srcPal, uint8 *ovl, int opColor, int weight) { - if (!srcPal || !ovl) +uint8 *Screen_LoL::generateLevelOverlay(const Palette &srcPal, uint8 *ovl, int opColor, int weight) { + if (!ovl) return ovl; if (weight > 255) @@ -186,7 +186,7 @@ uint8 *Screen_LoL::generateLevelOverlay(const uint8 *srcPal, uint8 *ovl, int opC int m = 0x7fff; int ii = 127; int x = 1; - const uint8 *s = srcPal + 3; + const uint8 *s = srcPal.getData() + 3; do { if (i == x) { @@ -282,14 +282,13 @@ void Screen_LoL::fadeClearSceneWindow(int delay) { if (_fadeFlag == 1) return; - uint8 *tpal = new uint8[768]; + Palette tpal(getPalette(0).getNumColors()); + tpal.copy(getPalette(0), 128); - memcpy(tpal, _currentPalette, 768); - memset(tpal, 0, 384); loadSpecialColors(tpal); fadePalette(tpal, delay); + fillRect(112, 0, 288, 120, 0); - delete[] tpal; _fadeFlag = 1; } @@ -838,18 +837,18 @@ void Screen_LoL::fadeToBlack(int delay, const UpdateFunctor *upFunc) { } void Screen_LoL::fadeToPalette1(int delay) { - loadSpecialColors(_palettes[0]); - fadePalette(_palettes[0], delay); + loadSpecialColors(getPalette(1)); + fadePalette(getPalette(1), delay); _fadeFlag = 0; } -void Screen_LoL::loadSpecialColors(uint8 *destPalette) { - memcpy(destPalette + 0x240, _screenPalette + 0x240, 12); +void Screen_LoL::loadSpecialColors(Palette &dst) { + dst.copy(*_screenPalette, 192, 4); } void Screen_LoL::copyColor(int dstColorIndex, int srcColorIndex) { - uint8 *s = _screenPalette + srcColorIndex * 3; - uint8 *d = _screenPalette + dstColorIndex * 3; + uint8 *s = _screenPalette->getData() + srcColorIndex * 3; + uint8 *d = _screenPalette->getData() + dstColorIndex * 3; memcpy(d, s, 3); uint8 ci[4]; @@ -862,9 +861,9 @@ void Screen_LoL::copyColor(int dstColorIndex, int srcColorIndex) { } bool Screen_LoL::fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedTime, uint32 targetTime) { - uint8 *dst = _screenPalette + 3 * dstColorIndex; - uint8 *src = _screenPalette + 3 * srcColorIndex; - uint8 *p = getPalette(1) + 3 * dstColorIndex; + const uint8 *dst = _screenPalette->getData() + 3 * dstColorIndex; + const uint8 *src = _screenPalette->getData() + 3 * srcColorIndex; + uint8 *p = getPalette(1).getData() + 3 * dstColorIndex; bool res = false; @@ -897,22 +896,21 @@ bool Screen_LoL::fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedT p++; } - uint8 tpal[768]; - memcpy(tpal, _screenPalette, 768); - memcpy(tpal + dstColorIndex * 3, tmpPalEntry, 3); - setScreenPalette(tpal); + _internFadePalette->copy(*_screenPalette); + _internFadePalette->copy(tmpPalEntry, 0, 1, dstColorIndex); + setScreenPalette(*_internFadePalette); updateScreen(); return res; } bool Screen_LoL::fadePaletteStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 targetTime) { - uint8 tpal[768]; - uint8 *p1 = _palettes[0]; + Palette &p1 = getPalette(1); bool res = false; for (int i = 0; i < 768; i++) { uint8 out = 0; + if (elapsedTime < targetTime) { int32 d = ((pal2[i] & 0x3f) - (pal1[i] & 0x3f)); if (d) @@ -925,10 +923,10 @@ bool Screen_LoL::fadePaletteStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, u res = false; } - tpal[i] = out; + (*_internFadePalette)[i] = out; } - setScreenPalette(tpal); + setScreenPalette(*_internFadePalette); updateScreen(); return res; @@ -936,7 +934,7 @@ bool Screen_LoL::fadePaletteStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, u uint8 *Screen_LoL::generateFadeTable(uint8 *dst, uint8 *src1, uint8 *src2, int numTabs) { if (!src1) - src1 = _screenPalette; + src1 = _screenPalette->getData(); uint8 *p1 = dst; uint8 *p2 = src1; @@ -949,14 +947,14 @@ uint8 *Screen_LoL::generateFadeTable(uint8 *dst, uint8 *src1, uint8 *src2, int n int16 t = 0; int16 d = 256 / numTabs; - + for (int i = 1; i < numTabs - 1; i++) { p2 = src1; p3 = p1; t += d; for (int ii = 0; ii < 768; ii++) { - int val = (((int8)*p3++ * t) >> 8) + (int8)*p2++; + int16 val = (((int8)*p3++ * t) >> 8) + (int8)*p2++; *dst++ = (uint8)val; } } @@ -972,6 +970,45 @@ uint8 Screen_LoL::getShapePaletteSize(const uint8 *shp) { return shp[10]; } +void Screen_LoL::mergeOverlay(int x, int y, int w, int h) { + // For now we convert to 16 colors on overlay merging. If that gives + // any problems, like Screen functionallity not prepared for the + // format PC98 16 color uses, we'll need to think of a better way. + // + // We must do this before merging the overlay, else the font colors + // will be wrong. + if (_use16ColorMode) + convertPC98Gfx(_sjisOverlayPtrs[0] + y * 640 + x, w, h, 640); + + Screen_v2::mergeOverlay(x, y, w, h); +} + +void Screen_LoL::convertPC98Gfx(uint8 *data, int w, int h, int pitch) { + while (h--) { + for (int i = 0; i < w; ++i) { + *data = _paletteConvTable[*data]; + ++data; + } + + data += pitch - w; + } +} + +void Screen_LoL::postProcessCursor(uint8 *data, int w, int h, int pitch) { + if (!_use16ColorMode) + return; + + while (h--) { + for (int i = 0; i < w; ++i) { + if (*data != _cursorColorKey) + *data = _paletteConvTable[*data]; + ++data; + } + + data += pitch - w; + } +} + } // end of namespace Kyra #endif // ENABLE_LOL diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h index 017af4ba48..db355977f8 100644 --- a/engines/kyra/screen_lol.h +++ b/engines/kyra/screen_lol.h @@ -70,14 +70,14 @@ public: // palette stuff void fadeToBlack(int delay=0x54, const UpdateFunctor *upFunc = 0); void fadeToPalette1(int delay); - void loadSpecialColors(uint8 *destPalette); + void loadSpecialColors(Palette &dst); void copyColor(int dstColorIndex, int srcColorIndex); bool fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedTime, uint32 targetTime); bool fadePaletteStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 targetTime); uint8 *generateFadeTable(uint8 *dst, uint8 *src1, uint8 *src2, int numTabs); - void generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors); - uint8 *generateLevelOverlay(const uint8 *srcPal, uint8 *ovl, int opColor, int weight); + void generateGrayOverlay(const Palette &Pal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors); + uint8 *generateLevelOverlay(const Palette &Pal, uint8 *ovl, int opColor, int weight); uint8 *getLevelOverlay(int index) { return _levelOverlays[index]; } void copyBlockAndApplyOverlay(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, uint8 *ovl); @@ -92,6 +92,9 @@ public: uint8 *_grayOverlay; int _fadeFlag; + // PC98 specific + static void convertPC98Gfx(uint8 *data, int w, int h, int pitch); + private: LoLEngine *_vm; @@ -106,6 +109,10 @@ private: uint8 *_levelOverlays[8]; + static const uint8 _paletteConvTable[256]; + void mergeOverlay(int x, int y, int w, int h); + void postProcessCursor(uint8 *data, int width, int height, int pitch); + // magic atlas void calcBoundariesIntern(int dstX, int dstY, int c, int d); diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp index a4e014e8c1..177d7d66dd 100644 --- a/engines/kyra/screen_v2.cpp +++ b/engines/kyra/screen_v2.cpp @@ -38,39 +38,38 @@ Screen_v2::~Screen_v2() { delete[] _wsaFrameAnimBuffer; } -uint8 *Screen_v2::generateOverlay(const uint8 *palette, uint8 *buffer, int startColor, uint16 factor) { - if (!palette || !buffer) +uint8 *Screen_v2::generateOverlay(const Palette &pal, uint8 *buffer, int startColor, uint16 factor) { + if (!buffer) return buffer; factor = MIN<uint16>(255, factor); factor >>= 1; factor &= 0xFF; - const byte col1 = palette[startColor * 3 + 0]; - const byte col2 = palette[startColor * 3 + 1]; - const byte col3 = palette[startColor * 3 + 2]; + const byte col1 = pal[startColor * 3 + 0]; + const byte col2 = pal[startColor * 3 + 1]; + const byte col3 = pal[startColor * 3 + 2]; uint8 *dst = buffer; *dst++ = 0; for (int i = 1; i != 255; ++i) { uint8 processedPalette[3]; - const uint8 *src = palette + i*3; byte col; - col = *src++; + col = pal[i * 3 + 0]; col -= ((((col - col1) * factor) << 1) >> 8) & 0xFF; processedPalette[0] = col; - col = *src++; + col = pal[i * 3 + 1]; col -= ((((col - col2) * factor) << 1) >> 8) & 0xFF; processedPalette[1] = col; - col = *src++; + col = pal[i * 3 + 2]; col -= ((((col - col3) * factor) << 1) >> 8) & 0xFF; processedPalette[2] = col; - *dst++ = findLeastDifferentColor(processedPalette, palette+3, 255)+1; + *dst++ = findLeastDifferentColor(processedPalette, pal, 1, 255) + 1; } return buffer; @@ -90,7 +89,7 @@ void Screen_v2::applyOverlay(int x, int y, int w, int h, int pageNum, const uint } } -int Screen_v2::findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *palette, uint16 numColors, bool skipSpecialColors) { +int Screen_v2::findLeastDifferentColor(const uint8 *paletteEntry, const Palette &pal, uint8 firstColor, uint16 numColors, bool skipSpecialColors) { int m = 0x7fff; int r = 0x101; @@ -98,11 +97,11 @@ int Screen_v2::findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *p if (skipSpecialColors && i >= 0xc0 && i <= 0xc3) continue; - int v = paletteEntry[0] - *palette++; + int v = paletteEntry[0] - pal[(i + firstColor) * 3 + 0]; int c = v * v; - v = paletteEntry[1] - *palette++; + v = paletteEntry[1] - pal[(i + firstColor) * 3 + 1]; c += (v * v); - v = paletteEntry[2] - *palette++; + v = paletteEntry[2] - pal[(i + firstColor) * 3 + 2]; c += (v * v); if (c <= m) { @@ -114,12 +113,11 @@ 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) { +void Screen_v2::getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff) { int maxDiff = 0; diff = 0; - int len = _use16ColorMode ? 48 : 768; - for (int i = 0; i < len; ++i) { - diff = ABS(palette[i] - _screenPalette[i]); + for (int i = 0; i < pal.getNumColors() * 3; ++i) { + diff = ABS(pal[i] - (*_screenPalette)[i]); maxDiff = MAX(maxDiff, diff); } @@ -137,148 +135,6 @@ void Screen_v2::getFadeParams(const uint8 *palette, int delay, int &delayInc, in } } -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); - uint8 *origDst = dstPtr; - - const ScreenDim *dim = getScreenDim(dimState); - int dimX1 = dim->sx << 3; - int dimX2 = dim->w << 3; - dimX2 += dimX1; - - int dimY1 = dim->sy; - int dimY2 = dim->h; - dimY2 += dimY1; - - int temp = y - dimY1; - if (temp < 0) { - if ((temp += h) <= 0) - return; - else { - SWAP(temp, h); - y += temp - h; - src += (temp - h) * w; - } - } - - temp = dimY2 - y; - if (temp <= 0) - return; - - if (temp < h) - h = temp; - - int srcOffset = 0; - temp = x - dimX1; - if (temp < 0) { - temp = -temp; - srcOffset = temp; - x += temp; - w -= temp; - } - - int srcAdd = 0; - - temp = dimX2 - x; - if (temp <= 0) - return; - - if (temp < w) { - SWAP(w, temp); - temp -= w; - srcAdd = temp; - } - - dstPtr += y * SCREEN_W + x; - uint8 *dst = dstPtr; - - if (_curPage == 0 || _curPage == 1) - addDirtyRect(x, y, w, h); - - clearOverlayRect(_curPage, x, y, w, h); - - temp = h; - int curY = y; - while (h--) { - src += srcOffset; - ++curY; - int cW = w; - - switch (plotFunc) { - case 0: - memcpy(dst, src, cW); - dst += cW; src += cW; - break; - - case 1: - while (cW--) { - uint8 d = *src++; - uint8 t = unkPtr1[d]; - if (t != 0xFF) - d = unkPtr2[*dst + (t << 8)]; - *dst++ = d; - } - break; - - case 4: - while (cW--) { - uint8 d = *src++; - if (d) - *dst = d; - ++dst; - } - break; - - case 5: - while (cW--) { - uint8 d = *src++; - if (d) { - uint8 t = unkPtr1[d]; - if (t != 0xFF) - d = unkPtr2[*dst + (t << 8)]; - *dst = d; - } - ++dst; - } - break; - - case 8: - case 9: - while (cW--) { - uint8 d = *src++; - uint8 t = _shapePages[0][dst - origDst] & 7; - if (unk1 < t && (curY > _maskMinY && curY < _maskMaxY)) - d = _shapePages[1][dst - origDst]; - *dst++ = d; - } - break; - - case 12: - case 13: - while (cW--) { - uint8 d = *src++; - if (d) { - uint8 t = _shapePages[0][dst - origDst] & 7; - if (unk1 < t && (curY > _maskMinY && curY < _maskMaxY)) - d = _shapePages[1][dst - origDst]; - *dst++ = d; - } else { - d = _shapePages[1][dst - origDst]; - *dst++ = d; - } - } - break; - - default: - break; - } - - dst = (dstPtr += SCREEN_W); - src += srcAdd; - } -} - const uint8 *Screen_v2::getPtrToShape(const uint8 *shpFile, int shape) { uint16 shapes = READ_LE_UINT16(shpFile); diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h index 18bac764ec..3aa726334c 100644 --- a/engines/kyra/screen_v2.h +++ b/engines/kyra/screen_v2.h @@ -37,17 +37,14 @@ public: ~Screen_v2(); // screen page handling - 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); + uint8 *generateOverlay(const Palette &pal, 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, bool skipSpecialColors = false); + int findLeastDifferentColor(const uint8 *paletteEntry, const Palette &pal, uint8 firstColor, uint16 numColors, bool skipSpecialColors = false); - virtual void getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff); + virtual void getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff); // shape handling uint8 *getPtrToShape(uint8 *shpFile, int shape); diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp index 9035708f5e..0473f03591 100644 --- a/engines/kyra/script.cpp +++ b/engines/kyra/script.cpp @@ -66,6 +66,42 @@ EMCInterpreter::EMCInterpreter(KyraEngine_v1 *vm) : _vm(vm) { #undef OPCODE } +bool EMCInterpreter::callback(Common::IFFChunk &chunk) { + switch (chunk._type) { + case MKID_BE('TEXT'): + _scriptData->text = new byte[chunk._size]; + assert(_scriptData->text); + if (chunk._stream->read(_scriptData->text, chunk._size) != chunk._size) + error("Couldn't read TEXT chunk from file '%s'", _filename); + break; + + case MKID_BE('ORDR'): + _scriptData->ordr = new uint16[chunk._size >> 1]; + assert(_scriptData->ordr); + if (chunk._stream->read(_scriptData->ordr, chunk._size) != chunk._size) + error("Couldn't read ORDR chunk from file '%s'", _filename); + + for (int i = (chunk._size >> 1) - 1; i >= 0; --i) + _scriptData->ordr[i] = READ_BE_UINT16(&_scriptData->ordr[i]); + break; + + case MKID_BE('DATA'): + _scriptData->data = new uint16[chunk._size >> 1]; + assert(_scriptData->data); + if (chunk._stream->read(_scriptData->data, chunk._size) != chunk._size) + error("Couldn't read DATA chunk from file '%s'", _filename); + + for (int i = (chunk._size >> 1) - 1; i >= 0; --i) + _scriptData->data[i] = READ_BE_UINT16(&_scriptData->data[i]); + break; + + default: + warning("Unexpected chunk '%s' of size %d found in file '%s'", Common::ID2string(chunk._type), chunk._size, _filename); + } + + return false; +} + bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array<const Opcode*> *opcodes) { Common::SeekableReadStream *stream = _vm->resource()->createReadStream(filename); if (!stream) { @@ -75,47 +111,17 @@ bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Commo memset(scriptData, 0, sizeof(EMCData)); + _scriptData = scriptData; + _filename = filename; + IFFParser iff(*stream); - Common::IFFChunk *chunk = 0; - - while ((chunk = iff.nextChunk()) != 0) { - switch (chunk->id) { - case MKID_BE('TEXT'): - scriptData->text = new byte[chunk->size]; - assert(scriptData->text); - if (chunk->read(scriptData->text, chunk->size) != chunk->size) - error("Couldn't read TEXT chunk from file '%s'", filename); - break; - - case MKID_BE('ORDR'): - scriptData->ordr = new uint16[chunk->size >> 1]; - assert(scriptData->ordr); - if (chunk->read(scriptData->ordr, chunk->size) != chunk->size) - error("Couldn't read ORDR chunk from file '%s'", filename); - - for (int i = (chunk->size >> 1) - 1; i >= 0; --i) - scriptData->ordr[i] = READ_BE_UINT16(&scriptData->ordr[i]); - break; - - case MKID_BE('DATA'): - scriptData->data = new uint16[chunk->size >> 1]; - assert(scriptData->data); - if (chunk->read(scriptData->data, chunk->size) != chunk->size) - error("Couldn't read DATA chunk from file '%s'", filename); - - for (int i = (chunk->size >> 1) - 1; i >= 0; --i) - scriptData->data[i] = READ_BE_UINT16(&scriptData->data[i]); - break; - - default: - warning("Unexpected chunk '%s' of size %d found in file '%s'", Common::ID2string(chunk->id), chunk->size, filename); - } - } + Common::Functor1Mem< Common::IFFChunk &, bool, EMCInterpreter > c(this, &EMCInterpreter::callback); + iff.parse(c); - if (!scriptData->ordr) + if (!_scriptData->ordr) error("No ORDR chunk found in file: '%s'", filename); - if (!scriptData->data) + if (!_scriptData->data) error("No DATA chunk found in file: '%s'", filename); if (stream->err()) @@ -123,10 +129,10 @@ bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Commo delete stream; - scriptData->sysFuncs = opcodes; + _scriptData->sysFuncs = opcodes; - strncpy(scriptData->filename, filename, 13); - scriptData->filename[12] = 0; + strncpy(_scriptData->filename, filename, 13); + _scriptData->filename[12] = 0; return true; } diff --git a/engines/kyra/script.h b/engines/kyra/script.h index 88bbe86c4d..862cfb7d97 100644 --- a/engines/kyra/script.h +++ b/engines/kyra/script.h @@ -70,7 +70,7 @@ class KyraEngine_v1; class IFFParser : public Common::IFFParser { public: - IFFParser(Common::SeekableReadStream &input) : Common::IFFParser(input) { + IFFParser(Common::ReadStream &input) : Common::IFFParser(&input) { // It seems Westwood missunderstood the 'size' field of the FORM chunk. // // For EMC scripts (type EMC2) it's filesize instead of filesize - 8, @@ -84,9 +84,9 @@ public: // Both lead to some problems in our IFF parser, either reading after the end // of file or producing a "Chunk overread" error message. To work around this // we need to adjust the size field properly. - if (_typeId == MKID_BE('EMC2')) + if (_formType == MKID_BE('EMC2')) _formChunk.size -= 8; - else if (_typeId == MKID_BE('AVFS')) + else if (_formType == MKID_BE('AVFS')) _formChunk.size += 4; } }; @@ -108,6 +108,11 @@ protected: KyraEngine_v1 *_vm; int16 _parameter; + const char *_filename; + EMCData *_scriptData; + + bool callback(Common::IFFChunk &chunk); + typedef void (EMCInterpreter::*OpcodeProc)(EMCState *); struct OpcodeEntry { OpcodeProc proc; diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp index b2a581cece..1b8c1d32b3 100644 --- a/engines/kyra/script_hof.cpp +++ b/engines/kyra/script_hof.cpp @@ -146,7 +146,7 @@ int KyraEngine_HoF::o2_meanWhileScene(EMCState *script) { const char *palfile = stackPosString(1); _screen->loadBitmap(cpsfile, 3, 3, 0); - memcpy(_screen->getPalette(2), _screen->_currentPalette, 768); + _screen->copyPalette(2, 0); _screen->loadPalette(palfile, _screen->getPalette(2)); _screen->fillRect(0, 0, 319, 199, 207); _screen->setScreenPalette(_screen->getPalette(2)); @@ -559,14 +559,14 @@ int KyraEngine_HoF::o2_enableAnimObject(EMCState *script) { int KyraEngine_HoF::o2_loadPalette384(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_loadPalette384(%p) ('%s')", (const void *)script, stackPosString(0)); - memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); - _res->loadFileToBuf(stackPosString(0), _screen->getPalette(1), 384); + _screen->copyPalette(1, 0); + _res->loadFileToBuf(stackPosString(0), _screen->getPalette(1).getData(), 384); return 0; } int KyraEngine_HoF::o2_setPalette384(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_setPalette384(%p) ()", (const void *)script); - memcpy(_screen->getPalette(0), _screen->getPalette(1), 384); + _screen->getPalette(0).copy(_screen->getPalette(1), 0, 128); _screen->setScreenPalette(_screen->getPalette(0)); return 0; } @@ -774,13 +774,13 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) { displayInvWsaLastFrame(); backUpPage0(); - memcpy(_screen->getPalette(2), _screen->getPalette(0), 768); + _screen->copyPalette(2, 0); _screen->clearPage(3); _screen->loadBitmap("_NOTE.CPS", 3, 3, 0); sprintf(filename, "_NTEPAL%.1d.COL", letter+1); - _res->loadFileToBuf(filename, _screen->getPalette(0), 768); + _screen->loadPalette(filename, _screen->getPalette(0)); _screen->fadeToBlack(0x14); @@ -819,7 +819,7 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) { _screen->hideMouse(); _screen->fadeToBlack(0x14); restorePage0(); - memcpy(_screen->getPalette(0), _screen->getPalette(2), 768); + _screen->copyPalette(0, 2); _screen->fadePalette(_screen->getPalette(0), 0x14); setHandItem(_itemInHand); _screen->showMouse(); @@ -1125,25 +1125,25 @@ int KyraEngine_HoF::o2_resetInputColorCode(EMCState *script) { int KyraEngine_HoF::o2_mushroomEffect(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_mushroomEffect(%p)", (const void *)script); - memcpy(_screen->getPalette(2), _screen->_currentPalette, 768); + _screen->copyPalette(2, 0); for (int i = 1; i < 768; i += 3) - _screen->_currentPalette[i] = 0; + _screen->getPalette(0)[i] = 0; snd_playSoundEffect(106); - _screen->fadePalette(_screen->_currentPalette, 90, &_updateFunctor); - memcpy(_screen->_currentPalette, _screen->getPalette(2), 768); + _screen->fadePalette(_screen->getPalette(0), 90, &_updateFunctor); + _screen->copyPalette(0, 2); for (int i = 0; i < 768; i += 3) { - _screen->_currentPalette[i] = _screen->_currentPalette[i + 1] = 0; - _screen->_currentPalette[i + 2] += (((int8)_screen->_currentPalette[i + 2]) >> 1); - if (_screen->_currentPalette[i + 2] > 63) - _screen->_currentPalette[i + 2] = 63; + _screen->getPalette(0)[i] = _screen->getPalette(0)[i + 1] = 0; + _screen->getPalette(0)[i + 2] += (((int8)_screen->getPalette(0)[i + 2]) >> 1); + if (_screen->getPalette(0)[i + 2] > 63) + _screen->getPalette(0)[i + 2] = 63; } snd_playSoundEffect(106); - _screen->fadePalette(_screen->_currentPalette, 90, &_updateFunctor); + _screen->fadePalette(_screen->getPalette(0), 90, &_updateFunctor); - memcpy(_screen->_currentPalette, _screen->getPalette(2), 768); - _screen->fadePalette(_screen->_currentPalette, 30, &_updateFunctor); + _screen->copyPalette(0, 2); + _screen->fadePalette(_screen->getPalette(0), 30, &_updateFunctor); return 0; } @@ -1262,19 +1262,23 @@ int KyraEngine_HoF::o2_stopSceneAnimation(EMCState *script) { int KyraEngine_HoF::o2_processPaletteIndex(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_processPaletteIndex(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5)); - uint8 *palette = _screen->getPalette(0); + Palette &palette = _screen->getPalette(0); + const int index = stackPos(0); const bool updatePalette = (stackPos(4) != 0); const int delayTime = stackPos(5); + palette[index*3+0] = (stackPos(1) * 0x3F) / 100; palette[index*3+1] = (stackPos(2) * 0x3F) / 100; palette[index*3+2] = (stackPos(3) * 0x3F) / 100; + if (updatePalette) { if (delayTime > 0) _screen->fadePalette(palette, delayTime, &_updateFunctor); else _screen->setScreenPalette(palette); } + return 0; } @@ -1396,7 +1400,7 @@ int KyraEngine_HoF::o2_demoFinale(EMCState *script) { assert(strings); _screen->clearPage(0); - _screen->loadPalette("THANKS.COL", _screen->_currentPalette); + _screen->loadPalette("THANKS.COL", _screen->getPalette(0)); _screen->loadBitmap("THANKS.CPS", 3, 3, 0); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0); @@ -1406,7 +1410,7 @@ int KyraEngine_HoF::o2_demoFinale(EMCState *script) { for (int i = 0; i < 6; i++) _text->printText(strings[i], _text->getCenterStringX(strings[i], 1, 319), y + i * 10, 255, 207, 0); - _screen->setScreenPalette(_screen->_currentPalette); + _screen->setScreenPalette(_screen->getPalette(0)); _screen->updateScreen(); _eventList.clear(); diff --git a/engines/kyra/script_lok.cpp b/engines/kyra/script_lok.cpp index 03a5d4efc1..849c6b776d 100644 --- a/engines/kyra/script_lok.cpp +++ b/engines/kyra/script_lok.cpp @@ -231,7 +231,8 @@ int KyraEngine_LoK::o1_fadeSpecialPalette(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_fadeSpecialPalette(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); if (_currentCharacter->sceneId != 45) { if (stackPos(0) == 13) { - memcpy(_screen->getPalette(0), _screen->getPalette(0) + 384*3, 32*3); + // TODO: Check this! + _screen->copyPalette(0, 12); _screen->setScreenPalette(_screen->getPalette(0)); } } else { @@ -427,7 +428,7 @@ int KyraEngine_LoK::o1_runWSAFromBeginningToEnd(EMCState *script) { int wsaFrame = 0; while (running) { - _movieObjects[wsaIndex]->displayFrame(wsaFrame++, 0, xpos, ypos); + _movieObjects[wsaIndex]->displayFrame(wsaFrame++, 0, xpos, ypos, 0, 0, 0); _animator->_updateScreen = true; if (wsaFrame >= _movieObjects[wsaIndex]->frames()) running = false; @@ -458,7 +459,7 @@ int KyraEngine_LoK::o1_displayWSAFrame(EMCState *script) { int waitTime = stackPos(3); int wsaIndex = stackPos(4); _screen->hideMouse(); - _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos); + _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos, 0, 0, 0); _animator->_updateScreen = true; uint32 continueTime = waitTime * _tickLength + _system->getMillis(); while (_system->getMillis() < continueTime) { @@ -500,7 +501,7 @@ int KyraEngine_LoK::o1_runWSAFrames(EMCState *script) { _screen->hideMouse(); for (; startFrame <= endFrame; ++startFrame) { uint32 nextRun = _system->getMillis() + delayTime * _tickLength; - _movieObjects[wsaIndex]->displayFrame(startFrame, 0, xpos, ypos); + _movieObjects[wsaIndex]->displayFrame(startFrame, 0, xpos, ypos, 0, 0, 0); _animator->_updateScreen = true; while (_system->getMillis() < nextRun) { _sprites->updateSceneAnims(); @@ -578,7 +579,7 @@ int KyraEngine_LoK::o1_restoreAllObjectBackgrounds(EMCState *script) { int KyraEngine_LoK::o1_setCustomPaletteRange(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCustomPaletteRange(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); - memcpy(_screen->getPalette(1) + stackPos(1)*3, _specialPalettes[stackPos(0)], stackPos(2)*3); + _screen->getPalette(1).copy(_specialPalettes[stackPos(0)], 0, stackPos(2), stackPos(1)); return 0; } @@ -682,7 +683,7 @@ int KyraEngine_LoK::o1_displayWSAFrameOnHidPage(EMCState *script) { _screen->hideMouse(); uint32 continueTime = waitTime * _tickLength + _system->getMillis(); - _movieObjects[wsaIndex]->displayFrame(frame, 2, xpos, ypos); + _movieObjects[wsaIndex]->displayFrame(frame, 2, xpos, ypos, 0, 0, 0); _animator->_updateScreen = true; while (_system->getMillis() < continueTime) { _sprites->updateSceneAnims(); @@ -753,7 +754,7 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) { // what shouldn't happen. So we're not updating the screen for this special // case too. if (startFrame == 18 && endFrame == 18 && _currentRoom == 45) { - _movieObjects[wsaIndex]->displayFrame(18, 0, xpos, ypos); + _movieObjects[wsaIndex]->displayFrame(18, 0, xpos, ypos, 0, 0, 0); delay(waitTime * _tickLength); return 0; } @@ -765,7 +766,7 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) { int frame = startFrame; while (endFrame >= frame) { uint32 continueTime = waitTime * _tickLength + _system->getMillis(); - _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos); + _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos, 0, 0, 0); if (waitTime) _animator->_updateScreen = true; while (_system->getMillis() < continueTime) { @@ -783,7 +784,7 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) { int frame = startFrame; while (endFrame <= frame) { uint32 continueTime = waitTime * _tickLength + _system->getMillis(); - _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos); + _movieObjects[wsaIndex]->displayFrame(frame, 0, xpos, ypos, 0, 0, 0); if (waitTime) _animator->_updateScreen = true; while (_system->getMillis() < continueTime) { @@ -912,8 +913,6 @@ int KyraEngine_LoK::o1_placeCharacterInOtherScene(EMCState *script) { int KyraEngine_LoK::o1_getKey(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getKey(%p) ()", (const void *)script); - // TODO: Check this implementation - while (true) { delay(10); @@ -1243,8 +1242,8 @@ int KyraEngine_LoK::o1_setFireberryGlowPalette(EMCState *script) { palIndex = 14; } } - const uint8 *palette = _specialPalettes[palIndex]; - memcpy(_screen->getPalette(1) + 684, palette, 44); + + _screen->getPalette(1).copy(_specialPalettes[palIndex], 0, 15, 228); return 0; } @@ -1276,7 +1275,7 @@ int KyraEngine_LoK::o1_makeAmuletAppear(EMCState *script) { if (code == 14) snd_playSoundEffect(0x73); - amulet.displayFrame(code, 0, 224, 152); + amulet.displayFrame(code, 0, 224, 152, 0, 0, 0); _animator->_updateScreen = true; while (_system->getMillis() < nextTime) { @@ -1501,40 +1500,38 @@ int KyraEngine_LoK::o1_setNoDrawShapesFlag(EMCState *script) { int KyraEngine_LoK::o1_fadeEntirePalette(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_fadeEntirePalette(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1)); int cmd = stackPos(0); - uint8 *fadePal = 0; + + int fadePal = 0; if (_flags.platform == Common::kPlatformAmiga) { if (cmd == 0) { - fadePal = _screen->getPalette(2); - memset(fadePal, 0, 32*3); - memcpy(_screen->getPalette(4), _screen->getPalette(0), 32*3); + _screen->getPalette(2).clear(); + fadePal = 2; + _screen->copyPalette(4, 0); } else if (cmd == 1) { - fadePal = _screen->getPalette(0); - memcpy(_screen->getPalette(0), _screen->getPalette(4), 32*3); + fadePal = 0; + _screen->copyPalette(0, 4); } else if (cmd == 2) { - fadePal = _screen->getPalette(0); - memset(_screen->getPalette(2), 0, 32*3); + fadePal = 0; + _screen->getPalette(2).clear(); } } else { if (cmd == 0) { - fadePal = _screen->getPalette(2); - uint8 *screenPal = _screen->getPalette(0); - uint8 *backUpPal = _screen->getPalette(3); - - memcpy(backUpPal, screenPal, sizeof(uint8)*768); - memset(fadePal, 0, sizeof(uint8)*768); + fadePal = 2; + _screen->getPalette(2).clear(); + _screen->copyPalette(3, 0); } else if (cmd == 1) { - //fadePal = _screen->getPalette(3); + //fadePal = 3; warning("unimplemented o1_fadeEntirePalette function"); return 0; } else if (cmd == 2) { - memset(_screen->getPalette(2), 0, 768); - memcpy(_screen->getPalette(0), _screen->getPalette(1), 768); - fadePal = _screen->getPalette(0); + _screen->getPalette(2).clear(); + _screen->copyPalette(0, 1); + fadePal = 0; } } - _screen->fadePalette(fadePal, stackPos(1)); + _screen->fadePalette(_screen->getPalette(fadePal), stackPos(1)); return 0; } diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp index 3d57b23181..a606419722 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -609,7 +609,7 @@ int LoLEngine::olol_fadePalette(EMCState *script) { int LoLEngine::olol_loadBitmap(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_clearDialogueField(%p) (%s, %d)", (const void *)script, stackPosString(0), stackPos(1)); - _screen->loadBitmap(stackPosString(0), 3, 3, _screen->getPalette(3)); + _screen->loadBitmap(stackPosString(0), 3, 3, &_screen->getPalette(3)); if (stackPos(1) != 2) _screen->copyPage(3, stackPos(1)); return 1; @@ -663,7 +663,7 @@ int LoLEngine::olol_getGlobalVar(EMCState *script) { case 12: return _drainMagic; case 13: - return _speechFlag; + return getVolume(kVolumeSpeech) - 2; default: break; } @@ -864,7 +864,7 @@ int LoLEngine::olol_fadeClearSceneWindow(EMCState *script) { int LoLEngine::olol_fadeSequencePalette(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_fadeSequencePalette(%p)", (const void *)script); - memcpy(_screen->getPalette(3) + 0x180, _screen->_currentPalette + 0x180, 0x180); + _screen->getPalette(3).copy(_screen->getPalette(0), 128); _screen->loadSpecialColors(_screen->getPalette(3)); _screen->fadePalette(_screen->getPalette(3), 10); _screen->_fadeFlag = 0; @@ -876,7 +876,7 @@ int LoLEngine::olol_redrawPlayfield(EMCState *script) { if (_screen->_fadeFlag != 2) _screen->fadeClearSceneWindow(10); gui_drawPlayField(); - setPaletteBrightness(_screen->_currentPalette, _brightness, _lampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); _screen->_fadeFlag = 0; return 1; } @@ -1276,7 +1276,7 @@ int LoLEngine::olol_getMonsterStat(EMCState *script) { int LoLEngine::olol_releaseMonsterShapes(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_releaseMonsterShapes(%p)", (const void *)script); for (int i = 0; i < 3; i++) - releaseMonsterShapes(i); + releaseMonsterShapes(i); return 0; } @@ -1399,17 +1399,17 @@ int LoLEngine::olol_playEndSequence(EMCState *script){ if (_characters[0].id == -9) c = 1; else if (_characters[0].id == -5) - c = 3; + c = 3; else if (_characters[0].id == -1) c = 2; while (snd_updateCharacterSpeech()) delay(_tickLength); - + _eventList.clear(); _screen->hideMouse(); - memset(_screen->getPalette(1), 0, 768); - + _screen->getPalette(1).clear(); + showOutro(c, (_monsterDifficulty == 2)); quitGame(); @@ -1428,7 +1428,7 @@ int LoLEngine::olol_setPaletteBrightness(EMCState *script) { uint16 old = _brightness; _brightness = stackPos(0); if (stackPos(1) == 1) - setPaletteBrightness(_screen->_currentPalette, stackPos(0), _lampEffect); + setPaletteBrightness(_screen->getPalette(0), stackPos(0), _lampEffect); return old; } @@ -1994,10 +1994,16 @@ int LoLEngine::olol_findInventoryItem(EMCState *script) { return -1; } +int LoLEngine::olol_drinkBezelCup(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_drinkBezelCup(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1)); + drinkBezelCup(3 - stackPos(0), stackPos(1)); + return 1; +} + int LoLEngine::olol_restoreFadePalette(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restoreFadePalette(%p)", (const void *)script); - memcpy(_screen->_currentPalette, _screen->getPalette(1), 384); - _screen->fadePalette(_screen->_currentPalette, 10); + _screen->getPalette(0).copy(_screen->getPalette(1), 0, 128); + _screen->fadePalette(_screen->getPalette(0), 10); _screen->_fadeFlag = 0; return 1; } @@ -2095,27 +2101,29 @@ int LoLEngine::olol_increaseSkill(EMCState *script) { int LoLEngine::olol_paletteFlash(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_paletteFlash(%p) (%d)", (const void *)script, stackPos(0)); - uint8 *s = _screen->getPalette(1); - uint8 *d = _screen->getPalette(3); + Palette &p1 = _screen->getPalette(1); + Palette &p2 = _screen->getPalette(3); + uint8 ovl[256]; - generateFlashPalette(s, d, stackPos(0)); - _screen->loadSpecialColors(s); - _screen->loadSpecialColors(d); + generateFlashPalette(p1, p2, stackPos(0)); + _screen->loadSpecialColors(p1); + _screen->loadSpecialColors(p2); if (_smoothScrollModeNormal) { for (int i = 0; i < 256; i++) ovl[i] = i; ovl[1] = 6; + _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, 2); _screen->applyOverlay(112, 0, 176, 120, 0, ovl); } - _screen->setScreenPalette(d); + _screen->setScreenPalette(p2); _screen->updateScreen(); delay(2 * _tickLength); - _screen->setScreenPalette(s); + _screen->setScreenPalette(p1); if (_smoothScrollModeNormal) _screen->copyRegion(112, 0, 112, 0, 176, 120, 2, 0); @@ -2126,55 +2134,65 @@ int LoLEngine::olol_paletteFlash(EMCState *script) { int LoLEngine::olol_restoreMagicShroud(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_restoreMagicShroud(%p)", (const void *)script); - WSAMovie_v2 *mov = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *mov = new WSAMovie_v2(this); mov->open("DARKLITE.WSA", 2, 0); if (!mov->opened()) return 0; _screen->hideMouse(); + // TODO: This function could need some major cleanup to work with our + // new palette code without needless conversions. uint8 *fadeTab = new uint8[21504]; uint8 *tpal1 = fadeTab; uint8 *tpal2 = tpal1 + 768; uint8 *tpal3 = tpal2 + 768; uint8 *tpal4 = 0; - _screen->loadPalette("LITEPAL1.COL", tpal1); + _res->loadFileToBuf("LITEPAL1.COL", tpal1, 768); tpal2 = _screen->generateFadeTable(tpal3, 0, tpal1, 21); - _screen->loadPalette("LITEPAL2.COL", tpal2); + _res->loadFileToBuf("LITEPAL2.COL", tpal2, 768); tpal4 = tpal2; tpal2 += 768; - _screen->loadPalette("LITEPAL3.COL", tpal1); + _res->loadFileToBuf("LITEPAL3.COL", tpal1, 768); _screen->generateFadeTable(tpal2, tpal4, tpal1, 4); + Palette pal(768); + for (int i = 0; i < 21; i++) { uint32 etime = _system->getMillis() + 20 * _tickLength; - mov->displayFrame(i, 0, 0, 0, 0); + mov->displayFrame(i, 0, 0, 0, 0, 0, 0); _screen->updateScreen(); - _screen->setScreenPalette(tpal3); + + pal.copy(tpal3, 0, 256); + _screen->setScreenPalette(pal); tpal3 += 768; + if (i == 2 || i == 5 || i == 8 || i == 11 || i == 13 || i == 15 || i == 17 || i == 19) snd_playSoundEffect(95, -1); delayUntil(etime); } + pal.copy(tpal3, 0, 256); snd_playSoundEffect(91, -1); - _screen->fadePalette(tpal3, 300); + _screen->fadePalette(pal, 300); tpal3 += 768; for (int i = 22; i < 38; i++) { uint32 etime = _system->getMillis() + 12 * _tickLength; - mov->displayFrame(i, 0, 0, 0, 0); + mov->displayFrame(i, 0, 0, 0, 0, 0, 0); _screen->updateScreen(); if (i == 22 || i == 24 || i == 28 || i == 32) { snd_playSoundEffect(131, -1); - _screen->setScreenPalette(tpal3); + + pal.copy(tpal3, 0, 256); + _screen->setScreenPalette(pal); tpal3 += 768; } delayUntil(etime); } mov->close(); - delete mov; + delete mov; delete[] fadeTab; _screen->showMouse(); @@ -2297,7 +2315,7 @@ int LoLEngine::tlol_loadPalette(const TIM *tim, const uint16 *param) { 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->copyPalette(0, 1); _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff); _tim->_palDelayAcc = 0; @@ -2375,7 +2393,6 @@ int LoLEngine::tlol_setPartyPosition(const TIM *tim, const uint16 *param) { int LoLEngine::tlol_fadeClearWindow(const TIM *tim, const uint16 *param) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_fadeClearWindow(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]); - uint8 *tmp = 0; switch (param[0]) { case 0: @@ -2383,10 +2400,9 @@ int LoLEngine::tlol_fadeClearWindow(const TIM *tim, const uint16 *param) { break; case 1: - tmp = _screen->getPalette(3); - memcpy(tmp + 0x180, _screen->_currentPalette + 0x180, 0x180); - _screen->loadSpecialColors(tmp); - _screen->fadePalette(tmp, 10); + _screen->getPalette(3).copy(_screen->getPalette(0), 128); + _screen->loadSpecialColors(_screen->getPalette(3)); + _screen->fadePalette(_screen->getPalette(3), 10); _screen->_fadeFlag = 0; break; @@ -2395,9 +2411,8 @@ int LoLEngine::tlol_fadeClearWindow(const TIM *tim, const uint16 *param) { break; case 3: - tmp = _screen->getPalette(3); - _screen->loadSpecialColors(tmp); - _screen->fadePalette(tmp, 10); + _screen->loadSpecialColors(_screen->getPalette(3)); + _screen->fadePalette(_screen->getPalette(3), 10); _screen->_fadeFlag = 0; break; @@ -2405,13 +2420,12 @@ int LoLEngine::tlol_fadeClearWindow(const TIM *tim, const uint16 *param) { if (_screen->_fadeFlag != 2) _screen->fadeClearSceneWindow(10); gui_drawPlayField(); - setPaletteBrightness(_screen->_currentPalette, _brightness, _lampEffect); + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); _screen->_fadeFlag = 0; break; case 5: - tmp = _screen->getPalette(3); - _screen->loadSpecialColors(tmp); + _screen->loadSpecialColors(_screen->getPalette(3)); _screen->fadePalette(_screen->getPalette(1), 10); _screen->_fadeFlag = 0; break; @@ -2511,7 +2525,7 @@ int LoLEngine::tlol_fadeInScene(const TIM *tim, const uint16 *param) { strcpy(filename, sceneFile); strcat(filename, ".CPS"); - _screen->loadBitmap(filename, 7, 5, _screen->getPalette(0)); + _screen->loadBitmap(filename, 7, 5, &_screen->getPalette(0)); filename[0] = 0; @@ -2547,9 +2561,11 @@ int LoLEngine::tlol_unusedResourceFunc(const TIM *tim, const uint16 *param) { int LoLEngine::tlol_fadeInPalette(const TIM *tim, const uint16 *param) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_fadeInPalette(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]); const char *bitmap = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0]<<1))); - uint8 palette[768]; - _screen->loadBitmap(bitmap, 3, 3, palette); - _screen->fadePalette(palette, param[1]); + + Palette pal(_screen->getPalette(0).getNumColors()); + _screen->loadBitmap(bitmap, 3, 3, &pal); + _screen->fadePalette(pal, param[1]); + return 1; } @@ -2566,7 +2582,7 @@ int LoLEngine::tlol_displayAnimFrame(const TIM *tim, const uint16 *param) { if (param[1] == 0xFFFF) { _screen->copyRegion(0, 0, 0, 0, 320, 200, 0, 2, Screen::CR_NO_P_CHECK); } else { - anim->wsa->displayFrame(param[1], 2, anim->x, anim->y, 0); + anim->wsa->displayFrame(param[1], 2, anim->x, anim->y, 0, 0, 0); _screen->copyRegion(anim->wsa->xAdd(), anim->wsa->yAdd(), anim->wsa->xAdd(), anim->wsa->yAdd(), anim->wsa->width(), anim->wsa->height(), 2, 0); } @@ -2852,7 +2868,7 @@ void LoLEngine::setupOpcodeTable() { // 0xA8 OpcodeUnImpl(); OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_drinkBezelCup); Opcode(olol_changeItemTypeOrFlag); // 0xAC diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp index 558d703f15..1800bd1939 100644 --- a/engines/kyra/script_mr.cpp +++ b/engines/kyra/script_mr.cpp @@ -381,13 +381,10 @@ int KyraEngine_MR::o3_checkInRect(EMCState *script) { y += desc[1]; } - if (x >= x1 && x <= x2 && y >= y1 && y <= y2) { - //XXX + if (x >= x1 && x <= x2 && y >= y1 && y <= y2) return 1; - } else { - //XXX + else return 0; - } } int KyraEngine_MR::o3_updateConversations(EMCState *script) { diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index e9ca23a4c9..424a62aaf8 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -116,6 +116,33 @@ TIMInterpreter::~TIMInterpreter() { delete[] _animations; } +bool TIMInterpreter::callback(Common::IFFChunk &chunk) { + switch (chunk._type) { + case MKID_BE('TEXT'): + _tim->text = new byte[chunk._size]; + assert(_tim->text); + if (chunk._stream->read(_tim->text, chunk._size) != chunk._size) + error("Couldn't read TEXT chunk from file '%s'", _filename); + break; + + case MKID_BE('AVTL'): + _avtlChunkSize = chunk._size >> 1; + _tim->avtl = new uint16[_avtlChunkSize]; + assert(_tim->avtl); + if (chunk._stream->read(_tim->avtl, chunk._size) != chunk._size) + error("Couldn't read AVTL chunk from file '%s'", _filename); + + for (int i = _avtlChunkSize - 1; i >= 0; --i) + _tim->avtl[i] = READ_LE_UINT16(&_tim->avtl[i]); + break; + + default: + warning("Unexpected chunk '%s' of size %d found in file '%s'", Common::ID2string(chunk._type), chunk._size, _filename); + } + + return false; +} + TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode *> *opcodes) { if (!_vm->resource()->exists(filename)) return 0; @@ -124,44 +151,21 @@ TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpc if (!stream) error("Couldn't open TIM file '%s'", filename); - IFFParser iff(*stream); - Common::IFFChunk *chunk = 0; - - TIM *tim = new TIM; - assert(tim); - memset(tim, 0, sizeof(TIM)); + _avtlChunkSize = 0; + _filename = filename; - tim->procFunc = -1; - tim->opcodes = opcodes; + _tim = new TIM; + assert(_tim); + memset(_tim, 0, sizeof(TIM)); - int avtlChunkSize = 0; - - while ((chunk = iff.nextChunk()) != 0) { - switch (chunk->id) { - case MKID_BE('TEXT'): - tim->text = new byte[chunk->size]; - assert(tim->text); - if (chunk->read(tim->text, chunk->size) != chunk->size) - error("Couldn't read TEXT chunk from file '%s'", filename); - break; - - case MKID_BE('AVTL'): - avtlChunkSize = chunk->size >> 1; - tim->avtl = new uint16[avtlChunkSize]; - assert(tim->avtl); - if (chunk->read(tim->avtl, chunk->size) != chunk->size) - error("Couldn't read AVTL chunk from file '%s'", filename); - - for (int i = avtlChunkSize - 1; i >= 0; --i) - tim->avtl[i] = READ_LE_UINT16(&tim->avtl[i]); - break; + _tim->procFunc = -1; + _tim->opcodes = opcodes; - default: - warning("Unexpected chunk '%s' of size %d found in file '%s'", Common::ID2string(chunk->id), chunk->size, filename); - } - } + IFFParser iff(*stream); + Common::Functor1Mem< Common::IFFChunk &, bool, TIMInterpreter > c(this, &TIMInterpreter::callback); + iff.parse(c); - if (!tim->avtl) + if (!_tim->avtl) error("No AVTL chunk found in file: '%s'", filename); if (stream->err()) @@ -169,17 +173,17 @@ TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpc delete stream; - int num = (avtlChunkSize < TIM::kCountFuncs) ? avtlChunkSize : (int)TIM::kCountFuncs; + int num = (_avtlChunkSize < TIM::kCountFuncs) ? _avtlChunkSize : (int)TIM::kCountFuncs; for (int i = 0; i < num; ++i) - tim->func[i].avtl = tim->avtl + tim->avtl[i]; + _tim->func[i].avtl = _tim->avtl + _tim->avtl[i]; - strncpy(tim->filename, filename, 13); - tim->filename[12] = 0; + strncpy(_tim->filename, filename, 13); + _tim->filename[12] = 0; - tim->isLoLOutro = (_vm->gameFlags().gameID == GI_LOL) && !scumm_stricmp(filename, "LOLFINAL.TIM"); - tim->lolCharacter = 0; + _tim->isLoLOutro = (_vm->gameFlags().gameID == GI_LOL) && !scumm_stricmp(filename, "LOLFINAL.TIM"); + _tim->lolCharacter = 0; - return tim; + return _tim; } void TIMInterpreter::unload(TIM *&tim) const { @@ -300,13 +304,15 @@ void TIMInterpreter::displayText(uint16 textId, int16 flags) { memcpy(filename, text+1, end-1-text); } - if (filename[0]) + const bool isPC98 = (_vm->gameFlags().platform == Common::kPlatformPC98); + if (filename[0] && (_vm->speechEnabled() || isPC98)) _vm->sound()->voicePlay(filename); if (text[0] == '$') text = strchr(text + 1, '$') + 1; - setupTextPalette((flags < 0) ? 1 : flags, 0); + if (!isPC98) + 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 }; @@ -324,7 +330,7 @@ void TIMInterpreter::displayText(uint16 textId, int16 flags) { char *str = text; int heightAdd = 0; - while (str[0]) { + while (str[0] && _vm->textEnabled()) { char *nextLine = strchr(str, '\r'); backupChar = 0; @@ -335,10 +341,16 @@ void TIMInterpreter::displayText(uint16 textId, int16 flags) { int width = _screen->getTextWidth(str); - if (flags >= 0) - _screen->printText(str, (320 - width) >> 1, 160 + heightAdd, 0xF0, 0x00); - else + if (flags >= 0) { + if (isPC98) { + static const uint8 colorMap[] = { 0xE1, 0xE1, 0xC1, 0xA1, 0x81, 0x61 }; + _screen->printText(str, (320 - width) >> 1, 160 + heightAdd, colorMap[flags], 0x00); + } else { + _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); @@ -423,7 +435,7 @@ void TIMInterpreter::setupTextPalette(uint index, int fadePalette) { }; for (int i = 0; i < 15; ++i) { - uint8 *palette = _screen->getPalette(0) + (240 + i) * 3; + uint8 *palette = _screen->getPalette(0).getData() + (240 + i) * 3; uint8 c1 = (((15 - i) << 2) * palTable[index*3+0]) / 100; uint8 c2 = (((15 - i) << 2) * palTable[index*3+1]) / 100; @@ -471,10 +483,10 @@ TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char if (isLoLDemo) anim->wsa = new WSAMovie_v1(_vm); else - anim->wsa = new WSAMovie_v2(_vm, _screen); + anim->wsa = new WSAMovie_v2(_vm); assert(anim->wsa); - anim->wsa->open(file, wsaOpenFlags, (index == 1) ? _screen->getPalette(0) : 0); + anim->wsa->open(file, wsaOpenFlags, (index == 1) ? &_screen->getPalette(0) : 0); } if (anim->wsa && anim->wsa->opened()) { @@ -511,14 +523,14 @@ TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char snprintf(file, 32, "%s.CPS", filename); if (_vm->resource()->exists(file)) { - _screen->loadBitmap(file, 3, 3, _screen->getPalette(0)); + _screen->loadBitmap(file, 3, 3, &_screen->getPalette(0)); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, _drawPage2, Screen::CR_NO_P_CHECK); if (_drawPage2) _screen->checkedPageUpdate(8, 4); _screen->updateScreen(); } - anim->wsa->displayFrame(0, 0, x, y, 0); + anim->wsa->displayFrame(0, 0, x, y, 0, 0, 0); } if (wsaFlags & 2) @@ -535,7 +547,7 @@ TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char snprintf(file, 32, "%s.CPS", filename); if (_vm->resource()->exists(file)) { - _screen->loadBitmap(file, 3, 3, _screen->getPalette(0)); + _screen->loadBitmap(file, 3, 3, &_screen->getPalette(0)); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, _drawPage2, Screen::CR_NO_P_CHECK); if (_drawPage2) _screen->checkedPageUpdate(8, 4); @@ -941,21 +953,21 @@ TIMInterpreter::Animation *TIMInterpreter_LoL::initAnimStruct(int index, const c snprintf(file, 32, "%s.WSA", filename); if (_vm->resource()->exists(file)) { - anim->wsa = new WSAMovie_v2(_vm, TIMInterpreter::_screen); + anim->wsa = new WSAMovie_v2(_vm); assert(anim->wsa); - anim->wsa->open(file, wsaOpenFlags, _screen->getPalette(3)); + anim->wsa->open(file, wsaOpenFlags, &_screen->getPalette(3)); } if (wsaFlags & 1) { if (_screen->_fadeFlag != 1) _screen->fadeClearSceneWindow(10); - memcpy(_screen->getPalette(3) + 384, _screen->_currentPalette + 384, 384); + _screen->getPalette(3).copy(_screen->getPalette(0), 128, 128); } else if (wsaFlags & 2) { _screen->fadeToBlack(10); } if (wsaFlags & 7) - anim->wsa->displayFrame(0, 0, x, y, 0); + anim->wsa->displayFrame(0, 0, x, y, 0, 0, 0); if (wsaFlags & 3) { _screen->loadSpecialColors(_screen->getPalette(3)); @@ -1000,7 +1012,7 @@ void TIMInterpreter_LoL::advanceToOpcode(int opcode) { void TIMInterpreter_LoL::drawDialogueBox(int numStr, const char *s1, const char *s2, const char *s3) { _screen->setScreenDim(5); - if (numStr == 1 && _vm->_speechFlag) { + if (numStr == 1 && _vm->speechEnabled()) { _dialogueNumButtons = 0; _dialogueButtonString[0] = _dialogueButtonString[1] = _dialogueButtonString[2] = 0; } else { @@ -1051,7 +1063,7 @@ void TIMInterpreter_LoL::startBackgroundAnimation(int animIndex, int part) { // WORKAROUND for some bugged scripts that will try to display frames of non-existent animations if (anim->wsa) - anim->wsa->displayFrame(anim->curFrame - 1, 0, anim->x, anim->y, 0); + anim->wsa->displayFrame(anim->curFrame - 1, 0, anim->x, anim->y, 0, 0, 0); } void TIMInterpreter_LoL::stopBackgroundAnimation(int animIndex) { @@ -1110,7 +1122,7 @@ void TIMInterpreter_LoL::updateBackgroundAnimation(int animIndex) { anim->nextFrame += (anim->frameDelay * _vm->_tickLength); - anim->wsa->displayFrame(anim->curFrame - 1, 0, anim->x, anim->y, 0); + anim->wsa->displayFrame(anim->curFrame - 1, 0, anim->x, anim->y, 0, 0, 0); anim->nextFrame += _system->getMillis(); } @@ -1126,10 +1138,12 @@ void TIMInterpreter_LoL::playAnimationPart(int animIndex, int firstFrame, int la _screen->copyRegion(112, 0, 112, 0, 176, 120, 2, 0); _screen->updateScreen(); } else { - anim->wsa->displayFrame(i - 1, 0, anim->x, anim->y, 0); + anim->wsa->displayFrame(i - 1, 0, anim->x, anim->y, 0, 0, 0); _screen->updateScreen(); } - _vm->delayUntil(next); + int32 del = (int32)(next - _system->getMillis()); + if (del > 0) + _vm->delay(del, true); } } @@ -1162,7 +1176,8 @@ uint16 TIMInterpreter_LoL::processDialogue() { int x = _dialogueButtonPosX; for (int i = 0; i < _dialogueNumButtons; i++) { - if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, x, _dialogueButtonPosY, x + 74, _dialogueButtonPosY + 9)) { + Common::Point p = _vm->getMousePos(); + if (_vm->posWithinRect(p.x, p.y, x, _dialogueButtonPosY, x + 74, _dialogueButtonPosY + 9)) { _dialogueHighlightedButton = i; break; } @@ -1222,7 +1237,8 @@ uint16 TIMInterpreter_LoL::processDialogue() { x = _dialogueButtonPosX; for (int i = 0; i < _dialogueNumButtons; i++) { - if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, x, _dialogueButtonPosY, x + 74, _dialogueButtonPosY + 9)) { + Common::Point p = _vm->getMousePos(); + if (_vm->posWithinRect(p.x, p.y, x, _dialogueButtonPosY, x + 74, _dialogueButtonPosY + 9)) { _dialogueHighlightedButton = i; res = _dialogueHighlightedButton + 1; break; diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h index 10337b4b09..40049c3dec 100644 --- a/engines/kyra/script_tim.h +++ b/engines/kyra/script_tim.h @@ -121,6 +121,8 @@ public: TIM *load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes); void unload(TIM *&tim) const; + bool callback(Common::IFFChunk &chunk); + virtual Animation *initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags); virtual int freeAnimStruct(int index); @@ -169,6 +171,11 @@ protected: bool _finished; + // used when loading + int _avtlChunkSize; + const char *_filename; + TIM *_tim; + Common::String _vocFiles[120]; Animation *_animations; diff --git a/engines/kyra/seqplayer.cpp b/engines/kyra/seqplayer.cpp index 54d6f2cbe3..2145591c03 100644 --- a/engines/kyra/seqplayer.cpp +++ b/engines/kyra/seqplayer.cpp @@ -92,7 +92,7 @@ uint8 *SeqPlayer::setPanPages(int pageNum, int shape) { } void SeqPlayer::makeHandShapes() { - _screen->loadBitmap("WRITING.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("WRITING.CPS", 3, 3, &_screen->getPalette(0)); if (_vm->gameFlags().platform == Common::kPlatformMacintosh || _vm->gameFlags().platform == Common::kPlatformAmiga) { freeHandShapes(); @@ -148,7 +148,7 @@ void SeqPlayer::s1_wsaPlayFrame() { _seqMovies[wsaObj].pos.x = READ_LE_UINT16(_seqData); _seqData += 2; _seqMovies[wsaObj].pos.y = *_seqData++; assert(_seqMovies[wsaObj].movie); - _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y); + _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, 0, 0); _seqMovies[wsaObj].frame = frame; } @@ -160,7 +160,7 @@ void SeqPlayer::s1_wsaPlayNextFrame() { frame = 0; _seqMovies[wsaObj].frame = 0; } - _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y); + _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, 0, 0); } void SeqPlayer::s1_wsaPlayPrevFrame() { @@ -171,7 +171,7 @@ void SeqPlayer::s1_wsaPlayPrevFrame() { frame = _seqMovies[wsaObj].numFrames; _seqMovies[wsaObj].frame = frame; } else { - _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y); + _seqMovies[wsaObj].movie->displayFrame(frame, _seqMovies[wsaObj].page, _seqMovies[wsaObj].pos.x, _seqMovies[wsaObj].pos.y, 0, 0, 0); } } @@ -194,21 +194,18 @@ void SeqPlayer::s1_copyWaitTicks() { void SeqPlayer::s1_shuffleScreen() { _screen->shuffleScreen(0, 16, 320, 128, 2, 0, 0, false); - _screen->_curPage = 2; if (_specialBuffer) - _screen->copyCurPageBlock(0, 16, 40, 128, _specialBuffer); + _screen->copyRegionToBuffer(2, 0, 16, 320, 128, _specialBuffer); _screen->_curPage = 0; } void SeqPlayer::s1_copyView() { - int y = 128; - if (!_copyViewOffs) - y -= 8; + int h = !_copyViewOffs ? 120 : 128; if (_specialBuffer && !_copyViewOffs) - _screen->copyToPage0(16, y, 3, _specialBuffer); + _screen->copyToPage0(16, h, 3, _specialBuffer); else - _screen->copyRegion(0, 16, 0, 16, 320, y, 2, 0); + _screen->copyRegion(0, 16, 0, 16, 320, h, 2, 0); } void SeqPlayer::s1_loopInit() { @@ -244,25 +241,21 @@ void SeqPlayer::s1_loadPalette() { if (_vm->gameFlags().platform == Common::kPlatformAmiga) { if (!colNum) - memcpy(_screen->_currentPalette, _screen->_currentPalette + 576, 3*32); + _screen->copyPalette(0, 6); else if (colNum == 3) - memcpy(_screen->_currentPalette, _screen->_currentPalette + 672, 3*32); + _screen->copyPalette(0, 7); else if (colNum == 4) - memcpy(_screen->_currentPalette, _screen->_currentPalette + 288, 3*32); + _screen->copyPalette(0, 3); - _screen->setScreenPalette(_screen->_currentPalette); + _screen->setScreenPalette(_screen->getPalette(0)); } else { - uint32 fileSize; - uint8 *srcData; - srcData = _res->fileData(_vm->seqCOLTable()[colNum], &fileSize); - memcpy(_screen->_currentPalette, srcData, fileSize); - delete[] srcData; + _screen->loadPalette(_vm->seqCOLTable()[colNum], _screen->getPalette(0)); } } void SeqPlayer::s1_loadBitmap() { uint8 cpsNum = *_seqData++; - _screen->loadBitmap(_vm->seqCPSTable()[cpsNum], 3, 3, _screen->_currentPalette); + _screen->loadBitmap(_vm->seqCPSTable()[cpsNum], 3, 3, &_screen->getPalette(0)); } void SeqPlayer::s1_fadeToBlack() { @@ -449,10 +442,7 @@ void SeqPlayer::s1_allocTempBuffer() { if (!_specialBuffer && !_copyViewOffs) { _specialBuffer = new uint8[40960]; assert(_specialBuffer); - int page = _screen->_curPage; - _screen->_curPage = 0; - _screen->copyCurPageBlock(0, 0, 320, 128, _specialBuffer); - _screen->_curPage = page; + _screen->copyRegionToBuffer(2, 0, 16, 320, 128, _specialBuffer); } } } diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp index 4e53399fbf..90b2fdd580 100644 --- a/engines/kyra/sequences_hof.cpp +++ b/engines/kyra/sequences_hof.cpp @@ -62,7 +62,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { int oldPage = _screen->setCurPage(2); for (int i = 0; i < 4; ++i) - memset(_screen->getPalette(i), 0, 0x300); + _screen->getPalette(i).clear(); _screen->clearPage(10); _screen->clearPage(12); @@ -77,7 +77,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { for (int seqNum = startSeq; seqNum <= endSeq && !((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice); seqNum++) { _screen->clearPage(0); _screen->clearPage(8); - memcpy(_screen->getPalette(1), _screen->getPalette(0), 0x300); + _screen->copyPalette(1, 0); _seqFrameCounter = 0; _seqStartTime = _system->getMillis(); @@ -87,7 +87,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { SeqProc cb = _callbackS[seqNum]; if (cseq.flags & 2) { - _screen->loadBitmap(cseq.cpsFile, 2, 2, _screen->getPalette(0)); + _screen->loadBitmap(cseq.cpsFile, 2, 2, &_screen->getPalette(0)); _screen->setScreenPalette(_screen->getPalette(0)); } else { _screen->setCurPage(2); @@ -100,9 +100,9 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { if (cseq.flags & 1) { _seqWsa->close(); - _seqWsa->open(cseq.wsaFile, 0, _screen->getPalette(0)); + _seqWsa->open(cseq.wsaFile, 0, &_screen->getPalette(0)); _screen->setScreenPalette(_screen->getPalette(0)); - _seqWsa->displayFrame(0, 2, cseq.xPos, cseq.yPos, 0); + _seqWsa->displayFrame(0, 2, cseq.xPos, cseq.yPos, 0, 0, 0); } if (cseq.flags & 4) { @@ -174,7 +174,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) { if (_seqWsa) { int f = _seqWsaCurrentFrame % _seqWsa->frames(); - _seqWsa->displayFrame(f, 2, cseq.xPos, cseq.yPos, 0); + _seqWsa->displayFrame(f, 2, cseq.xPos, cseq.yPos, 0, 0, 0); } _screen->copyPage(2, 12); @@ -361,7 +361,7 @@ int KyraEngine_HoF::seq_introTitle(WSAMovie_v2 *wsaObj, int x, int y, int frm) { } int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint8 *tmpPal = &(_screen->getPalette(3)[0x101]); + uint8 *tmpPal = _screen->getPalette(3).getData() + 0x101; memset(tmpPal, 0, 256); _seqSubFrameEndTimeInternal = 0; uint32 now = 0; @@ -372,9 +372,9 @@ int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm _sound->playTrack(4); _seqSubFrameEndTimeInternal = _system->getMillis() + 60 * _tickLength; - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); - _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff; _screen->setTextColorMap(_seqTextColorMap); @@ -384,7 +384,7 @@ int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm break; case 1: - _screen->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3), 0x40, 0, 0, 0, 0x100, true); + _screen->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x40, 0, 0, 0, 0x100, true); for (int i = 0; i < 256; i++) tmpPal[_screen->getPalette(3)[i]] = 1; @@ -417,7 +417,7 @@ int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm case 201: _screen->setScreenPalette(_screen->getPalette(2)); _screen->updateScreen(); - _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3)); + _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3).getData()); _screen->copyPage(2, 12); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0); _screen->setScreenPalette(_screen->getPalette(0)); @@ -465,10 +465,10 @@ int KyraEngine_HoF::seq_introLibrary(WSAMovie_v2 *wsaObj, int x, int y, int frm) _seqSubframePlaying = true; _sound->playTrack(5); - _screen->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3), 0x24, 0, 0, 0, 0x100, false); - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _screen->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false); + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); - _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff; _screen->setTextColorMap(_seqTextColorMap); break; @@ -482,7 +482,7 @@ int KyraEngine_HoF::seq_introLibrary(WSAMovie_v2 *wsaObj, int x, int y, int frm) seq_waitForTextsTimeout(); _screen->copyPage(12, 2); - _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3)); + _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3).getData()); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0); _screen->updateScreen(); _screen->copyPage(2, 12); @@ -503,7 +503,7 @@ int KyraEngine_HoF::seq_introLibrary(WSAMovie_v2 *wsaObj, int x, int y, int frm) case 340: seq_resetActiveWSA(0); - _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3)); + _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3).getData()); _screen->copyPage(2, 12); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0); _screen->updateScreen(); @@ -539,10 +539,10 @@ int KyraEngine_HoF::seq_introHand(WSAMovie_v2 *wsaObj, int x, int y, int frm) { _seqSubframePlaying = true; _sound->playTrack(6); - _screen->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3), 0x24, 0, 0, 0, 0x100, false); - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _screen->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false); + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); - _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff; _screen->setTextColorMap(_seqTextColorMap); break; @@ -556,7 +556,7 @@ int KyraEngine_HoF::seq_introHand(WSAMovie_v2 *wsaObj, int x, int y, int frm) { case 201: seq_waitForTextsTimeout(); - _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3)); + _screen->applyOverlay(0, 0, 320, 200, 2, _screen->getPalette(3).getData()); _screen->copyPage(2, 12); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0); _screen->updateScreen(); @@ -631,9 +631,9 @@ int KyraEngine_HoF::seq_introPoint(WSAMovie_v2 *wsaObj, int x, int y, int frm) { _seqTextColor[1] = 0xf7; memset(_seqTextColorMap, _seqTextColor[1], 16); - _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff; _screen->setTextColorMap(_seqTextColorMap); - _screen->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3), 0x24, 0, 0, 0, 0x100, false); + _screen->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false); break; case 1: @@ -661,7 +661,7 @@ int KyraEngine_HoF::seq_introZanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm) _seqTextColor[1] = 0xfd; memset(_seqTextColorMap, _seqTextColor[1], 16); - _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff; _screen->setTextColorMap(_seqTextColorMap); break; @@ -831,7 +831,7 @@ int KyraEngine_HoF::seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm case 0: _sound->playTrack(3); - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); _seqTextColor[0] = _seqTextColorMap[1] = 0xff; _screen->setTextColorMap(_seqTextColorMap); @@ -924,7 +924,7 @@ int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) { break; case 0: - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); _seqTextColor[0] = _seqTextColorMap[1] = 255; _screen->setTextColorMap(_seqTextColorMap); @@ -1006,7 +1006,7 @@ int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) { break; case 0: - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); _seqTextColor[0] = _seqTextColorMap[1] = 0xff; _screen->setTextColorMap(_seqTextColorMap); @@ -1096,7 +1096,7 @@ int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) break; case 0: - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); _seqTextColor[0] = _seqTextColorMap[1] = 0xff; _screen->setTextColorMap(_seqTextColorMap); @@ -1172,9 +1172,9 @@ int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) break; case 0: - _seqTextColor[1] = 1 + (_screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 254) & 0xff); + _seqTextColor[1] = 1 + (_screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 254) & 0xff); memset(_seqTextColorMap, _seqTextColor[1], 16); - _seqTextColorMap[1] = _seqTextColor[0] = 1 + (_screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0) + 3, 254) & 0xff); + _seqTextColorMap[1] = _seqTextColor[0] = 1 + (_screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0), 1, 254) & 0xff); _screen->setTextColorMap(_seqTextColorMap); seq_playTalkText(_flags.isTalkie ? 30 : 26); break; @@ -1339,7 +1339,7 @@ int KyraEngine_HoF::seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm break; case 0: - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); _seqTextColor[0] = _seqTextColorMap[1] = 0xff; _screen->setTextColorMap(_seqTextColorMap); @@ -1426,7 +1426,7 @@ int KyraEngine_HoF::seq_finaleFrash(WSAMovie_v2 *wsaObj, int x, int y, int frm) case 0: if (_seqFrameCounter == 1) { _sound->playTrack(4); - _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff; + _seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff; memset(_seqTextColorMap, _seqTextColor[1], 16); _seqTextColor[0] = _seqTextColorMap[1] = 0xff; _screen->setTextColorMap(_seqTextColorMap); @@ -1501,7 +1501,7 @@ void KyraEngine_HoF::seq_finaleActorScreen() { static const uint8 colormap[] = {0, 0, 102, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const ScreenDim d = { 0x00, 0x0C, 0x28, 0xB4, 0xFF, 0x00, 0x00, 0x00 }; - _screen->loadBitmap("finale.cps", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("finale.cps", 3, 3, &_screen->getPalette(0)); _screen->setFont(Screen::FID_GOLDFONT_FNT); int talkieCreditsSize, talkieCreditsSpecialSize; @@ -1781,19 +1781,21 @@ int KyraEngine_HoF::seq_demoDig(WSAMovie_v2 *wsaObj, int x, int y, int frm) { #ifdef ENABLE_LOL int KyraEngine_HoF::seq_lolDemoScene1(WSAMovie_v2 *wsaObj, int x, int y, int frm) { - uint8 *tmpPal = _screen->getPalette(2); + Palette &tmpPal = _screen->getPalette(2); if (!(_seqFrameCounter % 100)) { if (_seqFrameCounter == 0) { _sound->haltTrack(); _sound->playTrack(6); } - memcpy(tmpPal, _screen->getPalette(0), 0x300); + tmpPal.copy(_screen->getPalette(0)); + for (int i = 3; i < 0x300; i++) { tmpPal[i] = ((int)tmpPal[i] * 120) / 64; if (tmpPal[i] > 0x3f) tmpPal[i] = 0x3f; } + seq_playTalkText(_rnd.getRandomBit()); _screen->setScreenPalette(tmpPal); _screen->updateScreen(); @@ -1926,13 +1928,15 @@ int KyraEngine_HoF::seq_lolDemoScene6(WSAMovie_v2 *wsaObj, int x, int y, int frm if (_seqFrameCounter % 175) { _screen->setScreenPalette(_screen->getPalette(0)); } else { - uint8 *tmpPal = _screen->getPalette(2); - memcpy(tmpPal, _screen->getPalette(0), 0x300); + Palette &tmpPal = _screen->getPalette(2); + tmpPal.copy(_screen->getPalette(0)); + for (int i = 3; i < 0x300; i++) { tmpPal[i] = ((int)tmpPal[i] * 120) / 64; if (tmpPal[i] > 0x3f) tmpPal[i] = 0x3f; } + seq_playTalkText(_rnd.getRandomBit()); _screen->setScreenPalette(tmpPal); _screen->updateScreen(); @@ -2045,37 +2049,35 @@ char *KyraEngine_HoF::seq_preprocessString(const char *srcStr, int width) { } void KyraEngine_HoF::seq_sequenceCommand(int command) { - uint8 pal[768]; - for (int i = 0; i < 8; i++) seq_resetActiveWSA(i); switch (command) { case 0: - memset(pal, 0, 0x300); - _screen->fadePalette(pal, 36); - memcpy(_screen->getPalette(0), pal, 0x300); - memcpy(_screen->getPalette(1), pal, 0x300); + _screen->fadeToBlack(36); + _screen->getPalette(0).clear(); + _screen->getPalette(1).clear(); break; case 1: - memset(pal, 0x3F, 0x300); seq_playTalkText(_rnd.getRandomBit()); - _screen->fadePalette(pal, 16); - memcpy(_screen->getPalette(0), pal, 0x300); - memcpy(_screen->getPalette(1), pal, 0x300); + + _screen->getPalette(0).fill(0, 256, 0x3F); + _screen->fadePalette(_screen->getPalette(0), 16); + + _screen->copyPalette(1, 0); break; case 3: _screen->copyPage(2, 0); _screen->fadePalette(_screen->getPalette(0), 16); - memcpy(_screen->getPalette(1), _screen->getPalette(0), 0x300); + _screen->copyPalette(1, 0); break; case 4: _screen->copyPage(2, 0); _screen->fadePalette(_screen->getPalette(0), 36); - memcpy(_screen->getPalette(1), _screen->getPalette(0), 0x300); + _screen->copyPalette(1, 0); break; case 5: @@ -2093,17 +2095,17 @@ void KyraEngine_HoF::seq_sequenceCommand(int command) { break; case 8: - memset(pal, 0, 0x300); - _screen->fadePalette(pal, 16); - memcpy(_screen->getPalette(0), pal, 0x300); - memcpy(_screen->getPalette(1), pal, 0x300); + _screen->fadeToBlack(16); + _screen->getPalette(0).clear(); + _screen->getPalette(1).clear(); delay(120 * _tickLength); break; - case 9: - for (int i = 0; i < 0x100; i++) { - int pv = (_screen->getPalette(0)[3 * i] + _screen->getPalette(0)[3 * i + 1] + _screen->getPalette(0)[3 * i + 2]) / 3; + case 9: { + Palette &pal = _screen->getPalette(0); + for (int i = 0; i < 256; i++) { + int pv = (pal[3 * i] + pal[3 * i + 1] + pal[3 * i + 2]) / 3; pal[3 * i] = pal[3 * i + 1] = pal[3 * i + 2] = pv & 0xff; } @@ -2112,9 +2114,8 @@ void KyraEngine_HoF::seq_sequenceCommand(int command) { //pal[3 * i] = pal[3 * i + 1] = pal[3 * i + 2] = 0x3f; _screen->fadePalette(pal, 64); - memcpy(_screen->getPalette(0), pal, 0x300); - memcpy(_screen->getPalette(1), pal, 0x300); - break; + _screen->copyPalette(1, 0); + } break; default: break; @@ -2201,7 +2202,7 @@ void KyraEngine_HoF::seq_loadNestedSequence(int wsaNum, int seqNum) { NestedSequence s = _sequences->seqn[seqNum]; if (!_activeWSA[wsaNum].movie) { - _activeWSA[wsaNum].movie = new WSAMovie_v2(this, _screen); + _activeWSA[wsaNum].movie = new WSAMovie_v2(this); assert(_activeWSA[wsaNum].movie); } @@ -2246,7 +2247,7 @@ void KyraEngine_HoF::seq_nestedSequenceFrame(int command, int wsaNum) { case 0: xa = -_activeWSA[wsaNum].movie->xAdd(); ya = -_activeWSA[wsaNum].movie->yAdd(); - _activeWSA[wsaNum].movie->displayFrame(0, 8, xa, ya, 0); + _activeWSA[wsaNum].movie->displayFrame(0, 8, xa, ya, 0, 0, 0); seq_animatedSubFrame(8, 2, 7, 8, _activeWSA[wsaNum].movie->xAdd(), _activeWSA[wsaNum].movie->yAdd(), _activeWSA[wsaNum].movie->width(), _activeWSA[wsaNum].movie->height(), 1, 2); break; @@ -2254,7 +2255,7 @@ void KyraEngine_HoF::seq_nestedSequenceFrame(int command, int wsaNum) { case 1: xa = -_activeWSA[wsaNum].movie->xAdd(); ya = -_activeWSA[wsaNum].movie->yAdd(); - _activeWSA[wsaNum].movie->displayFrame(0, 8, xa, ya, 0); + _activeWSA[wsaNum].movie->displayFrame(0, 8, xa, ya, 0, 0, 0); seq_animatedSubFrame(8, 2, 7, 8, _activeWSA[wsaNum].movie->xAdd(), _activeWSA[wsaNum].movie->yAdd(), _activeWSA[wsaNum].movie->width(), _activeWSA[wsaNum].movie->height(), 1, 1); break; @@ -2263,21 +2264,21 @@ void KyraEngine_HoF::seq_nestedSequenceFrame(int command, int wsaNum) { seq_waitForTextsTimeout(); xa = -_activeWSA[wsaNum].movie->xAdd(); ya = -_activeWSA[wsaNum].movie->yAdd(); - _activeWSA[wsaNum].movie->displayFrame(0x15, 8, xa, ya, 0); + _activeWSA[wsaNum].movie->displayFrame(0x15, 8, xa, ya, 0, 0, 0); seq_animatedSubFrame(8, 2, 7, 8, _activeWSA[wsaNum].movie->xAdd(), _activeWSA[wsaNum].movie->yAdd(), _activeWSA[wsaNum].movie->width(), _activeWSA[wsaNum].movie->height(), 0, 2); break; case 3: _screen->copyPage(2, 10); - _activeWSA[wsaNum].movie->displayFrame(0, 2, 0, 0, 0); + _activeWSA[wsaNum].movie->displayFrame(0, 2, 0, 0, 0, 0, 0); _screen->copyPage(2, 12); seq_cmpFadeFrame("scene2.cmp"); break; case 4: _screen->copyPage(2, 10); - _activeWSA[wsaNum].movie->displayFrame(0, 2, 0, 0, 0); + _activeWSA[wsaNum].movie->displayFrame(0, 2, 0, 0, 0, 0, 0); _screen->copyPage(2, 12); seq_cmpFadeFrame("scene3.cmp"); break; @@ -2364,10 +2365,10 @@ bool KyraEngine_HoF::seq_processNextSubFrame(int wsaNum) { if (_activeWSA[wsaNum].movie) { if (_activeWSA[wsaNum].flags & 0x20) { - _activeWSA[wsaNum].movie->displayFrame(_activeWSA[wsaNum].control[currentFrame].index, 2, _activeWSA[wsaNum].x, _activeWSA[wsaNum].y, 0x4000); + _activeWSA[wsaNum].movie->displayFrame(_activeWSA[wsaNum].control[currentFrame].index, 2, _activeWSA[wsaNum].x, _activeWSA[wsaNum].y, 0x4000, 0, 0); _activeWSA[wsaNum].frameDelay = _activeWSA[wsaNum].control[currentFrame].delay; } else { - _activeWSA[wsaNum].movie->displayFrame(currentFrame % _activeWSA[wsaNum].movie->frames(), 2, _activeWSA[wsaNum].x, _activeWSA[wsaNum].y, 0x4000); + _activeWSA[wsaNum].movie->displayFrame(currentFrame % _activeWSA[wsaNum].movie->frames(), 2, _activeWSA[wsaNum].x, _activeWSA[wsaNum].y, 0x4000, 0, 0); } } @@ -2477,7 +2478,7 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i _seqWsaChatFrameTimeout = _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength; if (wsa) - wsa->displayFrame(curframe % wsa->frames(), 2, wsaXpos, wsaYpos, 0); + wsa->displayFrame(curframe % wsa->frames(), 2, wsaXpos, wsaYpos, 0, 0, 0); _screen->copyPage(2, 12); @@ -2663,9 +2664,9 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int if (palCycle) { for (int col = 133; col > 112; col--) - memcpy(_screen->_currentPalette + (col * 3), _screen->_currentPalette + ((col - 1) * 3), 3); - memcpy(_screen->_currentPalette + 336, _screen->_currentPalette + 399, 3); - _screen->setScreenPalette(_screen->_currentPalette); + _screen->getPalette(0).copy(_screen->getPalette(0), col - 1, 1, col); + _screen->getPalette(0).copy(_screen->getPalette(0), 133, 1, 112); + _screen->setScreenPalette(_screen->getPalette(0)); } delayUntil(_seqSubFrameEndTimeInternal); @@ -2721,32 +2722,32 @@ void KyraEngine_HoF::seq_scrollPage(int bottom, int top) { } void KyraEngine_HoF::seq_showStarcraftLogo() { - WSAMovie_v2 *ci = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *ci = new WSAMovie_v2(this); assert(ci); _screen->clearPage(2); _res->loadPakFile("INTROGEN.PAK"); - int endframe = ci->open("ci.wsa", 0, _screen->_currentPalette); + int endframe = ci->open("ci.wsa", 0, &_screen->getPalette(0)); _res->unloadPakFile("INTROGEN.PAK"); if (!ci->opened()) { delete ci; return; } _screen->hideMouse(); - ci->displayFrame(0, 2, 0, 0, 0); + ci->displayFrame(0, 2, 0, 0, 0, 0, 0); _screen->copyPage(2, 0); _screen->fadeFromBlack(); for (int i = 1; i < endframe; i++) { _seqEndTime = _system->getMillis() + 50; if (skipFlag()) break; - ci->displayFrame(i, 2, 0, 0, 0); + ci->displayFrame(i, 2, 0, 0, 0, 0, 0); _screen->copyPage(2, 0); _screen->updateScreen(); delay(_seqEndTime - _system->getMillis()); } if (!skipFlag()) { _seqEndTime = _system->getMillis() + 50; - ci->displayFrame(0, 2, 0, 0, 0); + ci->displayFrame(0, 2, 0, 0, 0, 0, 0); _screen->copyPage(2, 0); _screen->updateScreen(); delay(_seqEndTime - _system->getMillis()); @@ -2760,7 +2761,7 @@ void KyraEngine_HoF::seq_showStarcraftLogo() { void KyraEngine_HoF::seq_init() { _seqProcessedString = new char[200]; - _seqWsa = new WSAMovie_v2(this, _screen); + _seqWsa = new WSAMovie_v2(this); _activeWSA = new ActiveWSA[8]; _activeText = new ActiveText[10]; diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp index 12ede98ad4..d483409090 100644 --- a/engines/kyra/sequences_lok.cpp +++ b/engines/kyra/sequences_lok.cpp @@ -42,7 +42,7 @@ namespace Kyra { void KyraEngine_LoK::seq_demo() { snd_playTheme(0, 2); - _screen->loadBitmap("START.CPS", 7, 7, _screen->_currentPalette); + _screen->loadBitmap("START.CPS", 7, 7, &_screen->getPalette(0)); _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0, Screen::CR_NO_P_CHECK); _screen->updateScreen(); _screen->fadeFromBlack(); @@ -50,8 +50,8 @@ void KyraEngine_LoK::seq_demo() { _screen->fadeToBlack(); _screen->clearPage(0); - _screen->loadBitmap("TOP.CPS", 7, 7, NULL); - _screen->loadBitmap("BOTTOM.CPS", 5, 5, _screen->_currentPalette); + _screen->loadBitmap("TOP.CPS", 7, 7, 0); + _screen->loadBitmap("BOTTOM.CPS", 5, 5, &_screen->getPalette(0)); _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 0); _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 0); _screen->updateScreen(); @@ -77,7 +77,7 @@ void KyraEngine_LoK::seq_demo() { _seq->playSequence(_seq_Demo4, true); _screen->clearPage(0); - _screen->loadBitmap("FINAL.CPS", 7, 7, _screen->_currentPalette); + _screen->loadBitmap("FINAL.CPS", 7, 7, &_screen->getPalette(0)); _screen->_curPage = 0; _screen->copyRegion(0, 0, 0, 0, 320, 200, 6, 0); _screen->updateScreen(); @@ -128,7 +128,7 @@ void KyraEngine_LoK::seq_intro() { void KyraEngine_LoK::seq_introLogos() { if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { - _screen->loadBitmap("LOGO.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("LOGO.CPS", 3, 3, &_screen->getPalette(0)); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0); _screen->updateScreen(); _screen->fadeFromBlack(); @@ -141,7 +141,7 @@ void KyraEngine_LoK::seq_introLogos() { _screen->clearPage(0); if (_flags.platform == Common::kPlatformAmiga) { - _screen->loadPalette("INTRO.PAL", _screen->_currentPalette); + _screen->loadPaletteTable("INTRO.PAL", 0); _screen->loadBitmap("BOTTOM.CPS", 3, 5, 0); _screen->loadBitmap("TOP.CPS", 3, 3, 0); _screen->copyRegion(0, 0, 0, 111, 320, 64, 2, 0); @@ -149,7 +149,7 @@ void KyraEngine_LoK::seq_introLogos() { _screen->copyRegion(0, 0, 0, 0, 320, 190, 0, 2); } else { _screen->loadBitmap("TOP.CPS", 7, 7, 0); - _screen->loadBitmap("BOTTOM.CPS", 5, 5, _screen->_currentPalette); + _screen->loadBitmap("BOTTOM.CPS", 5, 5, &_screen->getPalette(0)); _screen->copyRegion(0, 91, 0, 8, 320, 103, 6, 0); _screen->copyRegion(0, 0, 0, 111, 320, 64, 6, 0); } @@ -166,8 +166,8 @@ void KyraEngine_LoK::seq_introLogos() { delay(60 * _tickLength); if (_flags.platform == Common::kPlatformAmiga) { - memcpy(_screen->_currentPalette, _screen->_currentPalette + 3*32, 3*32); - _screen->setScreenPalette(_screen->_currentPalette); + _screen->copyPalette(0, 1); + _screen->setScreenPalette(_screen->getPalette(0)); } if ((_seq->playSequence(_seq_KyrandiaLogo, skipFlag()) && !seq_skipSequence()) || shouldQuit()) { @@ -181,7 +181,7 @@ void KyraEngine_LoK::seq_introLogos() { return; if (_flags.platform == Common::kPlatformAmiga) { - memcpy(_screen->_currentPalette, _screen->_currentPalette + 3*64, 3*32); + _screen->copyPalette(0, 2); _screen->fadeToBlack(); _screen->copyRegion(0, 0, 0, 0, 320, 200, 4, 0); _screen->fadeFromBlack(); @@ -236,22 +236,22 @@ void KyraEngine_LoK::seq_introStory() { return; if (_flags.lang == Common::EN_ANY && !_flags.isTalkie && (_flags.platform == Common::kPlatformPC || _flags.platform == Common::kPlatformAmiga)) - _screen->loadBitmap("TEXT.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("TEXT.CPS", 3, 3, &_screen->getPalette(0)); else if (_flags.lang == Common::EN_ANY || _flags.lang == Common::JA_JPN) - _screen->loadBitmap("TEXT_ENG.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("TEXT_ENG.CPS", 3, 3, &_screen->getPalette(0)); else if (_flags.lang == Common::DE_DEU) - _screen->loadBitmap("TEXT_GER.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("TEXT_GER.CPS", 3, 3, &_screen->getPalette(0)); else if (_flags.lang == Common::FR_FRA) - _screen->loadBitmap("TEXT_FRE.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("TEXT_FRE.CPS", 3, 3, &_screen->getPalette(0)); else if (_flags.lang == Common::ES_ESP) - _screen->loadBitmap("TEXT_SPA.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("TEXT_SPA.CPS", 3, 3, &_screen->getPalette(0)); else if (_flags.lang == Common::IT_ITA && !_flags.isTalkie) - _screen->loadBitmap("TEXT_ITA.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("TEXT_ITA.CPS", 3, 3, &_screen->getPalette(0)); else if (_flags.lang == Common::IT_ITA && _flags.isTalkie) - _screen->loadBitmap("TEXT_ENG.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("TEXT_ENG.CPS", 3, 3, &_screen->getPalette(0)); else warning("no story graphics file found"); - _screen->setScreenPalette(_screen->_currentPalette); + _screen->setScreenPalette(_screen->getPalette(0)); _screen->copyRegion(0, 0, 0, 0, 320, 200, 3, 0); if (_flags.lang == Common::JA_JPN) { @@ -569,12 +569,9 @@ void KyraEngine_LoK::seq_winterScroll1() { _sprites->_anims[i].play = false; _animator->sprites()[i].active = 0; } - uint8 tmpPal[768]; - memcpy(tmpPal, _screen->_currentPalette, 768); - memcpy(&tmpPal[684], palTable2()[0], 60); - _screen->fadePalette(tmpPal, 72); - memcpy(&_screen->_currentPalette[684], palTable2()[0], 60); - _screen->setScreenPalette(_screen->_currentPalette); + _screen->getPalette(0).copy(palTable2()[0], 0, 20, 228); + _screen->fadePalette(_screen->getPalette(0), 72); + _screen->setScreenPalette(_screen->getPalette(0)); setGameFlag(0xB3); } else { delayWithTicks(120); @@ -950,8 +947,8 @@ int KyraEngine_LoK::seq_playEnd() { _screen->hideMouse(); _screen->fadeSpecialPalette(32, 228, 20, 60); delay(60 * _tickLength); - _screen->loadBitmap("GEMHEAL.CPS", 3, 3, _screen->_currentPalette); - _screen->setScreenPalette(_screen->_currentPalette); + _screen->loadBitmap("GEMHEAL.CPS", 3, 3, &_screen->getPalette(0)); + _screen->setScreenPalette(_screen->getPalette(0)); _screen->shuffleScreen(8, 8, 304, 128, 2, 0, 1, 0); uint32 nextTime = _system->getMillis() + 120 * _tickLength; _finalA = new WSAMovie_v1(this); @@ -966,7 +963,7 @@ int KyraEngine_LoK::seq_playEnd() { else if (i == 20) snd_playSoundEffect(0x0E); nextTime = _system->getMillis() + 8 * _tickLength; - _finalA->displayFrame(i, 0, 8, 8); + _finalA->displayFrame(i, 0, 8, 8, 0, 0, 0); _screen->updateScreen(); } delete _finalA; @@ -1004,14 +1001,14 @@ void KyraEngine_LoK::seq_playEnding() { _screen->hideMouse(); _screen->_curPage = 0; _screen->fadeToBlack(); - _screen->loadBitmap("REUNION.CPS", 3, 3, _screen->_currentPalette); + _screen->loadBitmap("REUNION.CPS", 3, 3, &_screen->getPalette(0)); _screen->copyRegion(8, 8, 8, 8, 304, 128, 2, 0); _screen->_curPage = 0; // XXX assert(_homeString); drawSentenceCommand(_homeString[0], 179); - memset(_screen->getPalette(2), 0, sizeof(uint8)*768); + _screen->getPalette(2).clear(); _screen->setScreenPalette(_screen->getPalette(2)); _seqPlayerFlag = true; @@ -1045,7 +1042,7 @@ void KyraEngine_LoK::seq_playCredits() { } else _screen->setFont(Screen::FID_8_FNT); - _screen->loadBitmap("CHALET.CPS", 4, 4, _screen->_currentPalette); + _screen->loadBitmap("CHALET.CPS", 4, 4, &_screen->getPalette(0)); _screen->setCurPage(0); _screen->clearCurPage(); @@ -1123,10 +1120,10 @@ void KyraEngine_LoK::seq_playCredits() { _screen->setCurPage(2); - memset(_screen->getPalette(2), 0, sizeof(uint8)*768); + _screen->getPalette(2).clear(); _screen->setScreenPalette(_screen->getPalette(2)); _screen->copyRegion(8, 32, 8, 32, 312, 128, 4, 0, Screen::CR_NO_P_CHECK); - _screen->fadePalette(_screen->_currentPalette, 0x5A); + _screen->fadePalette(_screen->getPalette(0), 0x5A); Common::Event event; bool finished = false; @@ -1198,7 +1195,7 @@ int KyraEngine_LoK::handleMalcolmFlag() { case 2: if (_system->getMillis() >= timer2) { - _finalA->displayFrame(frame, 0, 8, 46); + _finalA->displayFrame(frame, 0, 8, 46, 0, 0, 0); _screen->updateScreen(); timer2 = _system->getMillis() + 8 * _tickLength; ++frame; @@ -1213,7 +1210,7 @@ int KyraEngine_LoK::handleMalcolmFlag() { if (_system->getMillis() < timer1) { if (_system->getMillis() >= timer2) { frame = _rnd.getRandomNumberRng(14, 17); - _finalA->displayFrame(frame, 0, 8, 46); + _finalA->displayFrame(frame, 0, 8, 46, 0, 0, 0); _screen->updateScreen(); timer2 = _system->getMillis() + 8 * _tickLength; } @@ -1225,7 +1222,7 @@ int KyraEngine_LoK::handleMalcolmFlag() { case 4: if (_system->getMillis() >= timer2) { - _finalA->displayFrame(frame, 0, 8, 46); + _finalA->displayFrame(frame, 0, 8, 46, 0, 0, 0); _screen->updateScreen(); timer2 = _system->getMillis() + 8 * _tickLength; ++frame; @@ -1239,7 +1236,7 @@ int KyraEngine_LoK::handleMalcolmFlag() { case 5: if (_system->getMillis() >= timer2) { - _finalA->displayFrame(frame, 0, 8, 46); + _finalA->displayFrame(frame, 0, 8, 46, 0, 0, 0); _screen->updateScreen(); timer2 = _system->getMillis() + 8 * _tickLength; ++frame; @@ -1253,7 +1250,7 @@ int KyraEngine_LoK::handleMalcolmFlag() { case 6: if (_unkEndSeqVar4) { if (frame <= 33 && _system->getMillis() >= timer2) { - _finalA->displayFrame(frame, 0, 8, 46); + _finalA->displayFrame(frame, 0, 8, 46, 0, 0, 0); _screen->updateScreen(); timer2 = _system->getMillis() + 8 * _tickLength; ++frame; @@ -1278,7 +1275,7 @@ int KyraEngine_LoK::handleMalcolmFlag() { case 8: if (_system->getMillis() >= timer2) { - _finalA->displayFrame(frame, 0, 8, 46); + _finalA->displayFrame(frame, 0, 8, 46, 0, 0, 0); _screen->updateScreen(); timer2 = _system->getMillis() + 8 * _tickLength; ++frame; @@ -1295,7 +1292,7 @@ int KyraEngine_LoK::handleMalcolmFlag() { snd_playSoundEffect(12); for (int i = 0; i < 18; ++i) { timer2 = _system->getMillis() + 4 * _tickLength; - _finalC->displayFrame(i, 0, 16, 50); + _finalC->displayFrame(i, 0, 16, 50, 0, 0, 0); _screen->updateScreen(); delayUntil(timer2); } @@ -1353,7 +1350,7 @@ int KyraEngine_LoK::handleBeadState() { switch (_beadStateVar) { case 0: if (beadState1.x != -1 && _endSequenceBackUpRect) { - _screen->copyFromCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyBlockToPage(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->addBitBlitRect(beadState1.x, beadState1.y, beadState1.width2, beadState1.height); } @@ -1367,7 +1364,7 @@ int KyraEngine_LoK::handleBeadState() { case 1: if (beadState1.x != -1) { if (_endSequenceBackUpRect) { - _screen->copyFromCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyBlockToPage(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->addBitBlitRect(beadState1.x, beadState1.y, beadState1.width2, beadState1.height); } beadState1.x = -1; @@ -1402,14 +1399,14 @@ int KyraEngine_LoK::handleBeadState() { beadState1.dstY = beadState1.y; return 0; } else { - _screen->copyFromCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyBlockToPage(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->addBitBlitRect(beadState1.x, beadState1.y, beadState1.width2, beadState1.height); beadState1.x = x; beadState1.y = y; } } - _screen->copyCurPageBlock(x >> 3, y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyRegionToBuffer(_screen->_curPage, x, y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->drawShape(2, _panPagesTable[_lastDisplayedPanPage++], x, y, 0, 0); if (_lastDisplayedPanPage > 17) @@ -1422,12 +1419,12 @@ int KyraEngine_LoK::handleBeadState() { case 3: if (_system->getMillis() >= timer1) { timer1 = _system->getMillis() + 4 * _tickLength; - _screen->copyFromCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyBlockToPage(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->addBitBlitRect(beadState1.x, beadState1.y, beadState1.width2, beadState1.height); beadState1.x = beadState1.dstX + table1[beadState1.tableIndex]; beadState1.y = beadState1.dstY + table2[beadState1.tableIndex]; - _screen->copyCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyRegionToBuffer(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->drawShape(2, _panPagesTable[_lastDisplayedPanPage++], beadState1.x, beadState1.y, 0, 0); if (_lastDisplayedPanPage >= 17) @@ -1476,11 +1473,11 @@ int KyraEngine_LoK::handleBeadState() { _beadStateVar = 0; } } else { - _screen->copyFromCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyBlockToPage(_screen->_curPage, beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); _screen->addBitBlitRect(beadState1.x, beadState1.y, beadState1.width2, beadState1.height); beadState1.x = x; beadState1.y = y; - _screen->copyCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyRegionToBuffer(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->drawShape(2, _panPagesTable[_lastDisplayedPanPage++], x, y, 0, 0); if (_lastDisplayedPanPage > 17) { _lastDisplayedPanPage = 0; @@ -1496,24 +1493,24 @@ int KyraEngine_LoK::handleBeadState() { int x = 0, y = 0; if (processBead(beadState1.x, beadState1.y, x, y, &beadState2)) { if (beadState2.dstX == 290) { - _screen->copyFromCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyBlockToPage(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); uint32 nextRun = 0; for (int i = 0; i < 8; ++i) { nextRun = _system->getMillis() + _tickLength; - _finalB->displayFrame(i, 0, 224, 8); + _finalB->displayFrame(i, 0, 224, 8, 0, 0, 0); _screen->updateScreen(); delayUntil(nextRun); } snd_playSoundEffect(0x0D); for (int i = 7; i >= 0; --i) { nextRun = _system->getMillis() + _tickLength; - _finalB->displayFrame(i, 0, 224, 8); + _finalB->displayFrame(i, 0, 224, 8, 0, 0, 0); _screen->updateScreen(); delayUntil(nextRun); } initBeadState(beadState1.x, beadState1.y, 63, 60, 12, &beadState2); } else { - _screen->copyFromCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyBlockToPage(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->addBitBlitRect(beadState1.x, beadState1.y, beadState1.width2, beadState1.height); beadState1.x = -1; beadState1.tableIndex = 0; @@ -1521,11 +1518,11 @@ int KyraEngine_LoK::handleBeadState() { _malcolmFlag = 9; } } else { - _screen->copyFromCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyBlockToPage(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->addBitBlitRect(beadState1.x, beadState1.y, beadState1.width2, beadState1.height); beadState1.x = x; beadState1.y = y; - _screen->copyCurPageBlock(beadState1.x >> 3, beadState1.y, beadState1.width, beadState1.height, _endSequenceBackUpRect); + _screen->copyRegionToBuffer(_screen->_curPage, beadState1.x, beadState1.y, beadState1.width << 3, beadState1.height, _endSequenceBackUpRect); _screen->drawShape(2, _panPagesTable[_lastDisplayedPanPage++], x, y, 0, 0); if (_lastDisplayedPanPage > 17) _lastDisplayedPanPage = 0; @@ -1679,11 +1676,11 @@ void KyraEngine_LoK::updateKyragemFading() { _kyragemFadingState.timerCount = _system->getMillis() + 4 * _tickLength; int palPos = 684; for (int i = 0; i < 20; ++i) { - _screen->_currentPalette[palPos++] = kyraGemPalette[i + _kyragemFadingState.rOffset]; - _screen->_currentPalette[palPos++] = kyraGemPalette[i + _kyragemFadingState.gOffset]; - _screen->_currentPalette[palPos++] = kyraGemPalette[i + _kyragemFadingState.bOffset]; + _screen->getPalette(0)[palPos++] = kyraGemPalette[i + _kyragemFadingState.rOffset]; + _screen->getPalette(0)[palPos++] = kyraGemPalette[i + _kyragemFadingState.gOffset]; + _screen->getPalette(0)[palPos++] = kyraGemPalette[i + _kyragemFadingState.bOffset]; } - _screen->setScreenPalette(_screen->_currentPalette); + _screen->setScreenPalette(_screen->getPalette(0)); _animator->_updateScreen = true; switch (_kyragemFadingState.nextOperation) { case 0: diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp index 849a325560..beea129f66 100644 --- a/engines/kyra/sequences_lol.cpp +++ b/engines/kyra/sequences_lol.cpp @@ -43,7 +43,7 @@ int LoLEngine::processPrologue() { if (_flags.isDemo) { _screen->fadePalette(_screen->getPalette(1), 30, 0); - _screen->loadBitmap("FINAL.CPS", 2, 2, _screen->getPalette(0)); + _screen->loadBitmap("FINAL.CPS", 2, 2, &_screen->getPalette(0)); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); _screen->fadePalette(_screen->getPalette(0), 30, 0); delayWithTicks(300); @@ -57,7 +57,7 @@ int LoLEngine::processPrologue() { int processSelection = -1; while (!shouldQuit() && processSelection == -1) { - _screen->loadBitmap("TITLE.CPS", 2, 2, _screen->getPalette(0)); + _screen->loadBitmap("TITLE.CPS", 2, 2, &_screen->getPalette(0)); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); _screen->setFont(Screen::FID_6_FNT); @@ -71,11 +71,14 @@ int LoLEngine::processPrologue() { _eventList.clear(); int selection = mainMenu(); - _screen->hideMouse(); - // Unlike the original, we add a nice fade to black - memset(_screen->getPalette(0), 0, 768); - _screen->fadePalette(_screen->getPalette(0), 0x54); + if (selection != 3) { + _screen->hideMouse(); + + // Unlike the original, we add a nice fade to black + _screen->getPalette(0).clear(); + _screen->fadeToBlack(0x54); + } switch (selection) { case 0: // New game @@ -90,7 +93,8 @@ int LoLEngine::processPrologue() { break; case 3: // Load game - //processSelection = 3; + if (_gui->runMenu(_gui->_loadMenu)) + processSelection = 3; break; case 4: // Quit game @@ -100,7 +104,7 @@ int LoLEngine::processPrologue() { } } - if (processSelection == 0 || processSelection == 3) { + if (processSelection == 0) { _sound->loadSoundFile(0); _sound->playTrack(6); chooseCharacter(); @@ -131,7 +135,6 @@ void LoLEngine::setupPrologueData(bool load) { const char * const *fileList = _flags.isTalkie ? fileListCD : (_flags.useInstallerPackage ? fileListFloppy : fileListFloppyExtracted); - char filename[32]; for (uint i = 0; fileList[i]; ++i) { filename[0] = '\0'; @@ -155,7 +158,7 @@ void LoLEngine::setupPrologueData(bool load) { _screen->clearPage(3); if (load) { - _chargenWSA = new WSAMovie_v2(this, _screen); + _chargenWSA = new WSAMovie_v2(this); assert(_chargenWSA); //_charSelection = -1; @@ -165,7 +168,7 @@ void LoLEngine::setupPrologueData(bool load) { _selectionAnimFrames[1] = _selectionAnimFrames[3] = 1; memset(_selectionAnimTimers, 0, sizeof(_selectionAnimTimers)); - memset(_screen->getPalette(1), 0, 768); + _screen->getPalette(1).clear(); _sound->setSoundList(&_soundData[kMusicIntro]); @@ -181,9 +184,8 @@ void LoLEngine::setupPrologueData(bool load) { } else { delete _chargenWSA; _chargenWSA = 0; - uint8 *pal = _screen->getPalette(0); - memset(pal, 0, 768); - _screen->setScreenPalette(pal); + _screen->getPalette(0).clear(); + _screen->setScreenPalette(_screen->getPalette(0)); if (shouldQuit()) return; @@ -200,9 +202,8 @@ void LoLEngine::showIntro() { if (_flags.platform == Common::kPlatformPC98) showStarcraftLogo(); - uint8 *pal = _screen->getPalette(0); - memset(pal, 0, 768); - _screen->setScreenPalette(pal); + _screen->getPalette(0).clear(); + _screen->setScreenPalette(_screen->getPalette(0)); _screen->clearPage(0); _screen->clearPage(4); @@ -274,8 +275,8 @@ int LoLEngine::chooseCharacter() { while (!_screen->isMouseVisible()) _screen->showMouse(); - _screen->loadBitmap("CHAR.CPS", 2, 2, _screen->getPalette(0)); - _screen->loadBitmap("BACKGRND.CPS", 4, 4, _screen->getPalette(0)); + _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"); @@ -368,7 +369,7 @@ void LoLEngine::kingSelectionIntro() { _sound->voicePlay("KING01", &_speechHandle); int index = 4; - while ((!_speechFlag || (_speechFlag && _sound->voiceIsPlaying(&_speechHandle))) && _charSelection == -1 && !shouldQuit() && !skipFlag()) { + while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && _charSelection == -1 && !shouldQuit() && !skipFlag()) { index = MAX(index, 4); _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 113, 0, 0, 0, 0); @@ -384,7 +385,7 @@ void LoLEngine::kingSelectionIntro() { _system->delayMillis(10); } - if (_speechFlag) + if (speechEnabled()) index = (index + 1) % 22; else if (++index >= 27) break; @@ -407,7 +408,7 @@ void LoLEngine::kingSelectionReminder() { _sound->voicePlay("KING02", &_speechHandle); int index = 0; - while ((!_speechFlag || (_speechFlag && _sound->voiceIsPlaying(&_speechHandle))) && _charSelection == -1 && !shouldQuit() && index < 15) { + while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && _charSelection == -1 && !shouldQuit() && index < 15) { _chargenWSA->displayFrame(_chargenFrameTable[index+9], 0, 113, 0, 0, 0, 0); _screen->copyRegion(_selectionPosTable[_reminderChar1IdxTable[index]*2+0], _selectionPosTable[_reminderChar1IdxTable[index]*2+1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0); _screen->copyRegion(_selectionPosTable[_reminderChar2IdxTable[index]*2+0], _selectionPosTable[_reminderChar2IdxTable[index]*2+1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0); @@ -421,7 +422,7 @@ void LoLEngine::kingSelectionReminder() { _system->delayMillis(10); } - if (_speechFlag) + if (speechEnabled()) index = (index + 1) % 22; else if (++index >= 27) break; @@ -434,7 +435,7 @@ void LoLEngine::kingSelectionOutro() { _sound->voicePlay("KING03", &_speechHandle); int index = 0; - while ((!_speechFlag || (_speechFlag && _sound->voiceIsPlaying(&_speechHandle))) && !shouldQuit() && !skipFlag()) { + while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && !shouldQuit() && !skipFlag()) { index = MAX(index, 4); _chargenWSA->displayFrame(_chargenFrameTable[index], 0, 113, 0, 0, 0, 0); @@ -446,7 +447,7 @@ void LoLEngine::kingSelectionOutro() { _system->delayMillis(10); } - if (_speechFlag) + if (speechEnabled()) index = (index + 1) % 22; else if (++index >= 27) break; @@ -581,13 +582,13 @@ void LoLEngine::selectionCharInfoIntro(char *file) { bool processAnim = true; while (_charSelectionInfoResult == -1 && !shouldQuit()) { - if (_speechFlag && !_sound->isVoicePresent(file)) + if (speechEnabled() && !_sound->isVoicePresent(file)) break; _sound->voicePlay(file, &_speechHandle); int i = 0; - while ((!_speechFlag || (_speechFlag && _sound->voiceIsPlaying(&_speechHandle))) && _charSelectionInfoResult == -1 && !shouldQuit()) { + while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && _charSelectionInfoResult == -1 && !shouldQuit()) { _screen->drawShape(0, _screen->getPtrToShape(_screen->getCPagePtr(9), _charInfoFrameTable[i]), 11, 130, 0, 0); _screen->updateScreen(); @@ -597,7 +598,7 @@ void LoLEngine::selectionCharInfoIntro(char *file) { _system->delayMillis(10); } - if (_speechFlag || processAnim) + if (speechEnabled() || processAnim) i = (i + 1) % 32; if (i == 0) processAnim = false; @@ -641,19 +642,19 @@ int LoLEngine::selectionCharAccept() { } void LoLEngine::showStarcraftLogo() { - WSAMovie_v2 *ci = new WSAMovie_v2(this, _screen); + WSAMovie_v2 *ci = new WSAMovie_v2(this); assert(ci); _screen->clearPage(0); _screen->clearPage(2); - int endframe = ci->open("ci01.wsa", 0, _screen->_currentPalette); + int endframe = ci->open("ci01.wsa", 0, &_screen->getPalette(0)); if (!ci->opened()) { delete ci; return; } _screen->hideMouse(); - ci->displayFrame(0, 2, 32, 80, 0); + ci->displayFrame(0, 2, 32, 80, 0, 0, 0); _screen->copyPage(2, 0); _screen->fadeFromBlack(); int inputFlag = 0; @@ -661,7 +662,7 @@ void LoLEngine::showStarcraftLogo() { inputFlag = checkInput(0) & 0xff; if (shouldQuit() || inputFlag) break; - ci->displayFrame(i, 2, 32, 80, 0); + ci->displayFrame(i, 2, 32, 80, 0, 0, 0); _screen->copyPage(2, 0); _screen->updateScreen(); delay(4 * _tickLength); @@ -725,9 +726,8 @@ void LoLEngine::setupEpilogueData(bool load) { if (_flags.platform == Common::kPlatformPC98) _sound->loadSoundFile("SOUND.DAT"); } else { - uint8 *pal = _screen->getPalette(0); - memset(pal, 0, 768); - _screen->setScreenPalette(pal); + _screen->getPalette(0).clear(); + _screen->setScreenPalette(_screen->getPalette(0)); if (shouldQuit()) return; @@ -742,9 +742,8 @@ void LoLEngine::showOutro(int character, bool maxDifficulty) { TIMInterpreter *timBackUp = _tim; _tim = new TIMInterpreter(this, _screen, _system); - uint8 *pal = _screen->getPalette(0); - memset(pal, 0, 768); - _screen->setScreenPalette(pal); + _screen->getPalette(0).clear(); + _screen->setScreenPalette(_screen->getPalette(0)); _screen->clearPage(0); _screen->clearPage(4); @@ -803,25 +802,24 @@ void LoLEngine::showOutro(int character, bool maxDifficulty) { switch (character) { case 0: - _screen->loadBitmap("KIERAN.CPS", 3, 3, _screen->getPalette(0)); + _screen->loadBitmap("KIERAN.CPS", 3, 3, &_screen->getPalette(0)); break; case 1: - _screen->loadBitmap("AK'SHEL.CPS", 3, 3, _screen->getPalette(0)); + _screen->loadBitmap("AK'SHEL.CPS", 3, 3, &_screen->getPalette(0)); break; case 2: - _screen->loadBitmap("MICHAEL.CPS", 3, 3, _screen->getPalette(0)); + _screen->loadBitmap("MICHAEL.CPS", 3, 3, &_screen->getPalette(0)); break; case 3: - _screen->loadBitmap("CONRAD.CPS", 3, 3, _screen->getPalette(0)); + _screen->loadBitmap("CONRAD.CPS", 3, 3, &_screen->getPalette(0)); break; default: _screen->clearPage(3); - memset(_screen->getPalette(0), 0, 768); - break; + _screen->getPalette(0).clear(); } _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); @@ -856,8 +854,8 @@ void LoLEngine::showCredits() { _screen->setTextColorMap(colorMap); _screen->_charWidth = 0; - _screen->loadBitmap("ROOM.CPS", 2, 2, _screen->getPalette(0)); - memset(_screen->getPalette(0) + 764, 0, 3); + _screen->loadBitmap("ROOM.CPS", 2, 2, &_screen->getPalette(0)); + _screen->getPalette(0).fill(255, 1, 0); _screen->fadeToBlack(30); _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); @@ -865,7 +863,7 @@ void LoLEngine::showCredits() { _screen->_charOffset = 0; char *credits = (char *)_res->fileData("CREDITS.TXT", 0); - processCredits(credits, 19, 4, 5); + processCredits(credits, 21, 4, 5); delete[] credits; uint32 endTime = _system->getMillis() + 120 * _tickLength; @@ -895,8 +893,8 @@ void LoLEngine::processCredits(char *t, int dimState, int page, int delayTime) { uint8 *doorShape = _screen->makeShapeCopy(_screen->getCPagePtr(5), 0); assert(doorShape); - _screen->drawShape(0, doorShape, 0, 0, 20, 0x10); - _screen->drawShape(0, doorShape, 0, 0, 21, 0x11); + _screen->drawShape(0, doorShape, 0, 0, 22, 0x10); + _screen->drawShape(0, doorShape, 0, 0, 23, 0x11); int curShapeFile = 0; uint8 *shapes[12]; @@ -906,7 +904,7 @@ void LoLEngine::processCredits(char *t, int dimState, int page, int delayTime) { uint8 *monsterPal = _res->fileData("MONSTERS.PAL", 0); assert(monsterPal); - memcpy(_screen->getPalette(0) + 88 * 3, monsterPal + 0 * 3, 40 * 3); + _screen->getPalette(0).copy(monsterPal, 0, 40, 88); _screen->fadePalette(_screen->getPalette(0), 30); uint32 waitTimer = _system->getMillis(); @@ -1042,8 +1040,8 @@ void LoLEngine::processCredits(char *t, int dimState, int page, int delayTime) { } else { if (!monsterAnimFrame && doorRedraw) { _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, page, Screen::CR_NO_P_CHECK); - _screen->drawShape(page, doorShape, 0, 0, 20, 0x10); - _screen->drawShape(page, doorShape, 0, 0, 21, 0x11); + _screen->drawShape(page, doorShape, 0, 0, 22, 0x10); + _screen->drawShape(page, doorShape, 0, 0, 23, 0x11); --frameCounter; doorRedraw = false; @@ -1062,32 +1060,32 @@ void LoLEngine::processCredits(char *t, int dimState, int page, int delayTime) { bool isRightMonster = ((curShapeFile - 1) & 1) != 0; if (isRightMonster) { - doorSD = 21; + doorSD = 23; doorX = _outroRightDoorPos[monsterAnimFrame * 2 + 0]; doorY = _outroRightDoorPos[monsterAnimFrame * 2 + 1]; monsterX = _outroRightMonsterPos[monsterAnimFrame * 2 + 0]; monsterY = _outroRightMonsterPos[monsterAnimFrame * 2 + 1]; - _screen->drawShape(page, doorShape, 0, 0, 20, 0x10); + _screen->drawShape(page, doorShape, 0, 0, 22, 0x10); } else { - doorSD = 20; + doorSD = 22; doorX = _outroLeftDoorPos[monsterAnimFrame * 2 + 0]; doorY = _outroLeftDoorPos[monsterAnimFrame * 2 + 1]; monsterX = _outroLeftMonsterPos[monsterAnimFrame * 2 + 0]; monsterY = _outroLeftMonsterPos[monsterAnimFrame * 2 + 1]; - _screen->drawShape(page, doorShape, 0, 0, 21, 0x11); + _screen->drawShape(page, doorShape, 0, 0, 23, 0x11); } if (monsterAnimFrame >= 8) - _screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 20) ? 0 : 1); + _screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 22) ? 0 : 1); _screen->drawShape(page, monsterShape, monsterX, monsterY, 0, 0x104 | ((!isRightMonster | (monsterAnimFrame < 20)) ? 0 : 1), _outroShapeTable, 1, _outroMonsterScaleTableX[monsterAnimFrame], _outroMonsterScaleTableY[monsterAnimFrame]); if (monsterAnimFrame < 8) - _screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 20) ? 0 : 1); + _screen->drawShape(page, doorShape, doorX, doorY, doorSD, (doorSD == 22) ? 0 : 1); _screen->copyRegion(0, 0, 0, 0, 320, 200, page, 6, Screen::CR_NO_P_CHECK); doorRedraw = true; @@ -1129,7 +1127,7 @@ void LoLEngine::processCredits(char *t, int dimState, int page, int delayTime) { curShapeFile = curShapeFile % 28; loadOutroShapes(curShapeFile, shapes); - memcpy(_screen->getPalette(0) + 88 * 3, monsterPal + curShapeFile * 40 * 3, 40 * 3); + _screen->getPalette(0).copy(monsterPal, curShapeFile * 40, 40, 88); _screen->setScreenPalette(_screen->getPalette(0)); needNewShape = false; diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp index 3f87036849..63a42837aa 100644 --- a/engines/kyra/sound_lol.cpp +++ b/engines/kyra/sound_lol.cpp @@ -34,7 +34,7 @@ namespace Kyra { bool LoLEngine::snd_playCharacterSpeech(int id, int8 speaker, int) { - if (!_speechFlag) + if (!speechEnabled()) return false; if (speaker < 65) { @@ -304,6 +304,15 @@ int LoLEngine::snd_stopMusic() { return snd_playTrack(-1); } +int LoLEngine::convertVolumeToMixer(int value) { + value -= 2; + return (value * Audio::Mixer::kMaxMixerVolume) / 100; +} + +int LoLEngine::convertVolumeFromMixer(int value) { + return (value * 100) / Audio::Mixer::kMaxMixerVolume + 2; +} + } // end of namespace Kyra #endif // ENABLE_LOL diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp index f798251525..451b77cec2 100644 --- a/engines/kyra/sound_midi.cpp +++ b/engines/kyra/sound_midi.cpp @@ -311,10 +311,8 @@ void MidiOutput::sendSysEx(const byte p1, const byte p2, const byte p3, const by } void MidiOutput::metaEvent(byte type, byte *data, uint16 length) { - if (type == 0x2F) { // End of Track + if (type == 0x2F) // End of Track deinitSource(_curSource); - //XXX - } _output->metaEvent(type, data, length); } diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index 1980f62d7c..fe0a44c052 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -1504,7 +1504,7 @@ public: private: void updatesRegs(); - uint8 _updateRequestBuf[32]; + uint8 _updateRequestBuf[64]; int _updateRequest; int _rand; @@ -2657,7 +2657,7 @@ void TownsPC98_OpnSquareSineSource::writeReg(uint8 address, uint8 value, bool fo } if (!force) { - if (_updateRequest == 31) { + if (_updateRequest >= 63) { warning("TownsPC98_OpnSquareSineSource: event buffer overflow"); _updateRequest = -1; } @@ -3420,6 +3420,8 @@ TownsPC98_OpnDriver::TownsPC98_OpnDriver(Audio::Mixer *mixer, OpnType type) : To } TownsPC98_OpnDriver::~TownsPC98_OpnDriver() { + reset(); + if (_channels) { for (int i = 0; i < _numChan; i++) delete _channels[i]; @@ -4120,7 +4122,7 @@ void SoundPC98::playSoundEffect(uint8 track) { // This has been disabled for now since I don't know // how to make up the correct track number. It probably // needs a map. - //_driver->loadSoundEffectData(_sfxTrackData, track); + _driver->loadSoundEffectData(_sfxTrackData, track); } diff --git a/engines/kyra/sprites.cpp b/engines/kyra/sprites.cpp index 147ded3cfd..3cc632a391 100644 --- a/engines/kyra/sprites.cpp +++ b/engines/kyra/sprites.cpp @@ -47,7 +47,7 @@ Sprites::Sprites(KyraEngine_LoK *vm, OSystem *system) { _spriteDefStart = 0; memset(_drawLayerTable, 0, sizeof(_drawLayerTable)); _sceneAnimatorBeaconFlag = 0; - system->getEventManager()->registerRandomSource(_rnd, "kyraSprites"); + _vm->getEventManager()->registerRandomSource(_rnd, "kyraSprites"); } Sprites::~Sprites() { @@ -420,16 +420,16 @@ void Sprites::loadDat(const char *filename, SceneExits &exits) { if (_vm->gameFlags().platform == Common::kPlatformAmiga) { if (_vm->queryGameFlag(0xA0)) - memcpy(_screen->getPalette(3), _screen->getPalette(4), 32*3); + _screen->copyPalette(3, 4); else - memcpy(_screen->getPalette(3), _screen->getPalette(0), 32*3); + _screen->copyPalette(3, 0); } else { if (_vm->queryGameFlag(0xA0)) - memcpy(_screen->getPalette(1), _screen->getPalette(3), 768); + _screen->copyPalette(1, 3); else - memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); + _screen->copyPalette(1, 0); - _screen->loadPalette(_dat + 0x17, _screen->getPalette(1) + 684, 60); + _screen->getPalette(1).copy(_dat + 0x17, 0, 20, 228); } uint8 *data = _dat + 0x6B; diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp index 732a8bb2ca..8cee1dc5fc 100644 --- a/engines/kyra/sprites_lol.cpp +++ b/engines/kyra/sprites_lol.cpp @@ -784,7 +784,7 @@ int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) { default: return m->damageReceived ? 5 : m->currentSubFrame; } - + break; default: break; @@ -1092,7 +1092,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) { setMonsterMode(monster, 7); if ((monster->mode != 11) && (monster->mode != 14)) { - if (!(getRandomNumberSpecial() & 3)) { + if (!(_rnd.getRandomNumber(255) & 3)) { monster->shiftStep = (++monster->shiftStep) & 0x0f; checkSceneUpdateNeed(monster->block); } diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 3f41768c3c..e8597c8326 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1584,7 +1584,7 @@ void KyraEngine_LoK::loadMainScreen(int page) { _screen->clearPage(page); if (_flags.lang == Common::EN_ANY && !_flags.isTalkie && (_flags.platform == Common::kPlatformPC || _flags.platform == Common::kPlatformAmiga)) - _screen->loadBitmap("MAIN15.CPS", page, page, _screen->getPalette(0)); + _screen->loadBitmap("MAIN15.CPS", page, page, &_screen->getPalette(0)); else if (_flags.lang == Common::EN_ANY || _flags.lang == Common::JA_JPN || (_flags.isTalkie && _flags.lang == Common::IT_ITA)) _screen->loadBitmap("MAIN_ENG.CPS", page, page, 0); else if (_flags.lang == Common::FR_FRA) @@ -1599,7 +1599,7 @@ void KyraEngine_LoK::loadMainScreen(int page) { warning("no main graphics file found"); if (_flags.platform == Common::kPlatformAmiga) - memcpy(_screen->getPalette(1), _screen->getPalette(0), 32*3); + _screen->copyPalette(1, 0); _screen->copyRegion(0, 0, 0, 0, 320, 200, page, 0); } @@ -2011,9 +2011,108 @@ void LoLEngine::initStaticResource() { #undef cb } +void GUI_LoL::initStaticData() { + GUI_V2_BUTTON(_scrollUpButton, 20, 96, 0, 1, 1, 1, 0x4487, 0, 0, 0, 25, 16, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0); + GUI_V2_BUTTON(_scrollDownButton, 21, 98, 0, 1, 1, 1, 0x4487, 0, 0, 0, 25, 16, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0); + + for (uint i = 0; i < ARRAYSIZE(_menuButtons); ++i) + GUI_V2_BUTTON(_menuButtons[i], i, 0, 0, 0, 0, 0, 0x4487, 0, 0, 0, 0, 0, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0); + + GUI_LOL_MENU(_mainMenu, 9, 0x4000, 0, 7, -1, -1, -1, -1); + GUI_LOL_MENU_ITEM(_mainMenu.item[0], 0x4001, 16, 23, 176, 15, 0, 0); + GUI_LOL_MENU_ITEM(_mainMenu.item[1], 0x4002, 16, 40, 176, 15, 0, 0); + GUI_LOL_MENU_ITEM(_mainMenu.item[2], 0x4003, 16, 57, 176, 15, 0, 0); + GUI_LOL_MENU_ITEM(_mainMenu.item[3], 0x4004, 16, 74, 176, 15, 0, 0); + GUI_LOL_MENU_ITEM(_mainMenu.item[4], 0x42D9, 16, 91, 176, 15, 0, 0); + GUI_LOL_MENU_ITEM(_mainMenu.item[5], 0x4006, 16, 108, 176, 15, 0, 0); + GUI_LOL_MENU_ITEM(_mainMenu.item[6], 0x4005, 88, 127, 104, 15, 0, 110); + Button::Callback mainMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedMainMenu); + for (int i = 0; i < 7; ++i) + _mainMenu.item[i].callback = mainMenuFunctor; + + GUI_LOL_MENU(_loadMenu, 10, 0x400e, 1, 5, 128, 20, 128, 118); + GUI_LOL_MENU_ITEM(_loadMenu.item[0], 0xfffe, 8, 39, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_loadMenu.item[1], 0xfffd, 8, 56, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_loadMenu.item[2], 0xfffc, 8, 73, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_loadMenu.item[3], 0xfffb, 8, 90, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_loadMenu.item[4], 0x4011, 168, 118, 96, 15, 0, 110); + Button::Callback loadMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedLoadMenu); + for (int i = 0; i < 5; ++i) + _loadMenu.item[i].callback = loadMenuFunctor; + + GUI_LOL_MENU(_saveMenu, 10, 0x400d, 1, 5, 128, 20, 128, 118); + GUI_LOL_MENU_ITEM(_saveMenu.item[0], 0xfffe, 8, 39, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_saveMenu.item[1], 0xfffd, 8, 56, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_saveMenu.item[2], 0xfffc, 8, 73, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_saveMenu.item[3], 0xfffb, 8, 90, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_saveMenu.item[4], 0x4011, 168, 118, 96, 15, 0, 110); + Button::Callback saveMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedSaveMenu); + for (int i = 0; i < 5; ++i) + _saveMenu.item[i].callback = saveMenuFunctor; + + GUI_LOL_MENU(_deleteMenu, 10, 0x400f, 1, 5, 128, 20, 128, 118); + GUI_LOL_MENU_ITEM(_deleteMenu.item[0], 0xfffe, 8, 39, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_deleteMenu.item[1], 0xfffd, 8, 56, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_deleteMenu.item[2], 0xfffc, 8, 73, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_deleteMenu.item[3], 0xfffb, 8, 90, 256, 15, 0, 0); + GUI_LOL_MENU_ITEM(_deleteMenu.item[4], 0x4011, 168, 118, 96, 15, 0, 110); + Button::Callback deleteMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedDeleteMenu); + for (int i = 0; i < 5; ++i) + _deleteMenu.item[i].callback = deleteMenuFunctor; + + GUI_LOL_MENU(_gameOptions, 17, 0x400c, 0, 6, -1, -1, -1, -1); + GUI_LOL_MENU_ITEM(_gameOptions.item[0], 0xfff7, 120, 22, 80, 15, 0x406e, 0); + GUI_LOL_MENU_ITEM(_gameOptions.item[1], 0xfff6, 120, 39, 80, 15, 0x406c, 0); + GUI_LOL_MENU_ITEM(_gameOptions.item[2], 0xfff5, 120, 56, 80, 15, 0x406d, 0); + GUI_LOL_MENU_ITEM(_gameOptions.item[3], 0xfff4, 120, 73, 80, 15, 0x42d5, 0); + GUI_LOL_MENU_ITEM(_gameOptions.item[4], 0xfff3, 120, 90, 80, 15, 0x42d2, 0); + GUI_LOL_MENU_ITEM(_gameOptions.item[5], 0x4072, 104, 110, 96, 15, 0, 110); + Button::Callback optionsMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedOptionsMenu); + for (int i = 0; i < 6; ++i) + _gameOptions.item[i].callback = optionsMenuFunctor; + + GUI_LOL_MENU(_audioOptions, 18, 0x42d9, 2, 1, -1, -1, -1, -1); + GUI_LOL_MENU_ITEM(_audioOptions.item[0], 0x4072, 152, 76, 96, 15, 0, 110); + GUI_LOL_MENU_ITEM(_audioOptions.item[1], 3, 128, 22, 114, 14, 0x42db, 0); + GUI_LOL_MENU_ITEM(_audioOptions.item[2], 4, 128, 39, 114, 14, 0x42da, 0); + GUI_LOL_MENU_ITEM(_audioOptions.item[3], 5, 128, 56, 114, 14, 0x42dc, 0); + Button::Callback audioMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedAudioMenu); + for (int i = 0; i < 4; ++i) + _audioOptions.item[i].callback = audioMenuFunctor; + + GUI_LOL_MENU(_deathMenu, 11, 0x4013, 0, 2, -1, -1, -1, -1); + GUI_LOL_MENU_ITEM(_deathMenu.item[0], 0x4006, 8, 30, 104, 15, 0, 0); + GUI_LOL_MENU_ITEM(_deathMenu.item[1], 0x4001, 176, 30, 104, 15, 0, 0); + Button::Callback deathMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedDeathMenu); + for (int i = 0; i < 2; ++i) + _deathMenu.item[i].callback = deathMenuFunctor; + + GUI_LOL_MENU(_savenameMenu, 7, 0x4053, 0, 2, -1, -1, -1, -1); + GUI_LOL_MENU_ITEM(_savenameMenu.item[0], 0x4012, 8, 38, 72, 15, 0, 43); + GUI_LOL_MENU_ITEM(_savenameMenu.item[1], 0x4011, 176, 38, 72, 15, 0, 110); + Button::Callback savenameMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedSavenameMenu); + for (int i = 0; i < 2; ++i) + _savenameMenu.item[i].callback = savenameMenuFunctor; + + GUI_LOL_MENU(_choiceMenu, 11, 0, 0, 2, -1, -1, -1, -1); + GUI_LOL_MENU_ITEM(_choiceMenu.item[0], 0x4007, 8, 30, 72, 15, 0, 0); + GUI_LOL_MENU_ITEM(_choiceMenu.item[1], 0x4008, 208, 30, 72, 15, 0, 0); + Button::Callback choiceMenuFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::clickedChoiceMenu); + for (int i = 0; i < 2; ++i) + _choiceMenu.item[i].callback = choiceMenuFunctor; +} #endif // ENABLE_LOL +const uint8 Screen_LoK_16::_palette16[48] = { + 0x00, 0x00, 0x00, 0x02, 0x07, 0x0B, 0x0C, 0x06, 0x04, + 0x0E, 0x09, 0x07, 0x00, 0x06, 0x03, 0x00, 0x0C, 0x07, + 0x0A, 0x0A, 0x0A, 0x08, 0x03, 0x03, 0x02, 0x02, 0x02, + 0x08, 0x0B, 0x0E, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x0A, + 0x05, 0x05, 0x05, 0x00, 0x0F, 0x0F, 0x0F, 0x0D, 0x00, + 0x0F, 0x0F, 0x0F +}; + const ScreenDim Screen_LoK::_screenDimTable[] = { { 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 }, { 0x08, 0x48, 0x18, 0x38, 0x0F, 0x0C, 0x00, 0x00 }, @@ -3018,6 +3117,8 @@ const ScreenDim Screen_LoL::_screenDimTable256C[] = { { 0x0D, 0xA2, 0x18, 0x0C, 0xFE, 0x01, 0x00, 0x00 }, { 0x0F, 0x06, 0x14, 0x6E, 0x01, 0x00, 0x00, 0x00 }, { 0x1A, 0xBE, 0x0A, 0x07, 0xFE, 0x01, 0x00, 0x00 }, + { 0x07, 0x21, 0x1A, 0x85, 0x00, 0x00, 0x00, 0x00 }, + { 0x03, 0x32, 0x22, 0x62, 0x00, 0x00, 0x00, 0x00 }, { 0x0B, 0x8C, 0x10, 0x33, 0x3D, 0x01, 0x00, 0x00 }, // Main menu box (5 entries, CD version only) { 0x0B, 0x8C, 0x10, 0x23, 0x3D, 0x01, 0x00, 0x00 }, // Main menu box (3 entries, floppy version only) @@ -3045,6 +3146,8 @@ const ScreenDim Screen_LoL::_screenDimTable16C[] = { { 0x0D, 0xA2, 0x18, 0x0C, 0x33, 0x44, 0x00, 0x00 }, { 0x0F, 0x06, 0x14, 0x6E, 0x44, 0x00, 0x00, 0x00 }, { 0x1A, 0xBE, 0x0A, 0x07, 0x33, 0x44, 0x00, 0x00 }, + { 0x07, 0x21, 0x1A, 0x85, 0x00, 0x00, 0x00, 0x00 }, + { 0x03, 0x32, 0x22, 0x62, 0x00, 0x00, 0x00, 0x00 }, { 0x0B, 0x8C, 0x10, 0x33, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (5 entries, not used here) { 0x0B, 0x8C, 0x10, 0x23, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (3 entries) @@ -3056,6 +3159,42 @@ const ScreenDim Screen_LoL::_screenDimTable16C[] = { const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable256C); +// 256 -> 16 color conversion table +const uint8 Screen_LoL::_paletteConvTable[256] = { + 0x0, 0x1, 0x0, 0x3, 0x0, 0x5, 0x0, 0x7, + 0x0, 0x9, 0x0, 0xB, 0x0, 0xD, 0x0, 0xF, + 0x1, 0x1, 0x1, 0x3, 0x1, 0x5, 0x1, 0x7, + 0x1, 0x9, 0x1, 0xB, 0x1, 0xD, 0x1, 0xF, + 0x2, 0x1, 0x2, 0x3, 0x2, 0x5, 0x2, 0x7, + 0x2, 0x9, 0x2, 0xB, 0x2, 0xD, 0x2, 0xF, + 0x3, 0x1, 0x3, 0x3, 0x3, 0x5, 0x3, 0x7, + 0x3, 0x9, 0x3, 0xB, 0x3, 0xD, 0x3, 0xF, + 0x4, 0x1, 0x4, 0x3, 0x4, 0x5, 0x4, 0x7, + 0x4, 0x9, 0x4, 0xB, 0x4, 0xD, 0x4, 0xF, + 0x5, 0x1, 0x5, 0x3, 0x5, 0x5, 0x5, 0x7, + 0x5, 0x9, 0x5, 0xB, 0x5, 0xD, 0x5, 0xF, + 0x6, 0x1, 0x6, 0x3, 0x6, 0x5, 0x6, 0x7, + 0x6, 0x9, 0x6, 0xB, 0x6, 0xD, 0x6, 0xF, + 0x7, 0x1, 0x7, 0x3, 0x7, 0x5, 0x7, 0x7, + 0x7, 0x9, 0x7, 0xB, 0x7, 0xD, 0x7, 0xF, + 0x8, 0x1, 0x8, 0x3, 0x8, 0x5, 0x8, 0x7, + 0x8, 0x9, 0x8, 0xB, 0x8, 0xD, 0x8, 0xF, + 0x9, 0x1, 0x9, 0x3, 0x9, 0x5, 0x9, 0x7, + 0x9, 0x9, 0x9, 0xB, 0x9, 0xD, 0x9, 0xF, + 0xA, 0x1, 0xA, 0x3, 0xA, 0x5, 0xA, 0x7, + 0xA, 0x9, 0xA, 0xB, 0xA, 0xD, 0xA, 0xF, + 0xB, 0x1, 0xB, 0x3, 0xB, 0x5, 0xB, 0x7, + 0xB, 0x9, 0xB, 0xB, 0xB, 0xD, 0xB, 0xF, + 0xC, 0x1, 0xC, 0x3, 0xC, 0x5, 0xC, 0x7, + 0xC, 0x9, 0xC, 0xB, 0xC, 0xD, 0xC, 0xF, + 0xD, 0x1, 0xD, 0x3, 0xD, 0x5, 0xD, 0x7, + 0xD, 0x9, 0xD, 0xB, 0xD, 0xD, 0xD, 0xF, + 0xE, 0x1, 0xE, 0x3, 0xE, 0x5, 0xE, 0x7, + 0xE, 0x9, 0xE, 0xB, 0xE, 0xD, 0xE, 0xF, + 0xF, 0x1, 0xF, 0x3, 0xF, 0x5, 0xF, 0x7, + 0xF, 0x9, 0xF, 0xB, 0xF, 0xD, 0xF, 0xF +}; + const char * const LoLEngine::_languageExt[] = { "ENG", "FRE", @@ -3241,4 +3380,3 @@ const int LoLEngine::_outroMonsterScaleTableY[] = { #endif // ENABLE_LOL } // End of namespace Kyra - diff --git a/engines/kyra/text_lok.cpp b/engines/kyra/text_lok.cpp index 6b1cb4eca2..3f4bfb65ac 100644 --- a/engines/kyra/text_lok.cpp +++ b/engines/kyra/text_lok.cpp @@ -39,12 +39,9 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const uint8 currPage; Common::Event event; - //while (towns_isEscKeyPressed() ) - //towns_getKey(); - uint32 timeToEnd = strlen(chatStr) * 8 * _tickLength + _system->getMillis(); - if (_configVoice == 0 && chatDuration != -1) { + if (textEnabled() && !speechEnabled() && chatDuration != -1) { switch (_configTextspeed) { case 0: chatDuration *= 2; @@ -136,7 +133,6 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const _timer->enable(15); _timer->enable(18); _timer->enable(19); - //clearKyrandiaButtonIO(); } void KyraEngine_LoK::endCharacterChat(int8 charNum, int16 convoInitialized) { @@ -329,11 +325,11 @@ void KyraEngine_LoK::drawSentenceCommand(const char *sentence, int color) { _screen->fillRect(8, 143, 311, 152, 12); if (_startSentencePalIndex != color || _fadeText != false) { - _currSentenceColor[0] = _screen->_currentPalette[765] = _screen->_currentPalette[color*3]; - _currSentenceColor[1] = _screen->_currentPalette[766] = _screen->_currentPalette[color*3+1]; - _currSentenceColor[2] = _screen->_currentPalette[767] = _screen->_currentPalette[color*3+2]; + _currSentenceColor[0] = _screen->getPalette(0)[765] = _screen->getPalette(0)[color*3]; + _currSentenceColor[1] = _screen->getPalette(0)[766] = _screen->getPalette(0)[color*3+1]; + _currSentenceColor[2] = _screen->getPalette(0)[767] = _screen->getPalette(0)[color*3+2]; - _screen->setScreenPalette(_screen->_currentPalette); + _screen->setScreenPalette(_screen->getPalette(0)); _startSentencePalIndex = 0; } @@ -368,10 +364,10 @@ void KyraEngine_LoK::updateTextFade() { } } - _screen->_currentPalette[765] = _currSentenceColor[0]; - _screen->_currentPalette[766] = _currSentenceColor[1]; - _screen->_currentPalette[767] = _currSentenceColor[2]; - _screen->setScreenPalette(_screen->_currentPalette); + _screen->getPalette(0)[765] = _currSentenceColor[0]; + _screen->getPalette(0)[766] = _currSentenceColor[1]; + _screen->getPalette(0)[767] = _currSentenceColor[2]; + _screen->setScreenPalette(_screen->getPalette(0)); if (finished) { _fadeText = false; diff --git a/engines/kyra/text_lol.cpp b/engines/kyra/text_lol.cpp index 7ce12f47c7..2174bcc441 100644 --- a/engines/kyra/text_lol.cpp +++ b/engines/kyra/text_lol.cpp @@ -33,8 +33,8 @@ namespace Kyra { TextDisplayer_LoL::TextDisplayer_LoL(LoLEngine *vm, Screen_LoL *screen) : _vm(vm), _screen(screen), - _scriptParameter(0), _animWidth(0), _animColor1(0), _animColor2(0), _animFlag(true), _lineCount(0), - _printFlag(false), _lineWidth(0), _numCharsTotal(0), _numCharsLeft(0), _numCharsPrinted(0) { + _scriptParameter(0), _lineCount(0), _printFlag(false), _lineWidth(0), _numCharsTotal(0), + _numCharsLeft(0), _numCharsPrinted(0) { memset(_stringParameters, 0, 15 * sizeof(char *)); _buffer = new char[600]; @@ -138,7 +138,7 @@ void TextDisplayer_LoL::resetDimTextPositions(int dim) { _textDimData[dim].line = 0; } -void TextDisplayer_LoL::setAnimParameters(const char *str, int x, uint8 col1, uint8 col2) { +/*void TextDisplayer_LoL::setAnimParameters(const char *str, int x, uint8 col1, uint8 col2) { static const char defaultStr[] = "<MORE>"; if (str) { @@ -152,7 +152,7 @@ void TextDisplayer_LoL::setAnimParameters(const char *str, int x, uint8 col1, ui _animColor1 = 0; _animColor2 = 0; } -} +}*/ void TextDisplayer_LoL::printDialogueText(int dim, char *str, EMCState *script, const uint16 *paramList, int16 paramIndex) { int oldDim = 0; @@ -496,7 +496,7 @@ void TextDisplayer_LoL::printLine(char *str) { int lines = (sd->h - _screen->_charOffset) / fh; while (_textDimData[sdx].line >= lines) { - if (lines <= _lineCount && _animFlag) { + if (lines <= _lineCount) { _lineCount = 0; textPageBreak(); _numCharsPrinted = 0; @@ -521,8 +521,8 @@ void TextDisplayer_LoL::printLine(char *str) { char c = 0; if ((lw + _textDimData[sdx].column) > w) { - if ((lines - 1) <= _lineCount && _animFlag) - w -= (_animWidth * (_screen->getFontWidth() + _screen->_charWidth)); + if ((lines - 1) <= _lineCount) + w -= (10 * (_screen->getFontWidth() + _screen->_charWidth)); w -= _textDimData[sdx].column; @@ -608,7 +608,7 @@ void TextDisplayer_LoL::textPageBreak() { } uint32 speechPartTime = 0; - if (_vm->_speechFlag && _vm->_activeVoiceFileTotalTime && _numCharsTotal) + if (_vm->speechEnabled() && _vm->_activeVoiceFileTotalTime && _numCharsTotal) speechPartTime = _vm->_system->getMillis() + ((_numCharsPrinted * _vm->_activeVoiceFileTotalTime) / _numCharsTotal); const ScreenDim *dim = _screen->getScreenDim(_screen->curDimIndex()); @@ -643,7 +643,7 @@ void TextDisplayer_LoL::textPageBreak() { while (!inputFlag) { _vm->update(); - if (_vm->_speechFlag) { + if (_vm->speechEnabled()) { if (((_vm->_system->getMillis() > speechPartTime) || (_vm->snd_updateCharacterSpeech() != 2)) && speechPartTime) { loop = false; inputFlag = 43; diff --git a/engines/kyra/text_lol.h b/engines/kyra/text_lol.h index fc707843aa..06c13e1fef 100644 --- a/engines/kyra/text_lol.h +++ b/engines/kyra/text_lol.h @@ -40,9 +40,6 @@ public: TextDisplayer_LoL(LoLEngine *vm, Screen_LoL *screen); ~TextDisplayer_LoL(); - void setAnimParameters(const char *str, int x, uint8 col1, uint8 col2); - void setAnimFlag(bool flag) { _animFlag = flag; } - void setupField(bool mode); void expandField(); @@ -80,12 +77,6 @@ private: uint32 _numCharsLeft; uint32 _numCharsPrinted; - const char *_animString; - int16 _animWidth; - uint8 _animColor1; - uint8 _animColor2; - - bool _animFlag; bool _printFlag; LoLEngine *_vm; diff --git a/engines/kyra/text_mr.cpp b/engines/kyra/text_mr.cpp index e28d97d154..40f651ab01 100644 --- a/engines/kyra/text_mr.cpp +++ b/engines/kyra/text_mr.cpp @@ -581,7 +581,7 @@ void KyraEngine_MR::albumChatWaitToFinish() { frame = 13; albumRestoreRect(); - _album.wsa->displayFrame(frame, 2, -100, 90, 0x4000); + _album.wsa->displayFrame(frame, 2, -100, 90, 0x4000, 0, 0); albumUpdateRect(); nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength; diff --git a/engines/kyra/util.cpp b/engines/kyra/util.cpp index 794a1c78e3..fe02ba49ba 100644 --- a/engines/kyra/util.cpp +++ b/engines/kyra/util.cpp @@ -85,5 +85,68 @@ void Util::decodeString2(const char *src, char *dst) { *dst = 0; } +void Util::convertDOSToISO(char *str) { + uint8 *s = (uint8 *)str; + + for (; *s; ++s) { + if (*s >= 128) { + uint8 c = _charMapDOSToISO[*s - 128]; + + if (!c) + c = 0x20; + + *s = c; + } + } +} + +void Util::convertISOToDOS(char *str) { + while (*str) + convertISOToDOS(*str++); +} + +void Util::convertISOToDOS(char &c) { + uint8 code = (uint8)c; + if (code >= 128) { + code = _charMapISOToDOS[code - 128]; + if (!code) + code = 0x20; + } + + c = code; +} + +// CP850 to ISO-8859-1 (borrowed from engines/saga/font_map.cpp) +const uint8 Util::_charMapDOSToISO[128] = { + 199, 252, 233, 226, 228, 224, 229, 231, 234, 235, 232, + 239, 238, 236, 196, 197, 201, 230, 198, 244, 246, 242, + 251, 249, 255, 214, 220, 248, 163, 216, 215, 0, 225, + 237, 243, 250, 241, 209, 170, 186, 191, 174, 172, 189, + 188, 161, 171, 187, 0, 0, 0, 0, 0, 193, 194, + 192, 169, 0, 0, 0, 0, 162, 165, 0, 0, 0, + 0, 0, 0, 0, 227, 195, 0, 0, 0, 0, 0, + 0, 0, 164, 240, 208, 202, 203, 200, 0, 205, 206, + 207, 0, 0, 0, 0, 166, 204, 0, 211, 223, 212, + 210, 245, 213, 181, 254, 222, 218, 219, 217, 253, 221, + 175, 180, 173, 177, 0, 190, 182, 167, 247, 184, 176, + 168, 183, 185, 179, 178, 0, 160 +}; + +// ISO-8859-1 to CP850 +const uint8 Util::_charMapISOToDOS[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, + 173, 189, 156, 207, 190, 221, 245, 249, 184, 166, 174, + 170, 240, 169, 238, 248, 241, 253, 252, 239, 230, 244, + 250, 247, 251, 167, 175, 172, 171, 243, 168, 183, 181, + 182, 199, 142, 143, 146, 128, 212, 144, 210, 211, 222, + 214, 215, 216, 209, 165, 227, 224, 226, 229, 153, 158, + 157, 235, 233, 234, 154, 237, 232, 225, 133, 160, 131, + 198, 132, 134, 145, 135, 138, 130, 136, 137, 141, 161, + 140, 139, 208, 164, 149, 162, 147, 228, 148, 246, 155, + 151, 163, 150, 129, 236, 231, 152 +}; + } // end of namespace Kyra diff --git a/engines/kyra/util.h b/engines/kyra/util.h index ee869d9c04..6850a4d757 100644 --- a/engines/kyra/util.h +++ b/engines/kyra/util.h @@ -34,6 +34,16 @@ class Util { public: static int decodeString1(const char *src, char *dst); static void decodeString2(const char *src, char *dst); + + // Since our current GUI font uses ISO-8859-1, this + // conversion functionallty uses that as a base. + static void convertDOSToISO(char *str); + static void convertISOToDOS(char *str); + static void convertISOToDOS(char &c); + +private: + static const uint8 _charMapDOSToISO[128]; + static const uint8 _charMapISOToDOS[128]; }; } // end of namespace Kyra diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp index 0b8f9c99a2..1225bc9976 100644 --- a/engines/kyra/vqa.cpp +++ b/engines/kyra/vqa.cpp @@ -32,12 +32,14 @@ // The jung2.vqa movie does work, but only thanks to a grotesque hack. +#include "kyra/vqa.h" + #include "common/system.h" #include "sound/audiostream.h" #include "sound/mixer.h" + #include "kyra/sound.h" #include "kyra/screen.h" -#include "kyra/vqa.h" #include "kyra/resource.h" namespace Kyra { @@ -45,6 +47,7 @@ namespace Kyra { VQAMovie::VQAMovie(KyraEngine_v1 *vm, OSystem *system) { _system = system; _vm = vm; + _screen = _vm->screen(); _opened = false; _x = _y = _drawPage = -1; } @@ -474,13 +477,13 @@ void VQAMovie::displayFrame(uint frameNum) { case MKID_BE('CPL0'): // Palette assert(size <= 3 * 256); - _file->read(_vm->screen()->_currentPalette, size); + _file->read(_screen->getPalette(0).getData(), size); break; case MKID_BE('CPLZ'): // Palette inbuf = (byte *)allocBuffer(0, size); _file->read(inbuf, size); - Screen::decodeFrame4(inbuf, _vm->screen()->_currentPalette, 768); + Screen::decodeFrame4(inbuf, _screen->getPalette(0).getData(), 768); break; case MKID_BE('VPT0'): // Frame data @@ -520,9 +523,8 @@ void VQAMovie::displayFrame(uint frameNum) { // The frame has been decoded - if (_frameInfo[frameNum] & 0x80000000) { - _vm->screen()->setScreenPalette(_vm->screen()->_currentPalette); - } + if (_frameInfo[frameNum] & 0x80000000) + _screen->setScreenPalette(_screen->getPalette(0)); int blockPitch = _header.width / _header.blockW; @@ -562,7 +564,7 @@ void VQAMovie::displayFrame(uint frameNum) { _partialCodeBookSize = 0; } - _vm->screen()->copyBlockToPage(_drawPage, _x, _y, _header.width, _header.height, _frame); + _screen->copyBlockToPage(_drawPage, _x, _y, _header.width, _header.height, _frame); } void VQAMovie::play() { @@ -638,6 +640,7 @@ void VQAMovie::play() { } _vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sound, _stream); + Common::EventManager *eventMan = _vm->getEventManager(); for (uint i = 0; i < _header.numFrames; i++) { displayFrame(i); @@ -656,17 +659,17 @@ void VQAMovie::play() { break; Common::Event event; - - Common::EventManager *eventMan = _system->getEventManager(); while (eventMan->pollEvent(event)) { switch (event.type) { case Common::EVENT_KEYDOWN: - if (event.kbd.ascii == 27) + if (event.kbd.keycode == Common::KEYCODE_ESCAPE) return; break; + case Common::EVENT_RTL: case Common::EVENT_QUIT: return; + default: break; } @@ -675,7 +678,7 @@ void VQAMovie::play() { _system->delayMillis(10); } - _vm->screen()->updateScreen(); + _screen->updateScreen(); } // TODO: Wait for the sound to finish? diff --git a/engines/kyra/vqa.h b/engines/kyra/vqa.h index 46d3bd48fb..98e279bd29 100644 --- a/engines/kyra/vqa.h +++ b/engines/kyra/vqa.h @@ -26,13 +26,24 @@ #ifndef KYRA_VQA_H #define KYRA_VQA_H -#include "common/stream.h" +#include "common/scummsys.h" + +#include "sound/mixer.h" class OSystem; +namespace Audio { +class AppendableAudioStream; +} // end of namespace Audio + +namespace Common { +class SeekableReadStream; +} // end of namespace Common + namespace Kyra { class KyraEngine_v1; +class Screen; class VQAMovie { public: @@ -57,6 +68,7 @@ public: protected: OSystem *_system; KyraEngine_v1 *_vm; + Screen *_screen; bool _opened; int _x, _y; diff --git a/engines/kyra/wsamovie.cpp b/engines/kyra/wsamovie.cpp index 26638b8172..ef3fd1a966 100644 --- a/engines/kyra/wsamovie.cpp +++ b/engines/kyra/wsamovie.cpp @@ -38,7 +38,7 @@ namespace Kyra { WSAMovie_v1::WSAMovie_v1(KyraEngine_v1 *vm) : Movie(vm) {} WSAMovie_v1::~WSAMovie_v1() { close(); } -int WSAMovie_v1::open(const char *filename, int offscreenDecode, uint8 *palBuf) { +int WSAMovie_v1::open(const char *filename, int offscreenDecode, Palette *palBuf) { close(); uint32 flags = 0; @@ -64,7 +64,7 @@ int WSAMovie_v1::open(const char *filename, int offscreenDecode, uint8 *palBuf) offsPal = 0x300; _flags |= WF_HAS_PALETTE; if (palBuf) - memcpy(palBuf, wsaData + 8 + (_numFrames << 2), 0x300); + _screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x300); } if (offscreenDecode) { @@ -137,19 +137,19 @@ void WSAMovie_v1::close() { } } -void WSAMovie_v1::displayFrame(int frameNum, int pageNum, int x, int y, ...) { - if (frameNum >= _numFrames || !_opened) +void WSAMovie_v1::displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) { + if (frameNum >= _numFrames || frameNum < 0 || !_opened) return; _x = x; _y = y; _drawPage = pageNum; - uint8 *dst; + uint8 *dst = 0; if (_flags & WF_OFFSCREEN_DECODE) dst = _offscreenBuffer; else - dst = _vm->screen()->getPageRect(_drawPage, _x, _y, _width, _height); + dst = _screen->getPageRect(_drawPage, _x, _y, _width, _height); if (_currentFrame == _numFrames) { if (!(_flags & WF_NO_FIRST_FRAME)) { @@ -200,8 +200,16 @@ void WSAMovie_v1::displayFrame(int frameNum, int pageNum, int x, int y, ...) { // display _currentFrame = frameNum; - if (_flags & WF_OFFSCREEN_DECODE) - _vm->screen()->copyBlockToPage(_drawPage, _x, _y, _width, _height, _offscreenBuffer); + if (_flags & WF_OFFSCREEN_DECODE) { + int pageBackUp = _screen->setCurPage(_drawPage); + + int plotFunc = (flags & 0xFF00) >> 12; + int unk1 = flags & 0xFF; + + _screen->copyWsaRect(_x, _y, _width, _height, 0, plotFunc, _offscreenBuffer, unk1, table1, table2); + + _screen->_curPage = pageBackUp; + } } void WSAMovie_v1::processFrame(int frameNum, uint8 *dst) { @@ -220,7 +228,7 @@ void WSAMovie_v1::processFrame(int frameNum, uint8 *dst) { WSAMovieAmiga::WSAMovieAmiga(KyraEngine_v1 *vm) : WSAMovie_v1(vm), _buffer(0) {} -int WSAMovieAmiga::open(const char *filename, int offscreenDecode, uint8 *palBuf) { +int WSAMovieAmiga::open(const char *filename, int offscreenDecode, Palette *palBuf) { int res = WSAMovie_v1::open(filename, offscreenDecode, palBuf); if (!res) @@ -239,7 +247,7 @@ void WSAMovieAmiga::close() { WSAMovie_v1::close(); } -void WSAMovieAmiga::displayFrame(int frameNum, int pageNum, int x, int y, ...) { +void WSAMovieAmiga::displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) { if (frameNum >= _numFrames || frameNum < 0 || !_opened) return; @@ -266,7 +274,7 @@ void WSAMovieAmiga::displayFrame(int frameNum, int pageNum, int x, int y, ...) { dst = _buffer; } else { - _vm->screen()->copyBlockToPage(_drawPage, _x, _y, _width, _height, _buffer); + _screen->copyBlockToPage(_drawPage, _x, _y, _width, _height, _buffer); } } _currentFrame = 0; @@ -311,8 +319,16 @@ void WSAMovieAmiga::displayFrame(int frameNum, int pageNum, int x, int y, ...) { // display _currentFrame = frameNum; - if (_flags & WF_OFFSCREEN_DECODE) - _vm->screen()->copyBlockToPage(_drawPage, _x, _y, _width, _height, _offscreenBuffer); + if (_flags & WF_OFFSCREEN_DECODE) { + int pageBackUp = _screen->setCurPage(_drawPage); + + int plotFunc = (flags & 0xFF00) >> 12; + int unk1 = flags & 0xFF; + + _screen->copyWsaRect(_x, _y, _width, _height, 0, plotFunc, _offscreenBuffer, unk1, table1, table2); + + _screen->_curPage = pageBackUp; + } } void WSAMovieAmiga::processFrame(int frameNum, uint8 *dst) { @@ -334,7 +350,7 @@ void WSAMovieAmiga::processFrame(int frameNum, uint8 *dst) { dst = _offscreenBuffer; dstPitch = _width; } else { - dst = _vm->screen()->getPageRect(_drawPage, _x, _y, _width, _height); + dst = _screen->getPageRect(_drawPage, _x, _y, _width, _height); dstPitch = Screen::SCREEN_W; } @@ -347,9 +363,9 @@ void WSAMovieAmiga::processFrame(int frameNum, uint8 *dst) { #pragma mark - -WSAMovie_v2::WSAMovie_v2(KyraEngine_v1 *vm, Screen_v2 *screen) : WSAMovie_v1(vm), _screen(screen), _xAdd(0), _yAdd(0) {} +WSAMovie_v2::WSAMovie_v2(KyraEngine_v1 *vm) : WSAMovie_v1(vm), _xAdd(0), _yAdd(0) {} -int WSAMovie_v2::open(const char *filename, int unk1, uint8 *palBuf) { +int WSAMovie_v2::open(const char *filename, int unk1, Palette *palBuf) { close(); uint32 flags = 0; @@ -376,7 +392,7 @@ int WSAMovie_v2::open(const char *filename, int unk1, uint8 *palBuf) { offsPal = 0x300; _flags |= WF_HAS_PALETTE; if (palBuf) - _vm->screen()->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), palBuf, 0x300); + _screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x300); } if (flags & 2) { @@ -384,7 +400,7 @@ int WSAMovie_v2::open(const char *filename, int unk1, uint8 *palBuf) { offsPal = 0x30; _flags |= WF_HAS_PALETTE; if (palBuf) - _vm->screen()->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), palBuf, 0x30); + _screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x30); } _flags |= WF_XOR; @@ -448,90 +464,6 @@ int WSAMovie_v2::open(const char *filename, int unk1, uint8 *palBuf) { return _numFrames; } -void WSAMovie_v2::displayFrame(int frameNum, int pageNum, int x, int y, ...) { - if (frameNum >= _numFrames || frameNum < 0 || !_opened) - return; - - _x = x + _xAdd; - _y = y + _yAdd; - _drawPage = pageNum; - - uint8 *dst = 0; - if (_flags & WF_OFFSCREEN_DECODE) - dst = _offscreenBuffer; - else - dst = _screen->getPageRect(_drawPage, _x, _y, _width, _height); - - if (_currentFrame == _numFrames) { - if (!(_flags & WF_NO_FIRST_FRAME)) { - if (_flags & WF_OFFSCREEN_DECODE) - Screen::decodeFrameDelta(dst, _deltaBuffer); - else - Screen::decodeFrameDeltaPage(dst, _deltaBuffer, _width, (_flags & WF_XOR) == 0); - } - _currentFrame = 0; - } - - // try to reduce the number of needed frame operations - int diffCount = ABS(_currentFrame - frameNum); - int frameStep = 1; - int frameCount; - if (_currentFrame < frameNum) { - frameCount = _numFrames - frameNum + _currentFrame; - if (diffCount > frameCount && !(_flags & WF_NO_LAST_FRAME)) - frameStep = -1; - else - frameCount = diffCount; - } else { - frameCount = _numFrames - _currentFrame + frameNum; - if (frameCount >= diffCount || (_flags & WF_NO_LAST_FRAME)) { - frameStep = -1; - frameCount = diffCount; - } - } - - // process - if (frameStep > 0) { - uint16 cf = _currentFrame; - while (frameCount--) { - cf += frameStep; - processFrame(cf, dst); - if (cf == _numFrames) - cf = 0; - } - } else { - uint16 cf = _currentFrame; - while (frameCount--) { - if (cf == 0) - cf = _numFrames; - processFrame(cf, dst); - cf += frameStep; - } - } - - // display - _currentFrame = frameNum; - if (_flags & WF_OFFSCREEN_DECODE) { - int pageBackUp = _screen->_curPage; - _screen->_curPage = _drawPage; - - va_list args; - va_start(args, y); - - int copyParam = va_arg(args, int); - int plotFunc = (copyParam & 0xFF00) >> 12; - int unk1 = copyParam & 0xFF; - - const uint8 *unkPtr1 = va_arg(args, const uint8*); - const uint8 *unkPtr2 = va_arg(args, const uint8*); - va_end(args); - - _screen->copyWsaRect(_x, _y, _width, _height, 0, plotFunc, _offscreenBuffer, unk1, unkPtr1, unkPtr2); - - _screen->_curPage = pageBackUp; - } -} - } // end of namespace Kyra diff --git a/engines/kyra/wsamovie.h b/engines/kyra/wsamovie.h index fdceca1cd8..49ac5a28fe 100644 --- a/engines/kyra/wsamovie.h +++ b/engines/kyra/wsamovie.h @@ -26,6 +26,7 @@ #ifndef KYRA_WSAMOVIE_H #define KYRA_WSAMOVIE_H + namespace Audio { class AppendableAudioStream; class SoundHandle; @@ -34,10 +35,11 @@ class SoundHandle; namespace Kyra { class KyraEngine_v1; class Screen_v2; +class Palette; class Movie { public: - Movie(KyraEngine_v1 *vm) : _vm(vm), _opened(false), _x(-1), _y(-1), _drawPage(-1) {} + Movie(KyraEngine_v1 *vm) : _vm(vm), _screen(vm->screen()), _opened(false), _x(-1), _y(-1), _drawPage(-1) {} virtual ~Movie() {} virtual bool opened() { return _opened; } @@ -48,15 +50,16 @@ public: virtual int width() const = 0; virtual int height() const = 0; - virtual int open(const char *filename, int offscreen, uint8 *palette) = 0; + virtual int open(const char *filename, int offscreen, Palette *palette) = 0; virtual void close() = 0; virtual int frames() = 0; - virtual void displayFrame(int frameNum, int pageNum, int x, int y, ...) = 0; + virtual void displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) = 0; protected: KyraEngine_v1 *_vm; + Screen *_screen; bool _opened; int _x, _y; @@ -71,12 +74,12 @@ public: int width() const { return _width; } int height() const { return _height; } - virtual int open(const char *filename, int offscreen, uint8 *palette); + virtual int open(const char *filename, int offscreen, Palette *palette); virtual void close(); virtual int frames() { return _opened ? _numFrames : -1; } - virtual void displayFrame(int frameNum, int pageNum, int x, int y, ...); + virtual void displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2); enum WSAFlags { WF_OFFSCREEN_DECODE = 0x10, @@ -104,10 +107,10 @@ protected: class WSAMovieAmiga : public WSAMovie_v1 { public: WSAMovieAmiga(KyraEngine_v1 *vm); - int open(const char *filename, int offscreen, uint8 *palette); + int open(const char *filename, int offscreen, Palette *palette); void close(); - void displayFrame(int frameNum, int pageNum, int x, int y, ...); + void displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2); private: void processFrame(int frameNum, uint8 *dst); @@ -116,11 +119,12 @@ private: class WSAMovie_v2 : public WSAMovie_v1 { public: - WSAMovie_v2(KyraEngine_v1 *vm, Screen_v2 *screen); - - int open(const char *filename, int unk1, uint8 *palette); + WSAMovie_v2(KyraEngine_v1 *vm); - virtual void displayFrame(int frameNum, int pageNum, int x, int y, ...); + int open(const char *filename, int unk1, Palette *palette); + virtual void displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) { + WSAMovie_v1::displayFrame(frameNum, pageNum, x + _xAdd, y + _yAdd, flags, table1, table2); + } int xAdd() const { return _xAdd; } int yAdd() const { return _yAdd; } @@ -128,8 +132,6 @@ public: void setWidth(int w) { _width = w; } void setHeight(int h) { _height = h; } protected: - Screen_v2 *_screen; - int16 _xAdd; int16 _yAdd; }; diff --git a/engines/parallaction/disk.cpp b/engines/parallaction/disk.cpp new file mode 100644 index 0000000000..6928c1eefc --- /dev/null +++ b/engines/parallaction/disk.cpp @@ -0,0 +1,145 @@ +/* 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 "parallaction/disk.h" +#include "parallaction/graphics.h" + +namespace Parallaction { + +void ILBMLoader::setupBuffer(uint32 w, uint32 h) { + _intBuffer = 0; + switch (_bodyMode) { + case BODYMODE_SURFACE: + if (!_surf) { + _surf = new Graphics::Surface; + assert(_surf); + } + _surf->create(w, h, 1); + _mode = Graphics::ILBMDecoder::ILBM_UNPACK_PLANES; + _intBuffer = (byte*)_surf->pixels; + break; + + case BODYMODE_MASKBUFFER: + if (!_maskBuffer) { + _maskBuffer = new MaskBuffer; + assert(_maskBuffer); + } + _maskBuffer->create(w, h); + _mode = Graphics::ILBMDecoder::ILBM_2_PACK_PLANES; + _intBuffer = _maskBuffer->data; + break; + + case BODYMODE_PATHBUFFER: + if (!_pathBuffer) { + _pathBuffer = new PathBuffer; + assert(_pathBuffer); + } + _pathBuffer->create(w, h); + _mode = Graphics::ILBMDecoder::ILBM_1_PACK_PLANES; + _intBuffer = _pathBuffer->data; + break; + + default: + error("Invalid bodyMode '%i' for ILBMLoader", _bodyMode); + break; + } +} + +bool ILBMLoader::callback(Common::IFFChunk &chunk) { + switch (chunk._type) { + case ID_BMHD: + _decoder.loadHeader(chunk._stream); + break; + + case ID_CMAP: + if (_palette) { + chunk._stream->read(_palette, chunk._size); + } + break; + + case ID_CRNG: + if (_crng) { + PaletteFxRange *ptr = &_crng[_numCRNG]; + chunk._stream->read((byte*)ptr, chunk._size); + ptr->_timer = FROM_BE_16(ptr->_timer); + ptr->_step = FROM_BE_16(ptr->_step); + ptr->_flags = FROM_BE_16(ptr->_flags); + ++_numCRNG; + } + break; + + case ID_BODY: + setupBuffer(_decoder._header.width, _decoder._header.height); + assert(_intBuffer); + _decoder.loadBitmap(_mode, _intBuffer, chunk._stream); + return true; // stop the parser + } + + return false; +} + +void ILBMLoader::load(Common::ReadStream *in, bool disposeStream) { + Common::IFFParser parser(in, disposeStream); + Common::Functor1Mem< Common::IFFChunk&, bool, ILBMLoader > c(this, &ILBMLoader::callback); + parser.parse(c); +} + +ILBMLoader::ILBMLoader(uint32 bodyMode, byte *palette, PaletteFxRange *crng) { + _bodyMode = bodyMode; + _surf = 0; + _maskBuffer = 0; + _pathBuffer = 0; + _palette = palette; + _crng = crng; + _numCRNG = 0; +} + +ILBMLoader::ILBMLoader(Graphics::Surface *surf, byte *palette, PaletteFxRange *crng) { + _bodyMode = ILBMLoader::BODYMODE_SURFACE; + _surf = surf; + _palette = palette; + _crng = crng; + _numCRNG = 0; +} + +ILBMLoader::ILBMLoader(MaskBuffer *buffer) { + _bodyMode = ILBMLoader::BODYMODE_MASKBUFFER; + _maskBuffer = buffer; + _palette = 0; + _crng = 0; + _numCRNG = 0; +} + +ILBMLoader::ILBMLoader(PathBuffer *buffer) { + _bodyMode = ILBMLoader::BODYMODE_PATHBUFFER; + _pathBuffer = buffer; + _palette = 0; + _crng = 0; + _numCRNG = 0; +} + + + +} diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h index 4cc2711e96..a9da429473 100644 --- a/engines/parallaction/disk.h +++ b/engines/parallaction/disk.h @@ -33,6 +33,7 @@ #include "common/file.h" #include "graphics/surface.h" +#include "graphics/iff.h" @@ -77,8 +78,37 @@ public: virtual Table* loadTable(const char* name) = 0; virtual Common::SeekableReadStream* loadMusic(const char* name) = 0; virtual Common::SeekableReadStream* loadSound(const char* name) = 0; - virtual void loadMask(const char *name, MaskBuffer &buffer) { } - virtual void loadPath(const char *name, PathBuffer &buffer) { } + virtual MaskBuffer *loadMask(const char *name, uint32 w, uint32 h) { return 0; } + virtual PathBuffer *loadPath(const char *name, uint32 w, uint32 h) { return 0; } +}; + +struct PaletteFxRange; + +struct ILBMLoader { + enum { + BODYMODE_SURFACE, + BODYMODE_MASKBUFFER, + BODYMODE_PATHBUFFER + }; + uint32 _bodyMode; + Graphics::Surface *_surf; + MaskBuffer *_maskBuffer; + PathBuffer *_pathBuffer; + byte *_palette; + PaletteFxRange *_crng; + uint32 _mode; + byte* _intBuffer; + uint32 _numCRNG; + Graphics::ILBMDecoder _decoder; + + ILBMLoader(uint32 bodyMode, byte *palette = 0, PaletteFxRange *crng = 0); + ILBMLoader(Graphics::Surface *surf, byte *palette = 0, PaletteFxRange *crng = 0); + ILBMLoader(MaskBuffer *buffer); + ILBMLoader(PathBuffer *buffer); + + bool callback(Common::IFFChunk &chunk); + void setupBuffer(uint32 w, uint32 h); + void load(Common::ReadStream *in, bool disposeStream = false); }; @@ -235,8 +265,8 @@ public: Table* loadTable(const char* name); Common::SeekableReadStream* loadMusic(const char* name); Common::SeekableReadStream* loadSound(const char* name); - void loadMask(const char *name, MaskBuffer &buffer); - void loadPath(const char *name, PathBuffer &buffer); + MaskBuffer *loadMask(const char *name, uint32 w, uint32 h); + PathBuffer *loadPath(const char *name, uint32 w, uint32 h); }; class DosDemoDisk_br : public DosDisk_br { @@ -272,7 +302,7 @@ public: GfxObj* loadObjects(const char *name, uint8 part = 0); Common::SeekableReadStream* loadMusic(const char* name); Common::SeekableReadStream* loadSound(const char* name); - void loadMask(const char *name, MaskBuffer &buffer); + MaskBuffer *loadMask(const char *name, uint32 w, uint32 h); }; } // namespace Parallaction diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index ec4fc32cc1..46c849e6f2 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -28,7 +28,6 @@ #include "common/config-manager.h" #include "parallaction/parallaction.h" #include "parallaction/parser.h" -#include "parallaction/iff.h" namespace Parallaction { @@ -331,32 +330,40 @@ void DosDisk_br::loadSlide(BackgroundInfo& info, const char *name) { } } -void DosDisk_br::loadMask(const char *name, MaskBuffer &buffer) { +MaskBuffer *DosDisk_br::loadMask(const char *name, uint32 w, uint32 h) { if (!name) { - return; + return 0; } Common::SeekableReadStream *stream = openFile("msk/" + Common::String(name), ".msk"); - // NOTE: info.width and info.height are only valid if the background graphics - // have already been loaded - buffer.bigEndian = false; - stream->read(buffer.data, buffer.size); + MaskBuffer *buffer = new MaskBuffer; + assert(buffer); + buffer->create(w, h); + buffer->bigEndian = false; + + stream->read(buffer->data, buffer->size); delete stream; + + return buffer; } -void DosDisk_br::loadPath(const char *name, PathBuffer &buffer) { +PathBuffer *DosDisk_br::loadPath(const char *name, uint32 w, uint32 h) { if (!name) { - return; + return 0; } Common::SeekableReadStream *stream = openFile("pth/" + Common::String(name), ".pth"); - // NOTE: info.width and info.height are only valid if the background graphics - // have already been loaded - buffer.bigEndian = false; - stream->read(buffer.data, buffer.size); + PathBuffer *buffer = new PathBuffer; + assert(buffer); + buffer->create(w, h); + buffer->bigEndian = false; + + stream->read(buffer->data, buffer->size); delete stream; + + return buffer; } void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char *mask, const char* path) { @@ -380,18 +387,12 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char } if (mask) { - info._mask = new MaskBuffer; - info._mask->create(info.width, info.height); - loadMask(mask, *info._mask); + info._mask = loadMask(mask, info.width, info.height); } if (path) { - info._path = new PathBuffer; - info._path->create(info.width, info.height); - loadPath(path, *info._path); + info._path = loadPath(path, info.width, info.height); } - - return; } Table* DosDisk_br::loadTable(const char* name) { @@ -459,7 +460,7 @@ void AmigaDisk_br::adjustForPalette(Graphics::Surface &surf, int transparentColo void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) { byte r,g,b; - byte *pal, *p; + byte *p; Common::SeekableReadStream *stream; uint i; @@ -488,20 +489,14 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) { } stream = openFile("backs/" + Common::String(filename), ".bkg"); - ILBMDecoder decoder(stream, true); - // TODO: encapsulate surface creation - info.bg.w = decoder.getWidth(); - info.bg.h = decoder.getHeight(); - info.bg.pitch = info.bg.w; - info.bg.bytesPerPixel = 1; - info.bg.pixels = decoder.getBitmap(); - assert(info.bg.pixels); + byte pal[768]; + ILBMLoader loader(&info.bg, pal); + loader.load(stream, true); info.width = info.bg.w; info.height = info.bg.h; - pal = decoder.getPalette(); p = pal; for (i = 16; i < 32; i++) { r = *p >> 2; @@ -516,8 +511,6 @@ void AmigaDisk_br::loadBackground(BackgroundInfo& info, const char *filename) { // Overwrite the first color (transparent key) in the palette info.palette.setEntry(0, pal[0] >> 2, pal[1] >> 2, pal[2] >> 0); - delete []pal; - // background data is drawn used the upper portion of the palette adjustForPalette(info.bg); } @@ -543,27 +536,24 @@ void finalpass(byte *buffer, uint32 size) { } } -void AmigaDisk_br::loadMask(const char *name, MaskBuffer &buffer) { +MaskBuffer *AmigaDisk_br::loadMask(const char *name, uint32 w, uint32 h) { if (!name) { - return; + return 0; } debugC(1, kDebugDisk, "AmigaDisk_br::loadMask '%s'", name); Common::SeekableReadStream *stream = tryOpenFile("msk/" + Common::String(name), ".msk"); if (!stream) { - return; + return 0; } - ILBMDecoder decoder(stream, true); + ILBMLoader loader(ILBMLoader::BODYMODE_MASKBUFFER); + loader.load(stream, true); - // TODO: the buffer is allocated by the caller, so a copy here is - // unavoidable... a better solution would be inform the function - // of the size of the mask (the size in the mask file is not valid!) - byte *bitmap = decoder.getBitmap(2, true); - memcpy(buffer.data, bitmap, buffer.size); - finalpass(buffer.data, buffer.size); - - buffer.bigEndian = true; + MaskBuffer *buffer = loader._maskBuffer; + buffer->bigEndian = true; + finalpass(buffer->data, buffer->size); + return buffer; } void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const char* mask, const char* path) { @@ -573,18 +563,12 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha loadBackground(info, name); } if (mask) { - info._mask = new MaskBuffer; - info._mask->create(info.width, info.height); - loadMask(mask, *info._mask); + info._mask = loadMask(mask, info.width, info.height); } if (path) { - info._path = new PathBuffer; - info._path->create(info.width, info.height); - loadPath(path, *info._path); + info._path = loadPath(path, info.width, info.height); } - - return; } void AmigaDisk_br::loadSlide(BackgroundInfo& info, const char *name) { @@ -596,20 +580,13 @@ GfxObj* AmigaDisk_br::loadStatic(const char* name) { debugC(1, kDebugDisk, "AmigaDisk_br::loadStatic '%s'", name); Common::String sName = name; - Common::SeekableReadStream *stream = openFile("ras/" + sName, ".ras"); - ILBMDecoder decoder(stream, true); - Graphics::Surface* surf = new Graphics::Surface; - assert(surf); + ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE); + loader.load(stream, true); - // TODO: encapsulate surface creation - surf->w = decoder.getWidth(); - surf->h = decoder.getHeight(); - surf->pitch = surf->w; - surf->bytesPerPixel = 1; - surf->pixels = decoder.getBitmap(); - assert(surf->pixels); + Graphics::Surface* surf = loader._surf; + assert(surf); // Static pictures are drawn used the upper half of the palette: this must be // done before shadow mask is applied. This way, only really transparent pixels @@ -741,15 +718,16 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name, uint8 part) { debugC(5, kDebugDisk, "AmigaDisk_br::loadObjects"); Common::SeekableReadStream *stream = openFile(name); - ILBMDecoder decoder(stream, true); + ILBMLoader loader(ILBMLoader::BODYMODE_SURFACE); + loader.load(stream, true); uint16 max = objectsMax[part]; if (_vm->getFeatures() & GF_DEMO) max = 72; byte *data = new byte[max * 2601]; - byte *srcPtr = decoder.getBitmap(); - int w = decoder.getWidth(); + byte *srcPtr = (byte*)loader._surf->getBasePtr(0,0); + int w = loader._surf->w; // Convert to the expected display format for (int i = 0; i < max; i++) { @@ -764,7 +742,7 @@ GfxObj* AmigaDisk_br::loadObjects(const char *name, uint8 part) { dst += 51; } } - free(srcPtr); + delete loader._surf; return new GfxObj(0, new Cnv(max, 51, 51, data, true)); } diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp index 8aa2a9f543..d35b338069 100644 --- a/engines/parallaction/disk_ns.cpp +++ b/engines/parallaction/disk_ns.cpp @@ -23,18 +23,11 @@ * */ -#include "parallaction/iff.h" #include "common/config-manager.h" #include "parallaction/parser.h" #include "parallaction/parallaction.h" -namespace Audio { - class AudioStream; - - AudioStream *make8SVXStream(Common::ReadStream &input); -} - namespace Parallaction { @@ -900,56 +893,18 @@ void AmigaDisk_ns::buildMask(byte* buf) { } } -// TODO: extend the ILBMDecoder to return CRNG chunks and get rid of this BackgroundDecoder crap -class BackgroundDecoder : public ILBMDecoder { - -public: - BackgroundDecoder(Common::SeekableReadStream *input, bool disposeStream = false) : ILBMDecoder(input, disposeStream) { - } - - uint32 getCRNG(PaletteFxRange *ranges, uint32 num) { - assert(ranges); - - uint32 size = _parser.getIFFBlockSize(ID_CRNG); - if (size == (uint32)-1) { - return 0; - } - - uint32 count = MIN((uint32)(size / sizeof(PaletteFxRange)), num); - _parser.loadIFFBlock(ID_CRNG, ranges, count * sizeof(PaletteFxRange)); - - for (uint32 i = 0; i < count; ++i) { - ranges[i]._timer = FROM_BE_16(ranges[i]._timer); - ranges[i]._step = FROM_BE_16(ranges[i]._step); - ranges[i]._flags = FROM_BE_16(ranges[i]._flags); - } - - return count; - } -}; - void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) { - - Common::SeekableReadStream *s = openFile(name); - BackgroundDecoder decoder(s, true); - PaletteFxRange ranges[6]; - memset(ranges, 0, 6*sizeof(PaletteFxRange)); - decoder.getCRNG(ranges, 6); + byte pal[768]; - // TODO: encapsulate surface creation - info.bg.w = decoder.getWidth(); - info.bg.h = decoder.getHeight(); - info.bg.pitch = info.bg.w; - info.bg.bytesPerPixel = 1; - info.bg.pixels = decoder.getBitmap(); + Common::SeekableReadStream *s = openFile(name); + ILBMLoader loader(&info.bg, pal, ranges); + loader.load(s, true); info.width = info.bg.w; info.height = info.bg.h; - byte *pal = decoder.getPalette(); - assert(pal); byte *p = pal; for (uint i = 0; i < 32; i++) { byte r = *p >> 2; @@ -960,7 +915,6 @@ void AmigaDisk_ns::loadBackground(BackgroundInfo& info, const char *name) { p++; info.palette.setEntry(i, r, g, b); } - delete []pal; for (uint j = 0; j < 6; j++) { info.setPaletteRange(j, ranges[j]); @@ -979,9 +933,9 @@ void AmigaDisk_ns::loadMask(BackgroundInfo& info, const char *name) { return; // no errors if missing mask files: not every location has one } - ILBMDecoder decoder(s, true); - byte *pal = decoder.getPalette(); - assert(pal); + byte pal[768]; + ILBMLoader loader(ILBMLoader::BODYMODE_MASKBUFFER, pal); + loader.load(s, true); byte r, g, b; for (uint i = 0; i < 4; i++) { @@ -990,14 +944,8 @@ void AmigaDisk_ns::loadMask(BackgroundInfo& info, const char *name) { b = pal[i*3+2]; info.layers[i] = (((r << 4) & 0xF00) | (g & 0xF0) | (b >> 4)) & 0xFF; } - delete []pal; - info._mask = new MaskBuffer; - info._mask->w = info.width; - info._mask->h = info.height; - info._mask->internalWidth = info.width >> 2; - info._mask->size = info._mask->internalWidth * info._mask->h; - info._mask->data = decoder.getBitmap(2, true); + info._mask = loader._maskBuffer; } void AmigaDisk_ns::loadPath(BackgroundInfo& info, const char *name) { @@ -1010,15 +958,10 @@ void AmigaDisk_ns::loadPath(BackgroundInfo& info, const char *name) { return; // no errors if missing path files: not every location has one } - ILBMDecoder decoder(s, true); - info._path = new PathBuffer; - info._path->create(info.width, info.height); + ILBMLoader loader(ILBMLoader::BODYMODE_PATHBUFFER); + loader.load(s, true); + info._path = loader._pathBuffer; info._path->bigEndian = true; - - byte *bitmap = decoder.getBitmap(1, true); - assert(bitmap); - memcpy(info._path->data, bitmap, info._path->size); - delete bitmap; } void AmigaDisk_ns::loadScenery(BackgroundInfo& info, const char* background, const char* mask, const char* path) { diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index ec72b14c15..fc6cb28d9e 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -162,9 +162,7 @@ void BackgroundInfo::loadGfxObjMask(const char *name, GfxObj *obj) { Common::Rect rect; obj->getRect(0, rect); - MaskBuffer *buf = new MaskBuffer; - buf->create(rect.width(), rect.height()); - _vm->_disk->loadMask(name, *buf); + MaskBuffer *buf = _vm->_disk->loadMask(name, rect.width(), rect.height()); obj->_maskId = addMaskPatch(buf); obj->_hasMask = true; @@ -174,9 +172,7 @@ void BackgroundInfo::loadGfxObjPath(const char *name, GfxObj *obj) { Common::Rect rect; obj->getRect(0, rect); - PathBuffer *buf = new PathBuffer; - buf->create(rect.width(), rect.height()); - _vm->_disk->loadPath(name, *buf); + PathBuffer *buf = _vm->_disk->loadPath(name, rect.width(), rect.height()); obj->_pathId = addPathPatch(buf); obj->_hasPath = true; diff --git a/engines/parallaction/iff.cpp b/engines/parallaction/iff.cpp deleted file mode 100644 index 43dcac3697..0000000000 --- a/engines/parallaction/iff.cpp +++ /dev/null @@ -1,276 +0,0 @@ -/* 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 "common/iff_container.h" -#include "common/stream.h" -#include "common/util.h" -#include "parallaction/iff.h" - -namespace Parallaction { - - -void IFFParser::setInputStream(Common::SeekableReadStream *stream) { - destroy(); - - assert(stream); - _stream = stream; - _startOffset = 0; - _endOffset = _stream->size(); - - _formType = 0; - _formSize = (uint32)-1; - - if (_stream->size() < 12) { - // this file is too small to be a valid IFF container - return; - } - - if (_stream->readUint32BE() != ID_FORM) { - // no FORM header was found - return; - } - - _formSize = _stream->readUint32BE(); - _formType = _stream->readUint32BE(); -} - -void IFFParser::destroy() { - _stream = 0; - _startOffset = _endOffset = 0; -} - -uint32 IFFParser::getFORMSize() const { - return _formSize; -} - -Common::IFF_ID IFFParser::getFORMType() const { - return _formType; -} - -uint32 IFFParser::moveToIFFBlock(Common::IFF_ID chunkName) { - uint32 size = (uint32)-1; - - _stream->seek(_startOffset + 0x0C); - - while ((uint)_stream->pos() < _endOffset) { - uint32 chunk = _stream->readUint32BE(); - uint32 size_temp = _stream->readUint32BE(); - - if (chunk != chunkName) { - _stream->seek((size_temp + 1) & (~1), SEEK_CUR); - assert((uint)_stream->pos() <= _endOffset); - } else { - size = size_temp; - break; - } - } - - return size; -} - -uint32 IFFParser::getIFFBlockSize(Common::IFF_ID chunkName) { - uint32 size = moveToIFFBlock(chunkName); - return size; -} - -bool IFFParser::loadIFFBlock(Common::IFF_ID chunkName, void *loadTo, uint32 ptrSize) { - uint32 chunkSize = moveToIFFBlock(chunkName); - - if (chunkSize == (uint32)-1) { - return false; - } - - uint32 loadSize = 0; - loadSize = MIN(ptrSize, chunkSize); - _stream->read(loadTo, loadSize); - return true; -} - -Common::SeekableReadStream *IFFParser::getIFFBlockStream(Common::IFF_ID chunkName) { - uint32 chunkSize = moveToIFFBlock(chunkName); - - if (chunkSize == (uint32)-1) { - return 0; - } - - uint32 pos = _stream->pos(); - return new Common::SeekableSubReadStream(_stream, pos, pos + chunkSize, false); -} - - -// ILBM decoder implementation - -ILBMDecoder::ILBMDecoder(Common::SeekableReadStream *in, bool disposeStream) : _in(in), _disposeStream(disposeStream), _hasHeader(false), _bodySize((uint32)-1), _paletteSize((uint32)-1) { - assert(in); - _parser.setInputStream(in); - - if (_parser.getFORMType() != ID_ILBM) { - return; - } - - _hasHeader = _parser.loadIFFBlock(ID_BMHD, &_header, sizeof(_header)); - if (!_hasHeader) { - return; - } - - _header.width = TO_BE_16(_header.width); - _header.height = TO_BE_16(_header.height); - - _paletteSize = _parser.getIFFBlockSize(ID_CMAP); - _bodySize = _parser.getIFFBlockSize(ID_BODY); -} - - -ILBMDecoder::~ILBMDecoder() { - if (_disposeStream) { - delete _in; - } -} - -uint32 ILBMDecoder::getWidth() { - assert(_hasHeader); - return _header.width; -} - -uint32 ILBMDecoder::getHeight() { - assert(_hasHeader); - return _header.height; -} - -uint32 ILBMDecoder::getNumColors() { - assert(_hasHeader); - return (1 << _header.depth); -} - -byte *ILBMDecoder::getPalette() { - assert(_paletteSize != (uint32)-1); - byte *palette = new byte[_paletteSize]; - assert(palette); - _parser.loadIFFBlock(ID_CMAP, palette, _paletteSize); - return palette; -} - -byte *ILBMDecoder::getBitmap(uint32 numPlanes, bool packPlanes) { - assert(_bodySize != (uint32)-1); - assert(numPlanes == 1 || numPlanes == 2 || numPlanes == 3 || numPlanes == 4 || numPlanes == 5 || numPlanes == 8); - - numPlanes = MIN(numPlanes, (uint32)_header.depth); - if (numPlanes > 4) { - packPlanes = false; - } - - uint32 bitmapSize = _header.width * _header.height; - uint32 bitmapWidth = _header.width; - if (packPlanes) { - bitmapSize /= (8 / numPlanes); - bitmapWidth /= (8 / numPlanes); - } - - Common::SeekableReadStream *bodyStream = _parser.getIFFBlockStream(ID_BODY); - assert(bodyStream); - - byte *bitmap = (byte*)calloc(bitmapSize, 1); - assert(bitmap); - - switch (_header.pack) { - case 1: { // PackBits compressed bitmap - Graphics::PackBitsReadStream stream(*bodyStream); - - byte *out = bitmap; - - // setup a buffer to hold enough data to build a line in the output - uint32 scanWidth = ((_header.width + 15)/16) << 1; - byte *scanBuffer = (byte*)malloc(scanWidth * _header.depth); - - for (uint i = 0; i < _header.height; ++i) { - byte *s = scanBuffer; - for (uint32 j = 0; j < _header.depth; ++j) { - stream.read(s, scanWidth); - s += scanWidth; - } - - planarToChunky(out, bitmapWidth, scanBuffer, scanWidth, numPlanes, packPlanes); - out += bitmapWidth; - } - - free(scanBuffer); - break; - } - default: - error("only RLE compressed ILBM files are supported"); - break; - } - - delete bodyStream; - - return bitmap; -} - - -void ILBMDecoder::planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth, uint32 nPlanes, bool packPlanes) { - byte pix, ofs, bit; - byte *s; - - uint32 pixels = width; - if (packPlanes) { - pixels *= (8 / nPlanes); - } - - for (uint32 x = 0; x < pixels; ++x) { - - pix = 0; - ofs = x >> 3; - bit = 0x80 >> (x & 7); - - // first build a pixel by scanning all the usable planes in the input - s = in; - for (uint32 plane = 0; plane < nPlanes; ++plane) { - if (s[ofs] & bit) { - pix |= (1 << plane); - } - s += planeWidth; - } - - - // then output the pixel according to the requested packing - if (!packPlanes) { - out[x] = pix; - } else - if (nPlanes == 1) { - out[x/8] |= (pix << (x & 7)); - } else - if (nPlanes == 2) { - out[x/4] |= (pix << ((x & 3) << 1)); - } else - if (nPlanes == 4) { - out[x/2] |= (pix << ((x & 1) << 2)); - } - } - -} - - -} // End of namespace Parallaction diff --git a/engines/parallaction/iff.h b/engines/parallaction/iff.h deleted file mode 100644 index 43f78bf001..0000000000 --- a/engines/parallaction/iff.h +++ /dev/null @@ -1,105 +0,0 @@ -/* 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 PARALLACTION_IFF_H -#define PARALLACTION_IFF_H - -#include "common/stream.h" -#include "common/iff_container.h" // for IFF chunk names -#include "graphics/iff.h" // for BMHD - -// this IFF parser code is courtesy of the Kyra engine team ;) - -namespace Parallaction { - -class IFFParser { -public: - IFFParser() : _stream(0), _startOffset(0), _endOffset(0) {} - IFFParser(Common::SeekableReadStream *stream) : _stream(0), _startOffset(0), _endOffset(0) { - setInputStream(stream); - } - ~IFFParser() { destroy(); } - - void setInputStream(Common::SeekableReadStream *stream); - - operator bool() const { return (_startOffset != _endOffset) && _stream; } - - uint32 getFORMSize() const; - Common::IFF_ID getFORMType() const; - - uint32 getIFFBlockSize(Common::IFF_ID chunk); - bool loadIFFBlock(Common::IFF_ID chunk, void *loadTo, uint32 ptrSize); - Common::SeekableReadStream *getIFFBlockStream(Common::IFF_ID chunkName); -private: - void destroy(); - uint32 moveToIFFBlock(Common::IFF_ID chunkName); - - Common::SeekableReadStream *_stream; - uint32 _startOffset; - uint32 _endOffset; - - uint32 _formSize; - Common::IFF_ID _formType; -}; - - - - -class ILBMDecoder { - Common::SeekableReadStream *_in; - bool _disposeStream; - - void planarToChunky(byte *out, uint32 width, byte *in, uint32 planeWidth, uint32 nPlanes, bool packPlanes); - -protected: - IFFParser _parser; - Graphics::BMHD _header; - bool _hasHeader; - uint32 _bodySize; - uint32 _paletteSize; - - -public: - ILBMDecoder(Common::SeekableReadStream *input, bool disposeStream = false); - - virtual ~ILBMDecoder(); - - uint32 getWidth(); - uint32 getHeight(); - uint32 getNumColors(); - byte *getPalette(); - - byte *getBitmap(uint32 numPlanes, bool packPlanes); - byte *getBitmap() { - assert(_hasHeader); - return getBitmap(_header.depth, false); - } -}; - - -} - -#endif - diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk index 16b79c3d5a..d65653cd92 100644 --- a/engines/parallaction/module.mk +++ b/engines/parallaction/module.mk @@ -7,6 +7,7 @@ MODULE_OBJS := \ debug.o \ detection.o \ dialogue.o \ + disk.o \ disk_br.o \ disk_ns.o \ exec.o \ @@ -18,7 +19,6 @@ MODULE_OBJS := \ gui.o \ gui_br.o \ gui_ns.o \ - iff.o \ input.o \ inventory.o \ objects.o \ diff --git a/engines/parallaction/sound.h b/engines/parallaction/sound.h index f0ecea67bb..8fcfb94a9a 100644 --- a/engines/parallaction/sound.h +++ b/engines/parallaction/sound.h @@ -84,6 +84,14 @@ enum { SC_PAUSE }; +struct Channel { + Audio::AudioStream *stream; + Audio::SoundHandle handle; + uint32 volume; +}; + + + class SoundMan_ns : public SoundManImpl { public: enum { @@ -148,16 +156,9 @@ class AmigaSoundMan_ns : public SoundMan_ns { Audio::AudioStream *_musicStream; Audio::SoundHandle _musicHandle; - struct Channel { - Audio::Voice8Header header; - int8 *data; - uint32 dataSize; - bool dispose; - Audio::SoundHandle handle; - uint32 flags; - } _channels[NUM_SFX_CHANNELS]; + Channel _channels[NUM_SFX_CHANNELS]; - void loadChannelData(const char *filename, Channel *ch); + Audio::AudioStream *loadChannelData(const char *filename, Channel *ch, bool looping); public: AmigaSoundMan_ns(Parallaction_ns *vm); @@ -192,21 +193,12 @@ protected: bool _musicEnabled; bool _sfxEnabled; + Channel _channels[NUM_SFX_CHANNELS]; + virtual void playMusic() = 0; virtual void stopMusic() = 0; virtual void pause(bool p) = 0; - struct Channel { - Audio::Voice8Header header; - int8 *data; - uint32 dataSize; - bool dispose; - Audio::SoundHandle handle; - uint32 flags; - } _channels[NUM_SFX_CHANNELS]; - - virtual void loadChannelData(const char *filename, Channel *ch) = 0; - public: SoundMan_br(Parallaction_br *vm); ~SoundMan_br(); @@ -228,7 +220,7 @@ class DosSoundMan_br : public SoundMan_br { MidiPlayer_MSC *_midiPlayer; - void loadChannelData(const char *filename, Channel *ch); + Audio::AudioStream *loadChannelData(const char *filename, Channel *ch, bool looping); public: DosSoundMan_br(Parallaction_br *vm, MidiDriver *midiDriver); @@ -246,7 +238,7 @@ class AmigaSoundMan_br : public SoundMan_br { Audio::AudioStream *_musicStream; Audio::SoundHandle _musicHandle; - void loadChannelData(const char *filename, Channel *ch); + Audio::AudioStream *loadChannelData(const char *filename, Channel *ch, bool looping); public: AmigaSoundMan_br(Parallaction_br *vm); diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp index 4915eb41e2..c0e3f3b24a 100644 --- a/engines/parallaction/sound_br.cpp +++ b/engines/parallaction/sound_br.cpp @@ -401,19 +401,29 @@ DosSoundMan_br::~DosSoundMan_br() { delete _midiPlayer; } -void DosSoundMan_br::loadChannelData(const char *filename, Channel *ch) { +Audio::AudioStream *DosSoundMan_br::loadChannelData(const char *filename, Channel *ch, bool looping) { Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename); - ch->dataSize = stream->size(); - ch->data = (int8*)malloc(ch->dataSize); - if (stream->read(ch->data, ch->dataSize) != ch->dataSize) + uint32 dataSize = stream->size(); + int8 *data = (int8*)malloc(dataSize); + if (stream->read(data, dataSize) != dataSize) error("DosSoundMan_br::loadChannelData: Read failed"); - ch->dispose = true; delete stream; // TODO: Confirm sound rate - ch->header.samplesPerSec = 11025; + int rate = 11025; + + uint32 loopStart = 0, loopEnd = 0; + uint32 flags = Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE; + + if (looping) { + loopEnd = dataSize; + flags |= Audio::Mixer::FLAG_LOOP; + } + + ch->stream = Audio::makeLinearInputStream((byte *)data, dataSize, rate, flags, loopStart, loopEnd); + return ch->stream; } void DosSoundMan_br::playSfx(const char *filename, uint channel, bool looping, int volume) { @@ -426,16 +436,8 @@ void DosSoundMan_br::playSfx(const char *filename, uint channel, bool looping, i debugC(1, kDebugAudio, "DosSoundMan_br::playSfx(%s, %u, %i, %i)", filename, channel, looping, volume); Channel *ch = &_channels[channel]; - loadChannelData(filename, ch); - - uint32 loopStart = 0, loopEnd = 0, flags = Audio::Mixer::FLAG_UNSIGNED; - if (looping) { - loopEnd = ch->dataSize; - flags |= Audio::Mixer::FLAG_LOOP; - } - - _mixer->playRaw(Audio::Mixer::kSFXSoundType, &ch->handle, ch->data, ch->dataSize, - ch->header.samplesPerSec, flags, -1, volume, 0, loopStart, loopEnd); + Audio::AudioStream *input = loadChannelData(filename, ch, looping); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume); } void DosSoundMan_br::playMusic() { @@ -468,22 +470,27 @@ AmigaSoundMan_br::~AmigaSoundMan_br() { stopMusic(); } -void AmigaSoundMan_br::loadChannelData(const char *filename, Channel *ch) { +Audio::AudioStream *AmigaSoundMan_br::loadChannelData(const char *filename, Channel *ch, bool looping) { Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename); + Audio::AudioStream *input = 0; + if (_vm->getFeatures() & GF_DEMO) { - ch->dataSize = stream->size(); - ch->data = (int8*)malloc(ch->dataSize); - if (stream->read(ch->data, ch->dataSize) != ch->dataSize) + uint32 dataSize = stream->size(); + int8 *data = (int8*)malloc(dataSize); + if (stream->read(data, dataSize) != dataSize) error("DosSoundMan_br::loadChannelData: Read failed"); // TODO: Confirm sound rate - ch->header.samplesPerSec = 11025; + int rate = 11025; + input = Audio::makeLinearInputStream((byte *)data, dataSize, rate, Audio::Mixer::FLAG_AUTOFREE, 0, 0); } else { - Audio::A8SVXDecoder decoder(*stream, ch->header, ch->data, ch->dataSize); - decoder.decode(); + input = Audio::make8SVXStream(*stream, looping); } - ch->dispose = true; + delete stream; + + ch->stream = input; + return input; } void AmigaSoundMan_br::playSfx(const char *filename, uint channel, bool looping, int volume) { @@ -501,24 +508,13 @@ void AmigaSoundMan_br::playSfx(const char *filename, uint channel, bool looping, debugC(1, kDebugAudio, "AmigaSoundMan_ns::playSfx(%s, %i)", filename, channel); Channel *ch = &_channels[channel]; - loadChannelData(filename, ch); - - uint32 loopStart = 0, loopEnd = 0, flags = 0; - if (looping) { - // the standard way to loop 8SVX audio implies use of the oneShotHiSamples and - // repeatHiSamples fields, but Nippon Safes handles loops according to flags - // set in its location scripts and always operates on the whole data. - loopStart = 0; - loopEnd = ch->header.oneShotHiSamples + ch->header.repeatHiSamples; - flags = Audio::Mixer::FLAG_LOOP; - } + Audio::AudioStream *input = loadChannelData(filename, ch, looping); if (volume == -1) { - volume = ch->header.volume; + volume = ch->volume; } - _mixer->playRaw(Audio::Mixer::kSFXSoundType, &ch->handle, ch->data, ch->dataSize, - ch->header.samplesPerSec, flags, -1, volume, 0, loopStart, loopEnd); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume); } void AmigaSoundMan_br::playMusic() { @@ -560,15 +556,6 @@ void AmigaSoundMan_br::pause(bool p) { SoundMan_br::SoundMan_br(Parallaction_br *vm) : _vm(vm) { _mixer = _vm->_mixer; - _channels[0].data = 0; - _channels[0].dispose = false; - _channels[1].data = 0; - _channels[1].dispose = false; - _channels[2].data = 0; - _channels[2].dispose = false; - _channels[3].data = 0; - _channels[3].dispose = false; - _musicEnabled = true; _sfxEnabled = true; } @@ -595,12 +582,9 @@ void SoundMan_br::stopSfx(uint channel) { return; } - if (_channels[channel].dispose) { - debugC(1, kDebugAudio, "SoundMan_br::stopSfx(%i)", channel); - _mixer->stopHandle(_channels[channel].handle); - free(_channels[channel].data); - _channels[channel].data = 0; - } + debugC(1, kDebugAudio, "SoundMan_br::stopSfx(%i)", channel); + _mixer->stopHandle(_channels[channel].handle); + _channels[channel].stream = 0; } void SoundMan_br::execute(int command, const char *parm) { diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp index d0688c7264..65ee75ed98 100644 --- a/engines/parallaction/sound_ns.cpp +++ b/engines/parallaction/sound_ns.cpp @@ -335,14 +335,6 @@ void DosSoundMan_ns::playLocationMusic(const char *location) { AmigaSoundMan_ns::AmigaSoundMan_ns(Parallaction_ns *vm) : SoundMan_ns(vm) { _musicStream = 0; - _channels[0].data = 0; - _channels[0].dispose = false; - _channels[1].data = 0; - _channels[1].dispose = false; - _channels[2].data = 0; - _channels[2].dispose = false; - _channels[3].data = 0; - _channels[3].dispose = false; } AmigaSoundMan_ns::~AmigaSoundMan_ns() { @@ -360,30 +352,30 @@ static int8 res_amigaBeep[AMIGABEEP_SIZE] = { 0, 20, 40, 60, 80, 60, 40, 20, 0, -20, -40, -60, -80, -60, -40, -20 }; +Audio::AudioStream *AmigaSoundMan_ns::loadChannelData(const char *filename, Channel *ch, bool looping) { + Audio::AudioStream *input = 0; -void AmigaSoundMan_ns::loadChannelData(const char *filename, Channel *ch) { if (!scumm_stricmp("beep", filename)) { - ch->header.oneShotHiSamples = 0; - ch->header.repeatHiSamples = 0; - ch->header.samplesPerHiCycle = 0; - ch->header.samplesPerSec = 11934; - ch->header.volume = 160; - ch->data = (int8*)malloc(AMIGABEEP_SIZE * NUM_REPEATS); - int8* odata = ch->data; + // TODO: make a permanent stream out of this + uint32 dataSize = AMIGABEEP_SIZE * NUM_REPEATS; + int8 *data = (int8*)malloc(dataSize); + int8 *odata = data; for (uint i = 0; i < NUM_REPEATS; i++) { memcpy(odata, res_amigaBeep, AMIGABEEP_SIZE); odata += AMIGABEEP_SIZE; } - ch->dataSize = AMIGABEEP_SIZE * NUM_REPEATS; - ch->dispose = true; - return; + int rate = 11934; + ch->volume = 160; + input = Audio::makeLinearInputStream((byte *)data, dataSize, rate, Audio::Mixer::FLAG_AUTOFREE, 0, 0); + } else { + Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename); + input = Audio::make8SVXStream(*stream, looping); + delete stream; } - Common::SeekableReadStream *stream = _vm->_disk->loadSound(filename); - Audio::A8SVXDecoder decoder(*stream, ch->header, ch->data, ch->dataSize); - decoder.decode(); - ch->dispose = true; - delete stream; + ch->stream = input; + + return input; } void AmigaSoundMan_ns::playSfx(const char *filename, uint channel, bool looping, int volume) { @@ -397,27 +389,13 @@ void AmigaSoundMan_ns::playSfx(const char *filename, uint channel, bool looping, debugC(1, kDebugAudio, "AmigaSoundMan_ns::playSfx(%s, %i)", filename, channel); Channel *ch = &_channels[channel]; - loadChannelData(filename, ch); - - uint32 loopStart, loopEnd, flags; - if (looping) { - // the standard way to loop 8SVX audio implies use of the oneShotHiSamples and - // repeatHiSamples fields, but Nippon Safes handles loops according to flags - // set in its location scripts and always operates on the whole data. - loopStart = 0; - loopEnd = ch->header.oneShotHiSamples + ch->header.repeatHiSamples; - flags = Audio::Mixer::FLAG_LOOP; - } else { - loopStart = loopEnd = 0; - flags = 0; - } + Audio::AudioStream *input = loadChannelData(filename, ch, looping); if (volume == -1) { - volume = ch->header.volume; + volume = ch->volume; } - _mixer->playRaw(Audio::Mixer::kSFXSoundType, &ch->handle, ch->data, ch->dataSize, - ch->header.samplesPerSec, flags, -1, volume, 0, loopStart, loopEnd); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &ch->handle, input, -1, volume); } void AmigaSoundMan_ns::stopSfx(uint channel) { @@ -426,12 +404,9 @@ void AmigaSoundMan_ns::stopSfx(uint channel) { return; } - if (_channels[channel].dispose) { - debugC(1, kDebugAudio, "AmigaSoundMan_ns::stopSfx(%i)", channel); - _mixer->stopHandle(_channels[channel].handle); - free(_channels[channel].data); - _channels[channel].data = 0; - } + debugC(1, kDebugAudio, "AmigaSoundMan_ns::stopSfx(%i)", channel); + _mixer->stopHandle(_channels[channel].handle); + _channels[channel].stream = 0; } void AmigaSoundMan_ns::playMusic() { diff --git a/engines/saga/scene.cpp b/engines/saga/scene.cpp index a7c802f0c9..f43db12d1a 100644 --- a/engines/saga/scene.cpp +++ b/engines/saga/scene.cpp @@ -472,7 +472,7 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy for (int i = 0; i < ARRAYSIZE(sceneSubstitutes); i++) { if (sceneSubstitutes[i].sceneId == sceneNumber) { Surface bbmBuffer; - byte *pal, *colors; + byte *pal, colors[768]; Common::File file; Rect rect; PalEntry cPal[PAL_ENTRIES]; @@ -480,8 +480,8 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy _vm->_interface->setMode(kPanelSceneSubstitute); if (file.open(sceneSubstitutes[i].image)) { - Graphics::decodePBM(file, bbmBuffer, pal); - colors = pal; + Graphics::decodePBM(file, bbmBuffer, colors); + pal = colors; rect.setWidth(bbmBuffer.w); rect.setHeight(bbmBuffer.h); _vm->_gfx->drawRegion(rect, (const byte*)bbmBuffer.pixels); @@ -490,7 +490,6 @@ void Scene::changeScene(int16 sceneNumber, int actorsEntrance, SceneTransitionTy cPal[j].green = *pal++; cPal[j].blue = *pal++; } - free(colors); _vm->_gfx->setPalette(cPal); } diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 4816f87a20..2f2fbc5243 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -55,15 +55,6 @@ int g_debug_seeking = 0; // Stepping forward until some special condition is met int g_debug_seek_special = 0; // Used for special seeks int g_debug_seek_level = 0; // Used for seekers that want to check their exec stack depth -enum DebugSeeking { - kDebugSeekNothing = 0, - kDebugSeekCallk = 1, // Step forward until callk is found - kDebugSeekLevelRet = 2, // Step forward until returned from this level - kDebugSeekSpecialCallk = 3, // Step forward until a /special/ callk is found - kDebugSeekSO = 4, // Step forward until specified PC (after the send command) and stack depth - kDebugSeekGlobal = 5 // Step forward until one specified global variable is modified -}; - Console::Console(SciEngine *vm) : GUI::Debugger() { _vm = vm; @@ -152,11 +143,17 @@ Console::Console(SciEngine *vm) : GUI::Debugger() { DCmd_Register("dissect_script", WRAP_METHOD(Console, cmdDissectScript)); DCmd_Register("set_acc", WRAP_METHOD(Console, cmdSetAccumulator)); DCmd_Register("backtrace", WRAP_METHOD(Console, cmdBacktrace)); + DCmd_Register("bt", WRAP_METHOD(Console, cmdBacktrace)); // alias DCmd_Register("step", WRAP_METHOD(Console, cmdStep)); + DCmd_Register("s", WRAP_METHOD(Console, cmdStep)); // alias DCmd_Register("step_event", WRAP_METHOD(Console, cmdStepEvent)); + DCmd_Register("se", WRAP_METHOD(Console, cmdStepEvent)); // alias DCmd_Register("step_ret", WRAP_METHOD(Console, cmdStepRet)); + DCmd_Register("sret", WRAP_METHOD(Console, cmdStepRet)); // alias DCmd_Register("step_global", WRAP_METHOD(Console, cmdStepGlobal)); + DCmd_Register("sg", WRAP_METHOD(Console, cmdStepGlobal)); // alias DCmd_Register("step_callk", WRAP_METHOD(Console, cmdStepCallk)); + DCmd_Register("snk", WRAP_METHOD(Console, cmdStepCallk)); // alias DCmd_Register("disasm", WRAP_METHOD(Console, cmdDissassemble)); DCmd_Register("disasm_addr", WRAP_METHOD(Console, cmdDissassembleAddress)); DCmd_Register("send", WRAP_METHOD(Console, cmdSend)); @@ -165,7 +162,9 @@ Console::Console(SciEngine *vm) : GUI::Debugger() { DCmd_Register("bp_list", WRAP_METHOD(Console, cmdBreakpointList)); DCmd_Register("bp_del", WRAP_METHOD(Console, cmdBreakpointDelete)); DCmd_Register("bp_exec_method", WRAP_METHOD(Console, cmdBreakpointExecMethod)); + DCmd_Register("bpx", WRAP_METHOD(Console, cmdBreakpointExecMethod)); // alias DCmd_Register("bp_exec_function", WRAP_METHOD(Console, cmdBreakpointExecFunction)); + DCmd_Register("bpe", WRAP_METHOD(Console, cmdBreakpointExecFunction)); // alias // VM DCmd_Register("script_steps", WRAP_METHOD(Console, cmdScriptSteps)); DCmd_Register("vm_varlist", WRAP_METHOD(Console, cmdVMVarlist)); @@ -174,7 +173,9 @@ Console::Console(SciEngine *vm) : GUI::Debugger() { DCmd_Register("value_type", WRAP_METHOD(Console, cmdValueType)); DCmd_Register("view_listnode", WRAP_METHOD(Console, cmdViewListNode)); DCmd_Register("view_reference", WRAP_METHOD(Console, cmdViewReference)); + DCmd_Register("vr", WRAP_METHOD(Console, cmdViewReference)); // alias DCmd_Register("view_object", WRAP_METHOD(Console, cmdViewObject)); + DCmd_Register("vo", WRAP_METHOD(Console, cmdViewObject)); // alias DCmd_Register("active_object", WRAP_METHOD(Console, cmdViewActiveObject)); DCmd_Register("acc_object", WRAP_METHOD(Console, cmdViewAccumulatorObject)); @@ -225,6 +226,12 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf("weak_validations: Turns some validation errors into warnings\n"); DebugPrintf("script_abort_flag: Set to 1 to abort script execution. Set to 2 to force a replay afterwards\n"); DebugPrintf("\n"); + DebugPrintf("Debug flags\n"); + DebugPrintf("-----------\n"); + DebugPrintf("debugflag_list - Lists the available debug flags and their status\n"); + DebugPrintf("debugflag_enable - Enables a debug flag\n"); + DebugPrintf("debugflag_disable - Disables a debug flag\n"); + DebugPrintf("\n"); DebugPrintf("Commands\n"); DebugPrintf("--------\n"); DebugPrintf("Kernel:\n"); @@ -310,12 +317,12 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf(" registers - Shows the current register values\n"); DebugPrintf(" dissect_script - Examines a script\n"); DebugPrintf(" set_acc - Sets the accumulator\n"); - DebugPrintf(" backtrace - Dumps the send/self/super/call/calle/callb stack\n"); - DebugPrintf(" step - Executes one operation (no parameters) or several operations (specified as a parameter) \n"); - DebugPrintf(" step_event - Steps forward until a SCI event is received.\n"); - DebugPrintf(" step_ret - Steps forward until ret is called on the current execution stack level.\n"); - DebugPrintf(" step_global - Steps until the global variable with the specified index is modified.\n"); - DebugPrintf(" step_callk - Steps forward until it hits the next callk operation, or a specific callk (specified as a parameter)\n"); + DebugPrintf(" backtrace / bt - Dumps the send/self/super/call/calle/callb stack\n"); + DebugPrintf(" step / s - Executes one operation (no parameters) or several operations (specified as a parameter) \n"); + DebugPrintf(" step_event / se - Steps forward until a SCI event is received.\n"); + DebugPrintf(" step_ret / sret - Steps forward until ret is called on the current execution stack level.\n"); + DebugPrintf(" step_global / sg - Steps until the global variable with the specified index is modified.\n"); + DebugPrintf(" step_callk / snk - Steps forward until it hits the next callk operation, or a specific callk (specified as a parameter)\n"); DebugPrintf(" disasm - Disassembles a method by name\n"); DebugPrintf(" disasm_addr - Disassembles one or more commands\n"); DebugPrintf(" send - Sends a message to an object\n"); @@ -324,8 +331,8 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf("Breakpoints:\n"); DebugPrintf(" bp_list - Lists the current breakpoints\n"); DebugPrintf(" bp_del - Deletes a breakpoint with the specified index\n"); - DebugPrintf(" bp_exec_method - Sets a breakpoint on the execution of the specified method\n"); - DebugPrintf(" bp_exec_function - Sets a breakpoint on the execution of the specified exported function\n"); + DebugPrintf(" bp_exec_method / bpx - Sets a breakpoint on the execution of the specified method\n"); + DebugPrintf(" bp_exec_function / bpe - Sets a breakpoint on the execution of the specified exported function\n"); DebugPrintf("\n"); DebugPrintf("VM:\n"); DebugPrintf(" script_steps - Shows the number of executed SCI operations\n"); @@ -334,8 +341,8 @@ bool Console::cmdHelp(int argc, const char **argv) { DebugPrintf(" stack - Lists the specified number of stack elements\n"); DebugPrintf(" value_type - Determines the type of a value\n"); DebugPrintf(" view_listnode - Examines the list node at the given address\n"); - DebugPrintf(" view_reference - Examines an arbitrary reference\n"); - DebugPrintf(" view_object - Examines the object at the given address\n"); + DebugPrintf(" view_reference / vr - Examines an arbitrary reference\n"); + DebugPrintf(" view_object / vo - Examines the object at the given address\n"); DebugPrintf(" active_object - Shows information on the currently active object or class\n"); DebugPrintf(" acc_object - Shows information on the object or class at the address indexed by the accumulator\n"); DebugPrintf("\n"); diff --git a/engines/sci/console.h b/engines/sci/console.h index c45202de16..22b5505bf2 100644 --- a/engines/sci/console.h +++ b/engines/sci/console.h @@ -35,6 +35,15 @@ namespace Sci { class SciEngine; struct List; +enum DebugSeeking { + kDebugSeekNothing = 0, + kDebugSeekCallk = 1, // Step forward until callk is found + kDebugSeekLevelRet = 2, // Step forward until returned from this level + kDebugSeekSpecialCallk = 3, // Step forward until a /special/ callk is found + kDebugSeekSO = 4, // Step forward until specified PC (after the send command) and stack depth + kDebugSeekGlobal = 5 // Step forward until one specified global variable is modified +}; + // Refer to the "addresses" command on how to pass address parameters int parse_reg_t(EngineState *s, const char *str, reg_t *dest); int printObject(EngineState *s, reg_t pos); diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index ac5268dd4c..bdf2c7c72a 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -953,9 +953,9 @@ static const struct SciGameDescription SciGameDescriptions[] = { {"resource.map", 0, "59b13619078bd47011421468959ee5d4", 954}, {"resource.001", 0, "4cfb9040db152868f7cb6a1e8151c910", 296555}, {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NOSPEECH}, - 0, + GF_SCI0_SCI1VOCAB, SCI_VERSION_AUTODETECT, - SCI_VERSION_01 + SCI_VERSION_0 }, // King's Quest 1 SCI Remake - English DOS (from the King's Quest Collection) @@ -969,7 +969,7 @@ static const struct SciGameDescription SciGameDescriptions[] = { {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC, 0, GUIO_NOSPEECH}, 0, SCI_VERSION_AUTODETECT, - SCI_VERSION_01 + SCI_VERSION_0 }, // King's Quest 4 - English Amiga (from www.back2roots.org) @@ -2504,6 +2504,32 @@ static const struct SciGameDescription SciGameDescriptions[] = { SCI_VERSION_0 }, + // Quest for Glory 1 - Japanese PC-98 5.25" Floppy + // Executable scanning reports "S.old.201" + {{"qfg1", "8 Colors", { + {"resource.map", 0, "5cbeb95dd2a4b7cb242b415cc6ec1c47", 6444}, + {"resource.001", 0, "a21451ef6fa8179bd4b22c4950004c44", 859959}, + {"resource.002", 0, "a21451ef6fa8179bd4b22c4950004c44", 1136968}, + {"resource.003", 0, "a21451ef6fa8179bd4b22c4950004c44", 769897}, + {NULL, 0, NULL, 0}}, Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH}, + 0, + SCI_VERSION_AUTODETECT, + SCI_VERSION_01 + }, + + // Quest for Glory 1 - Japanese PC-98 5.25" Floppy + // Executable scanning reports "S.old.201" + {{"qfg1", "16 Colors", { + {"resource.map", 0, "3ecaba33bf77cb434067a0b8aee15097", 6444}, + {"resource.001", 0, "a21451ef6fa8179bd4b22c4950004c44", 864754}, + {"resource.002", 0, "a21451ef6fa8179bd4b22c4950004c44", 1147121}, + {"resource.003", 0, "a21451ef6fa8179bd4b22c4950004c44", 777575}, + {NULL, 0, NULL, 0}}, Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH}, + 0, + SCI_VERSION_AUTODETECT, + SCI_VERSION_01 + }, + // Quest for Glory 1 - English Amiga // Executable scanning reports "1.002.020" // SCI interpreter version 0.000.685 @@ -3085,6 +3111,32 @@ static const struct SciGameDescription SciGameDescriptions[] = { SCI_VERSION_1 }, + // Space Quest 4 - Japanese PC-98 5.25" Floppy + // SCI interpreter version 1.000.1068 + {{"sq4", "", { + {"resource.map", 0, "ca7bba01019222b6f3e54e9051067a99", 5283}, + {"resource.000", 0, "161d719f38ed98d33f058a8cf3dc09c3", 952909}, + {"resource.001", 0, "454684e3a7a68cbca073945e50778447", 1187088}, + {"resource.002", 0, "6dc668326cc22cb9e8bd8ca9e68d2a66", 1181249}, + {NULL, 0, NULL, 0}}, Common::JA_JPN, Common::kPlatformPC98, 0, GUIO_NOSPEECH}, + GF_FOR_SCI1_510_OR_LATER | GF_SCI1_EGA, + SCI_VERSION_AUTODETECT, + SCI_VERSION_1 + }, + + // Space Quest 4 - Japanese PC-98 5.25" Floppy + // SCI interpreter version 1.000.1068 + {{"sq4", "", { + {"resource.map", 0, "ca7bba01019222b6f3e54e9051067a99", 5283}, + {"resource.000", 0, "161d719f38ed98d33f058a8cf3dc09c3", 952909}, + {"resource.001", 0, "454684e3a7a68cbca073945e50778447", 1187088}, + {"resource.002", 0, "6dc668326cc22cb9e8bd8ca9e68d2a66", 1181249}, + {NULL, 0, NULL, 0}}, Common::EN_ANY, Common::kPlatformPC98, 0, GUIO_NOSPEECH}, + GF_FOR_SCI1_510_OR_LATER | GF_SCI1_EGA, + SCI_VERSION_AUTODETECT, + SCI_VERSION_1 + }, + // Space Quest 4 - English DOS CD (from the Space Quest Collection) // Executable scanning reports "1.001.064", VERSION file reports "1.0" {{"sq4", "CD", { diff --git a/engines/sci/engine/gc.h b/engines/sci/engine/gc.h index e6fa737aaf..9f9347ca18 100644 --- a/engines/sci/engine/gc.h +++ b/engines/sci/engine/gc.h @@ -45,19 +45,23 @@ struct reg_t_Hash { } }; -// The reg_t_hash_map is actually really a hashset +/* + * The reg_t_hash_map is actually really a hashset + */ typedef Common::HashMap<reg_t, bool, reg_t_Hash, reg_t_EqualTo> reg_t_hash_map; +/** + * Finds all used references and normalises them to their memory addresses + * @param s The state to gather all information from + * @return A hash map containing entries for all used references + */ reg_t_hash_map *find_all_used_references(EngineState *s); -/* Finds all used references and normalises them to their memory addresses -** Parameters: (EngineState *) s: The state to gather all information from -** Returns : (reg_t_hash_map *) A hash map containing entries for all used references -*/ +/** + * Runs garbage collection on the current system state + * @param s The state in which we should gc + */ void run_gc(EngineState *s); -/* Runs garbage collection on the current system state -** Parameters: (EngineState *) s: The state in which we should gc -*/ } // End of namespace Sci diff --git a/engines/sci/engine/intmap.h b/engines/sci/engine/intmap.h index 2cb4f69f1f..1c028975a9 100644 --- a/engines/sci/engine/intmap.h +++ b/engines/sci/engine/intmap.h @@ -83,7 +83,7 @@ public: /** * Checks whether a key is in the map, adds it if neccessary. - * @param value The key to check for/add + * @param key The key to check for/add * @param add Whether to add the key if it's not in there * @param was_added Set to non-zero if and only if the key is new, ignored if NULL. * @return The new (or old) index, or -1 if add was zero and @@ -91,6 +91,11 @@ public: */ int checkKey(int key, bool add, bool *wasAdded = 0); + /** + * Looks up a key in the map + * @parmam key The key to look for + * @return The value or -1 if not found + */ int lookupKey(int key) const; diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index baf45d80c7..eafc6dbd4d 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -945,7 +945,11 @@ bool Kernel::loadKernelNames() { switch (_resmgr->_sciVersion) { case SCI_VERSION_0: case SCI_VERSION_01: - vocab_get_knames0(_resmgr, _kernelNames); + // HACK: The KQ1 demo requires the SCI1 vocabulary. + if (((SciEngine*)g_engine)->getFlags() & GF_SCI0_SCI1VOCAB) + vocab_get_knames1(_resmgr, _kernelNames); + else + vocab_get_knames0(_resmgr, _kernelNames); break; case SCI_VERSION_01_VGA: case SCI_VERSION_01_VGA_ODD: diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index 27d9df059d..46913a5b39 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -69,16 +69,17 @@ public: uint getKernelNamesSize() const { return _kernelNames.size(); } const Common::String &getKernelName(uint number) const { return _kernelNames[number]; } - /* Determines the selector ID of a selector by its name - ** (const char *) selectorName: Name of the selector to look up - ** Returns : (int) The appropriate selector ID, or -1 on error - */ + /** + * Determines the selector ID of a selector by its name + * @param selectorName Name of the selector to look up + * @return The appropriate selector ID, or -1 on error + */ int findSelector(const char *selectorName) const; - /* Detects whether a particular kernel function is required in the game - ** (const char *) functionName: The name of the desired kernel function - ** Returns : (bool) true if the kernel function is listed in the kernel table, - ** false otherwise + /** + * Detects whether a particular kernel function is required in the game + * @param functionName The name of the desired kernel function + * @return True if the kernel function is listed in the kernel table, false otherwise */ bool hasKernelFunction(const char *functionName) const; @@ -104,18 +105,18 @@ private: /** * Loads the kernel selector names. - * Returns true upon success, false otherwise. + * @return True upon success, false otherwise. */ bool loadSelectorNames(bool isOldSci0); - /* Maps special selectors - ** Returns : (void) - */ + /** + * Maps special selectors + */ void mapSelectors(); - /* Maps kernel functions - ** Returns : (void) - */ + /** + * Maps kernel functions + */ void mapFunctions(); /** @@ -127,8 +128,10 @@ private: ResourceManager *_resmgr; // Kernel-related lists - // List of opcodes, loaded from vocab.998. This list is only used for debugging - // purposes, as we hardcode the list of opcodes in the sci_opcodes enum (script.h) + /** + * List of opcodes, loaded from vocab.998. This list is only used for debugging + * purposes, as we hardcode the list of opcodes in the sci_opcodes enum (script.h) + */ Common::Array<opcode> _opcodes; Common::StringList _selectorNames; Common::StringList _kernelNames; @@ -178,61 +181,62 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvoc /******************** Text functionality ********************/ +/** + * Looks up text referenced by scripts + * SCI uses two values to reference to text: An address, and an index. The address + * determines whether the text should be read from a resource file, or from the heap, + * while the index either refers to the number of the string in the specified source, + * or to a relative position inside the text. + * + * @param s The current state + * @param address The address to look up + * @param index The relative index + * @return The referenced text, or NULL on error. + */ char *kernel_lookup_text(EngineState *s, reg_t address, int index); -/* Looks up text referenced by scripts -** Parameters: (EngineState *s): The current state -** (reg_t) address: The address to look up -** (int) index: The relative index -** Returns : (char *): The referenced text, or NULL on error. -** SCI uses two values to reference to text: An address, and an index. The address -** determines whether the text should be read from a resource file, or from the heap, -** while the index either refers to the number of the string in the specified source, -** or to a relative position inside the text. -*/ /******************** Debug functionality ********************/ - +/** + * Checks whether a heap address contains an object + * @param s The current state + * @parm obj The address to check + * @return True if it is an object, false otherwise + */ bool is_object(EngineState *s, reg_t obj); -/* Checks whether a heap address contains an object -** Parameters: (EngineState *) s: The current state -** (reg_t) obj: The address to check -** Returns : (bool) true if it is an object, false otherwise -*/ /******************** Kernel function parameter macros ********************/ /* Returns the parameter value or (alt) if not enough parameters were supplied */ - +/** + * Dereferences a heap pointer + * @param s The state to operate on + * @param pointer The pointer to dereference + * @parm entries The number of values expected (for checking; use 0 for strings) + * @return A physical reference to the address pointed to, or NULL on error or + * if not enugh entries were available. + * reg_t dereferenciation also assures alignedness of data. + */ reg_t *kernel_dereference_reg_pointer(EngineState *s, reg_t pointer, int entries); byte *kernel_dereference_bulk_pointer(EngineState *s, reg_t pointer, int entries); #define kernel_dereference_char_pointer(state, pointer, entries) (char*)kernel_dereference_bulk_pointer(state, pointer, entries) -/* Dereferences a heap pointer -** Parameters: (EngineState *) s: The state to operate on -** (reg_t ) pointer: The pointer to dereference -** (int) entries: The number of values expected (for checking) -** (use 0 for strings) -** Returns : (reg_t/char *): A physical reference to the address pointed -** to, or NULL on error or if not enugh entries -** were available -** reg_t dereferenciation also assures alignedness of data. -*/ /******************** Priority macros/functions ********************/ - +/** + * Finds the position of the priority band specified + * Parameters: (EngineState *) s: State to search in + * (int) band: Band to look for + * Returns : (int) Offset at which the band starts + */ int _find_priority_band(EngineState *s, int band); -/* Finds the position of the priority band specified -** Parameters: (EngineState *) s: State to search in -** (int) band: Band to look for -** Returns : (int) Offset at which the band starts -*/ +/** + * Does the opposite of _find_priority_band + * @param s Engine state + * @param y Coordinate to check + * @return The priority band y belongs to + */ int _find_view_priority(EngineState *s, int y); -/* Does the opposite of _find_priority_band -** Parameters: (EngineState *) s: State -** (int) y: Coordinate to check -** Returns : (int) The priority band y belongs to -*/ #define SCI0_VIEW_PRIORITY_14_ZONES(y) (((y) < s->priority_first)? 0 : (((y) >= s->priority_last)? 14 : 1\ + ((((y) - s->priority_first) * 14) / (s->priority_last - s->priority_first)))) @@ -249,50 +253,59 @@ int _find_view_priority(EngineState *s, int y); /******************** Dynamic view list functions ********************/ - +/** + * Determines the base rectangle of the specified view object + * @param s The state to use + * @param object The object to set + * @return The absolute base rectangle + */ Common::Rect set_base(EngineState *s, reg_t object); -/* Determines the base rectangle of the specified view object -** Parameters: (EngineState *) s: The state to use -** (reg_t) object: The object to set -** Returns : (abs_rect) The absolute base rectangle -*/ +/** + * Determines the now-seen rectangle of a view object + * @param s The state to use + * @param object The object to check + * @param clip Flag to determine wheter priority band clipping + * should be performed + * @return The absolute rectangle describing the now-seen area. + */ extern Common::Rect get_nsrect(EngineState *s, reg_t object, byte clip); -/* Determines the now-seen rectangle of a view object -** Parameters: (EngineState *) s: The state to use -** (reg_t) object: The object to check -** (byte) clip: Flag to determine wheter priority band -** clipping should be performed -** Returns : (abs_rect) The absolute rectangle describing the -** now-seen area. -*/ +/** + * Removes all views in anticipation of a new window or text + */ void _k_dyn_view_list_prepare_change(EngineState *s); -/* Removes all views in anticipation of a new window or text */ + +/** + * Redraws all views after a new window or text was added + */ void _k_dyn_view_list_accept_change(EngineState *s); -/* Redraws all views after a new window or text was added */ /******************** Misc functions ********************/ -void process_sound_events(EngineState *s); /* Get all sound events, apply their changes to the heap */ +/** + * Get all sound events, apply their changes to the heap + */ +void process_sound_events(EngineState *s); +/** + * Resolves an address into a list node + * @param s The state to operate on + * @param addr The address to resolve + * @return The list node referenced, or NULL on error + */ Node *lookup_node(EngineState *s, reg_t addr); -/* Resolves an address into a list node -** Parameters: (EngineState *) s: The state to operate on -** (reg_t) addr: The address to resolve -** Returns : (Node *) The list node referenced, or NULL on error -*/ - +/** + * Resolves a list pointer to a list + * @param s The state to operate on + * @param addr The address to resolve + * @return The list referenced, or NULL on error + */ List *lookup_list(EngineState *s, reg_t addr); -/* Resolves a list pointer to a list -** Parameters: (EngineState *) s: The state to operate on -** (reg_t) addr: The address to resolve -** Returns : (List *) The list referenced, or NULL on error -*/ /******************** Constants ********************/ diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index a26c2dbcb1..2856c76aa3 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -621,10 +621,14 @@ reg_t kGraph(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t kTextSize(EngineState *s, int funct_nr, int argc, reg_t *argv) { int width, height; char *text = argv[1].segment ? (char *) kernel_dereference_bulk_pointer(s, argv[1], 0) : NULL; + const char *sep = NULL; reg_t *dest = kernel_dereference_reg_pointer(s, argv[0], 4); int maxwidth = (argc > 3) ? argv[3].toUint16() : 0; int font_nr = argv[2].toUint16(); + if ((argc > 4) && (argv[4].segment)) + sep = (const char *)kernel_dereference_bulk_pointer(s, argv[4], 0); + if (maxwidth < 0) maxwidth = 0; @@ -636,7 +640,7 @@ reg_t kTextSize(EngineState *s, int funct_nr, int argc, reg_t *argv) { return s->r_acc; } - GFX_ASSERT(gfxop_get_text_params(s->gfx_state, font_nr, text, maxwidth ? maxwidth : MAX_TEXT_WIDTH_MAGIC_VALUE, + GFX_ASSERT(gfxop_get_text_params(s->gfx_state, font_nr, s->strSplit(text, sep).c_str(), maxwidth ? maxwidth : MAX_TEXT_WIDTH_MAGIC_VALUE, &width, &height, 0, NULL, NULL, NULL)); debugC(2, kDebugLevelStrings, "GetTextSize '%s' -> %dx%d\n", text, width, height); @@ -1570,7 +1574,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { int font_nr = GET_SEL32V(obj, font); reg_t text_pos = GET_SEL32(obj, text); - char *text = text_pos.isNull() ? NULL : (char *)s->seg_manager->dereference(text_pos, NULL); + const char *text = text_pos.isNull() ? NULL : (char *)s->seg_manager->dereference(text_pos, NULL); int view = GET_SEL32V(obj, view); int cel = sign_extend_byte(GET_SEL32V(obj, cel)); int loop = sign_extend_byte(GET_SEL32V(obj, loop)); @@ -1584,7 +1588,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { switch (type) { case K_CONTROL_BUTTON: debugC(2, kDebugLevelGraphics, "drawing button %04x:%04x to %d,%d\n", PRINT_REG(obj), x, y); - ADD_TO_CURRENT_PICTURE_PORT(sciw_new_button_control(s->port, obj, area, text, font_nr, + ADD_TO_CURRENT_PICTURE_PORT(sciw_new_button_control(s->port, obj, area, s->strSplit(text, NULL).c_str(), font_nr, (int8)(state & kControlStateFramed), (int8)inverse, (int8)(state & kControlStateDisabled))); break; @@ -1593,7 +1597,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { debugC(2, kDebugLevelGraphics, "drawing text %04x:%04x to %d,%d, mode=%d\n", PRINT_REG(obj), x, y, mode); - ADD_TO_CURRENT_PICTURE_PORT(sciw_new_text_control(s->port, obj, area, text, font_nr, mode, + ADD_TO_CURRENT_PICTURE_PORT(sciw_new_text_control(s->port, obj, area, s->strSplit(text).c_str(), font_nr, mode, (int8)(!!(state & kControlStateDitherFramed)), (int8)inverse)); break; @@ -1620,8 +1624,8 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { case K_CONTROL_CONTROL: case K_CONTROL_CONTROL_ALIAS: { - char **entries_list = NULL; - char *seeker; + const char **entries_list = NULL; + const char *seeker; int entries_nr; int lsTop = GET_SEL32V(obj, lsTop) - text_pos.offset; int list_top = 0; @@ -1641,7 +1645,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { if (entries_nr) { // determine list_top, selection, and the entries_list seeker = text; - entries_list = (char**)malloc(sizeof(char *) * entries_nr); + entries_list = (const char**)malloc(sizeof(char *) * entries_nr); for (i = 0; i < entries_nr; i++) { entries_list[i] = seeker; seeker += entry_size ; @@ -2524,10 +2528,10 @@ reg_t kNewWindow(EngineState *s, int funct_nr, int argc, reg_t *argv) { lWhite.alpha = 0; lWhite.priority = -1; lWhite.control = -1; + const char *title = argv[4 + argextra].segment ? kernel_dereference_char_pointer(s, argv[4 + argextra], 0) : NULL; window = sciw_new_window(s, gfx_rect(x, y, xl, yl), s->titlebar_port->_font, fgcolor, bgcolor, - s->titlebar_port->_font, lWhite, black, argv[4 + argextra].segment ? - kernel_dereference_char_pointer(s, argv[4 + argextra], 0) : NULL, flags); + s->titlebar_port->_font, lWhite, black, title ? s->strSplit(title, NULL).c_str() : NULL, flags); // PQ3 and SCI1.1 games have the interpreter store underBits implicitly if (argextra) @@ -3287,7 +3291,7 @@ reg_t kDisplay(EngineState *s, int funct_nr, int argc, reg_t *argv) { assert_primary_widget_lists(s); - text_handle = gfxw_new_text(s->gfx_state, area, font_nr, text, halign, ALIGN_TOP, color0, *color1, bg_color, 0); + text_handle = gfxw_new_text(s->gfx_state, area, font_nr, s->strSplit(text).c_str(), halign, ALIGN_TOP, color0, *color1, bg_color, 0); if (!text_handle) { error("Display: Failed to create text widget"); diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp index b742c93a52..bb27589d84 100644 --- a/engines/sci/engine/ksound.cpp +++ b/engines/sci/engine/ksound.cpp @@ -975,49 +975,42 @@ reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) { // Used for speech playback in CD games reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) { Audio::Mixer *mixer = g_system->getMixer(); - int sampleLen = 0; - - if (!s->_sound._audioResource) - s->_sound._audioResource = new AudioResource(s->resmgr, s->_version); switch (argv[0].toUint16()) { case kSciAudioWPlay: - case kSciAudioPlay: - s->_sound._audioResource->stop(); - - if (argc == 2) { // KQ5CD, KQ6 floppy - Audio::AudioStream *audioStream = s->_sound._audioResource->getAudioStream(argv[1].toUint16(), 65535, &sampleLen); - - if (audioStream) - mixer->playInputStream(Audio::Mixer::kSpeechSoundType, s->_sound._audioResource->getAudioHandle(), audioStream); - } else if (argc == 6) { // SQ4CD or newer - // Make a BE number - uint32 audioNumber = (((argv[2].toUint16() & 0xFF) << 24) & 0xFF000000) | - (((argv[3].toUint16() & 0xFF) << 16) & 0x00FF0000) | - (((argv[4].toUint16() & 0xFF) << 8) & 0x0000FF00) | - ( (argv[5].toUint16() & 0xFF) & 0x000000FF); - - Audio::AudioStream *audioStream = s->_sound._audioResource->getAudioStream(audioNumber, argv[1].toUint16(), &sampleLen); - - if (audioStream) - mixer->playInputStream(Audio::Mixer::kSpeechSoundType, s->_sound._audioResource->getAudioHandle(), audioStream); - } else { // Hopefully, this should never happen + case kSciAudioPlay: { + uint16 module; + uint32 number; + + s->_sound.stopAudio(); + + if (argc == 2) { + module = 65535; + number = argv[1].toUint16(); + } else if (argc == 6) { + module = argv[1].toUint16(); + number = ((argv[2].toUint16() & 0xff) << 24) | ((argv[3].toUint16() & 0xff) << 16) | + ((argv[4].toUint16() & 0xff) << 8) | (argv[5].toUint16() & 0xff); + } else { warning("kDoAudio: Play called with an unknown number of parameters (%d)", argc); + return NULL_REG; } - return make_reg(0, sampleLen); // return sample length in ticks + + return make_reg(0, s->_sound.startAudio(module, number)); // return sample length in ticks + } case kSciAudioStop: - s->_sound._audioResource->stop(); + s->_sound.stopAudio(); break; case kSciAudioPause: - s->_sound._audioResource->pause(); + s->_sound.pauseAudio(); break; case kSciAudioResume: - s->_sound._audioResource->resume(); + s->_sound.resumeAudio(); break; case kSciAudioPosition: - return make_reg(0, s->_sound._audioResource->getAudioPosition()); + return make_reg(0, s->_sound.getAudioPosition()); case kSciAudioRate: - s->_sound._audioResource->setAudioRate(argv[1].toUint16()); + s->_sound.setAudioRate(argv[1].toUint16()); break; case kSciAudioVolume: mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, argv[1].toUint16()); @@ -1027,7 +1020,7 @@ reg_t kDoAudio(EngineState *s, int funct_nr, int argc, reg_t *argv) { // In SCI1.1: tests for digital audio support return make_reg(0, 1); } else { - s->_sound._audioResource->setAudioLang(argv[1].toSint16()); + s->resmgr->setAudioLanguage(argv[1].toSint16()); } break; default: @@ -1042,8 +1035,10 @@ reg_t kDoSync(EngineState *s, int funct_nr, int argc, reg_t *argv) { case kSciAudioSyncStart: { ResourceId id; - if (s->_sound._soundSync) - s->resmgr->unlockResource(s->_sound._soundSync); + if (s->_sound._syncResource) { + s->resmgr->unlockResource(s->_sound._syncResource); + s->_sound._syncResource = NULL; + } // Load sound sync resource and lock it if (argc == 3) { @@ -1056,10 +1051,11 @@ reg_t kDoSync(EngineState *s, int funct_nr, int argc, reg_t *argv) { return s->r_acc; } - s->_sound._soundSync = (ResourceSync *)s->resmgr->findResource(id, 1); + s->_sound._syncResource = s->resmgr->findResource(id, 1); - if (s->_sound._soundSync) { - s->_sound._soundSync->startSync(s, argv[1]); + if (s->_sound._syncResource) { + PUT_SEL32V(argv[1], syncCue, 0); + s->_sound._syncOffset = 0; } else { warning("DoSync: failed to find resource %s", id.toString().c_str()); // Notify the scripts to stop sound sync @@ -1067,20 +1063,32 @@ reg_t kDoSync(EngineState *s, int funct_nr, int argc, reg_t *argv) { } break; } - case kSciAudioSyncNext: - if (s->_sound._soundSync) { - s->_sound._soundSync->nextSync(s, argv[1]); + case kSciAudioSyncNext: { + Resource *res = s->_sound._syncResource; + if (res && (s->_sound._syncOffset < res->size - 1)) { + int16 syncCue = -1; + int16 syncTime = (int16)READ_LE_UINT16(res->data + s->_sound._syncOffset); + + s->_sound._syncOffset += 2; + + if ((syncTime != -1) && (s->_sound._syncOffset < res->size - 1)) { + syncCue = (int16)READ_LE_UINT16(res->data + s->_sound._syncOffset); + s->_sound._syncOffset += 2; + } + + PUT_SEL32V(argv[1], syncTime, syncTime); + PUT_SEL32V(argv[1], syncCue, syncCue); } break; + } case kSciAudioSyncStop: - if (s->_sound._soundSync) { - s->_sound._soundSync->stopSync(); - s->resmgr->unlockResource(s->_sound._soundSync); - s->_sound._soundSync = NULL; + if (s->_sound._syncResource) { + s->resmgr->unlockResource(s->_sound._syncResource); + s->_sound._syncResource = NULL; } break; default: - warning("kDoSync: Unhandled case %d", argv[0].toUint16()); + warning("DoSync: Unhandled subfunction %d", argv[0].toUint16()); } return s->r_acc; diff --git a/engines/sci/engine/memobj.cpp b/engines/sci/engine/memobj.cpp index c0775ae51e..4d37d2aece 100644 --- a/engines/sci/engine/memobj.cpp +++ b/engines/sci/engine/memobj.cpp @@ -269,13 +269,6 @@ void Script::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, //-------------------- clones -------------------- -template<typename T> -void Table<T>::listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) { - for (uint i = 0; i < _table.size(); i++) - if (isValidEntry(i)) - (*note)(param, make_reg(segId, i)); -} - void CloneTable::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) { CloneTable *clone_table = this; Clone *clone; diff --git a/engines/sci/engine/memobj.h b/engines/sci/engine/memobj.h index f800695df5..50c43a0e88 100644 --- a/engines/sci/engine/memobj.h +++ b/engines/sci/engine/memobj.h @@ -502,7 +502,11 @@ public: entries_used--; } - virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); + virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note) { + for (uint i = 0; i < _table.size(); i++) + if (isValidEntry(i)) + (*note)(param, make_reg(segId, i)); + } }; diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index a0bfdeddc9..fb094e00f6 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -200,6 +200,9 @@ void Kernel::mapSelectors() { FIND_SELECTOR(points); FIND_SELECTOR(syncCue); FIND_SELECTOR(syncTime); + FIND_SELECTOR(printLang); + FIND_SELECTOR(subtitleLang); + FIND_SELECTOR(parseLang); } void Kernel::dumpScriptObject(char *data, int seeker, int objsize) { diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 63e99ad122..11c38052db 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -26,24 +26,9 @@ // Script debugger functionality. Absolutely not threadsafe. #include "sci/sci.h" +#include "sci/console.h" #include "sci/debug.h" #include "sci/engine/state.h" -#include "sci/engine/gc.h" -#include "sci/engine/kernel_types.h" -#include "sci/engine/kernel.h" -#include "sci/engine/savegame.h" -#include "sci/gfx/gfx_widgets.h" -#include "sci/gfx/gfx_gui.h" -#include "sci/gfx/gfx_state_internal.h" // required for GfxContainer, GfxPort, GfxVisual -#include "sci/resource.h" -#include "sci/vocabulary.h" -#include "sci/sfx/iterator.h" -#include "sci/sfx/sci_midi.h" - -#include "common/util.h" -#include "common/savefile.h" - -#include "sound/audiostream.h" namespace Sci { @@ -63,13 +48,13 @@ static int *p_var_max; // May be NULL even in valid state! extern const char *selector_name(EngineState *s, int selector); -int prop_ofs_to_id(EngineState *s, int prop_ofs, reg_t objp) { +int propertyOffsetToId(EngineState *s, int prop_ofs, reg_t objp) { Object *obj = obj_get(s, objp); byte *selectoroffset; int selectors; if (!obj) { - sciprintf("Applied prop_ofs_to_id on non-object at %04x:%04x\n", PRINT_REG(objp)); + sciprintf("Applied propertyOffsetToId on non-object at %04x:%04x\n", PRINT_REG(objp)); return -1; } @@ -86,7 +71,7 @@ int prop_ofs_to_id(EngineState *s, int prop_ofs, reg_t objp) { } if (prop_ofs < 0 || (prop_ofs >> 1) >= selectors) { - sciprintf("Applied prop_ofs_to_id to invalid property offset %x (property #%d not in [0..%d]) on object at %04x:%04x\n", + sciprintf("Applied propertyOffsetToId to invalid property offset %x (property #%d not in [0..%d]) on object at %04x:%04x\n", prop_ofs, prop_ofs >> 1, selectors - 1, PRINT_REG(objp)); return -1; } @@ -257,7 +242,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod if ((opcode == op_pTos) || (opcode == op_sTop) || (opcode == op_pToa) || (opcode == op_aTop) || (opcode == op_dpToa) || (opcode == op_ipToa) || (opcode == op_dpTos) || (opcode == op_ipTos)) { int prop_ofs = scr[pos.offset + 1]; - int prop_id = prop_ofs_to_id(s, prop_ofs, *p_objp); + int prop_id = propertyOffsetToId(s, prop_ofs, *p_objp); sciprintf(" (%s)", selector_name(s, prop_id)); } @@ -342,8 +327,6 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *objp, int *restadjust, SegmentId *segids, reg_t **variables, reg_t **variables_base, int *variables_nr, int bp) { -// TODO: disabled till this is moved in console.cpp -#if 0 // Do we support a separate console? int old_debugstate = g_debugstate_valid; @@ -412,7 +395,6 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t * // OK, found whatever we were looking for } } -#endif g_debugstate_valid = (g_debug_step_running == 0); diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 98fbd8bad7..2227167673 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -430,7 +430,7 @@ void SegManager::heapRelocate(reg_t block) { #define INST_LOOKUP_CLASS(id) ((id == 0xffff) ? NULL_REG : get_class_address(s, id, SCRIPT_GET_LOCK, NULL_REG)) -reg_t get_class_address(EngineState *s, int classnr, int lock, reg_t caller); +reg_t get_class_address(EngineState *s, int classnr, SCRIPT_GET lock, reg_t caller); Object *SegManager::scriptObjInit0(EngineState *s, reg_t obj_pos) { Object *obj; diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index dc91d60e69..a41d820014 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -45,29 +45,38 @@ namespace Sci { class SegManager : public Common::Serializable { public: - // Initialize the segment manager + /** + * Initialize the segment manager + */ SegManager(bool sci1_1); - // Deallocate all memory associated with the segment manager + /** + * Deallocate all memory associated with the segment manager + */ ~SegManager(); virtual void saveLoadWithSerializer(Common::Serializer &ser); // 1. Scripts - // Allocate a script into the segment manager - // Parameters: (int) script_nr: number of the script to load - // (state_t *) s: The state containing resource manager handlers to load the - // script data - // Returns : (int) 0 on failure, 1 on success - // (int) *seg_id: The segment ID of the newly allocated segment, on success + /** + * Allocate a script into the segment manager + * @param s The state containing resource manager + * handlers to load the script data + * @param script_nr The number of the script to load + * @param seg_id The segment ID of the newly allocated segment, + * on success + * @return 0 on failure, 1 on success + */ Script *allocateScript(EngineState *s, int script_nr, SegmentId *seg_id); // The script must then be initialised; see section (1b.), below. - // Forcefully deallocate a previously allocated script - // Parameters: (int) script_nr: number of the script to deallocate - // Returns : (int) 1 on success, 0 on failure + /** + * Forcefully deallocate a previously allocated script + * @param script_nr number of the script to deallocate + * @return 1 on success, 0 on failure + */ int deallocateScript(int script_nr); /** @@ -76,30 +85,40 @@ public: */ bool scriptIsLoaded(SegmentId seg); - // Validate whether the specified public function is exported by the script in the specified segment - // Parameters: (int) pubfunct: Index of the function to validate - // (int) seg: Segment ID of the script the check is to be performed for - // Returns : (uint16) 0 if the public function is invalid, its offset into the script's segment - // otherwise + /** + * Validate whether the specified public function is exported by + * the script in the specified segment + * @param pubfunct Index of the function to validate + * @param seg Segment ID of the script the check is to + * be performed for + * @return NULL if the public function is invalid, its + * offset into the script's segment otherwise + */ uint16 validateExportFunc(int pubfunct, SegmentId seg); - // Get the segment ID associated with a script number - // Parameters: (int) script_nr: Number of the script to look up - // Returns : (int) The associated segment ID, or -1 if no matching segment exists + /** + * Get the segment ID associated with a script number + * @param script_nr Number of the script to look up + * @return The associated segment ID, or -1 if no + * matching segment exists + */ SegmentId segGet(int script_nr) const; /** - * Return a pointer to the specified script. If the id is invalid, does not refer - * to a script or the script is not loaded, this will invoke error(). + * Return a pointer to the specified script. + * If the id is invalid, does not refer to a script or the script is + * not loaded, this will invoke error(). * @param seg ID of the script segment to check for - * @return pointer to the Script object + * @return A pointer to the Script object */ Script *getScript(SegmentId seg); /** - * Return a pointer to the specified script. If the id is invalid, does not refer + * Return a pointer to the specified script. + * If the id is invalid, does not refer to a script, or + * the script is not loaded, this will return NULL * @param seg ID of the script segment to check for - * @return pointer to the Script object, or NULL + * @return A pointer to the Script object, or NULL */ Script *getScriptIfLoaded(SegmentId seg); @@ -112,51 +131,70 @@ public: // to be used during script instantiation, // i.e. loading and linking. - // Initializes a script's local variable block - // Parameters: (SegmentId) seg: Segment containing the script to initialize - // (int) nr: Number of local variables to allocate - // All variables are initialized to zero. + /** + * Initializes a script's local variable block + * All variables are initialized to zero. + * @param seg Segment containing the script to initialize + * @param nr Number of local variables to allocate + */ void scriptInitialiseLocalsZero(SegmentId seg, int nr); - // Initializes a script's local variable block according to a prototype - // Parameters: (reg_t) location: Location to initialize from + /** + * Initializes a script's local variable block according to a prototype + * @param location Location to initialize from + */ void scriptInitialiseLocals(reg_t location); - // Initializes an object within the segment manager - // Parameters: (reg_t) obj_pos: Location (segment, offset) of the object - // Returns : (Object *) A newly created Object describing the object - // obj_pos must point to the beginning of the script/class block (as opposed - // to what the VM considers to be the object location) - // The corresponding Object is stored within the relevant script. + /** + * Initializes an object within the segment manager + * @param obj_pos Location (segment, offset) of the object. It must + * point to the beginning of the script/class block + * (as opposed to what the VM considers to be the + * object location) + * @returns A newly created Object describing the object, + * stored within the relevant script + */ Object *scriptObjInit(EngineState *s, reg_t obj_pos); - // Informs the segment manager that a code block must be relocated - // Parameters: (reg_t) location: Start of block to relocate + /** + * Informs the segment manager that a code block must be relocated + * @param location Start of block to relocate + */ void scriptAddCodeBlock(reg_t location); - // Tells the segment manager whether exports are wide (32-bit) or not. - // Parameters: (int) flag: 1 if exports are wide, 0 otherwise + /** + * Tells the segment manager whether exports are wide (32-bit) or not. + * @param flag 1 if exports are wide, 0 otherwise + */ void setExportWidth(int flag); - // Processes a relocation block witin a script - // Parameters: (reg_t) obj_pos: Location (segment, offset) of the block - // Returns : (Object *) Location of the relocation block - // This function is idempotent, but it must only be called after all - // objects have been instantiated, or a run-time error will occur. + /** + * Processes a relocation block witin a script + * This function is idempotent, but it must only be called after all + * objects have been instantiated, or a run-time error will occur. + * @param obj_pos Location (segment, offset) of the block + * @return Location of the relocation block + */ void scriptRelocate(reg_t block); - // Determines whether the script referenced by the indicated segment is marked as being deleted. - // Parameters: (SegmentId) Segment ID of the script to investigate - // Returns : (int) 1 iff seg points to a script and the segment is deleted, 0 otherwise - // Will return 0 when applied to an invalid or non-script seg. + /** + * Determines whether the script referenced by the indicated segment + * is marked as being deleted. + * Will return 0 when applied to an invalid or non-script seg. + * @param seg Segment ID of the script to investigate + * @return 1 iff seg points to a script and the segment is + * deleted, 0 otherwise + */ bool scriptIsMarkedAsDeleted(SegmentId seg); // 2. Clones - // Allocate a fresh clone - // Returns : (Clone*): Reference to the memory allocated for the clone - // (reg_t) *addr: The offset of the freshly allocated clone + /** + * Allocate a fresh clone + * @param addr The offset of the freshly allocated clone + * @return Reference to the memory allocated for the clone + */ Clone *alloc_Clone(reg_t *addr); @@ -166,76 +204,96 @@ public: // 4. Stack - // Allocates a data stack - // Parameters: (int) size: Number of stack entries to reserve - // Returns : (DataStack *): The physical stack - // (SegmentId) segid: Segment ID of the stack + /** + * Allocates a data stack + * @param size Number of stack entries to reserve + * @param segid Segment ID of the stack + * @return The physical stack + */ DataStack *allocateStack(int size, SegmentId *segid); // 5. System Strings - // Allocates a system string table - // Returns : (DataStack *): The physical stack - // (SegmentId) segid: Segment ID of the stack - // See also sys_string_acquire(); + /** + * Allocates a system string table + * See also sys_string_acquire(); + * @param[in] segid Segment ID of the stack + * @returns The physical stack + */ SystemStrings *allocateSysStrings(SegmentId *segid); // 5. System Strings - // Allocates a string fragments segment - // Returns : (SegmentId): Segment ID to use for string fragments - // See also stringfrag.h + /** + * Allocates a string fragments segment + * See also stringfrag.h + * @return Segment ID to use for string fragments + */ SegmentId allocateStringFrags(); // 6, 7. Lists and Nodes - // Allocate a fresh list - // Returns : (listY_t*): Reference to the memory allocated for the list - // (reg_t) *addr: The offset of the freshly allocated list + /** + * Allocate a fresh list + * @param[in] addr The offset of the freshly allocated list + * @return Reference to the memory allocated for the list + */ List *alloc_List(reg_t *addr); - // Allocate a fresh node - // Returns : (node_t*): Reference to the memory allocated for the node - // (reg_t) *addr: The offset of the freshly allocated node + /** + * Allocate a fresh node + * @param[in] addr The offset of the freshly allocated node + * @return Reference to the memory allocated for the node + */ Node *alloc_Node(reg_t *addr); // 8. Hunk Memory - // Allocate a fresh chunk of the hunk - // Parameters: (int) size: Number of bytes to allocate for the hunk entry - // (const char *) hunk_type: A descriptive string for the hunk entry, - // for debugging purposes - // Returns : (Hunk *): Reference to the memory allocated for the hunk piece - // (reg_t) *addr: The offset of the freshly allocated hunk entry + /** + * Allocate a fresh chunk of the hunk + * @param[in] size Number of bytes to allocate for the hunk entry + * @param[in] hunk_type A descriptive string for the hunk entry, for + * debugging purposes + * @param[out] addr The offset of the freshly allocated hunk entry + * @return Reference to the memory allocated for the hunk + * piece + */ Hunk *alloc_hunk_entry(const char *hunk_type, int size, reg_t *addr); - // Deallocates a hunk entry - // Parameters: (reg_t) addr: Offset of the hunk entry to delete + /** + * Deallocates a hunk entry + * @param[in] addr Offset of the hunk entry to delete + */ void free_hunk_entry(reg_t addr); // 9. Dynamic Memory - // Allocate some dynamic memory - // Parameters: (int) size: Number of bytes to allocate - // (const char_ *) description: A descriptive string, - // for debugging purposes - // Returns : (unsigned char*): Raw pointer into the allocated dynamic memory - // (reg_t) *addr: The offset of the freshly allocated X + /** + * Allocate some dynamic memory + * @param[in] size Number of bytes to allocate + * @param[in] description A descriptive string for debugging purposes + * @param[out] addr The offset of the freshly allocated X + * @return Raw pointer into the allocated dynamic + * memory + */ unsigned char *allocDynmem(int size, const char *description, reg_t *addr); - // Deallocates a piece of dynamic memory - // Parameters: (reg_t) addr: Offset of the dynmem chunk to free + /** + * Deallocates a piece of dynamic memory + * @param[in] addr Offset of the dynmem chunk to free + */ int freeDynmem(reg_t addr); - // Gets the description of a dynmem segment - // Parameters: (reg_t) addr: Segment to describe - // Returns : (const char *): Pointer to the descriptive string set in - // allocDynmem + /** + * Gets the description of a dynmem segment + * @param[in] addr Segment to describe + * @return Pointer to the descriptive string set in allocDynmem + */ const char *getDescription(reg_t addr); @@ -251,10 +309,12 @@ public: // Generic Operations on Segments and Addresses - // Dereferences a raw memory pointer - // Parameters: (reg_t) reg: The reference to dereference - // Returns : (byte *) The data block referenced - // (int) size: (optionally) the theoretical maximum size of it + /** + * Dereferences a raw memory pointer + * @param[in] reg The reference to dereference + * @param[out] size (optional) The theoretical maximum size + * @return The data block referenced + */ byte *dereference(reg_t reg, int *size); @@ -266,17 +326,17 @@ public: int initialiseScript(Script &scr, EngineState *s, int script_nr); private: - IntMapper *id_seg_map; // id - script id; seg - index of heap + IntMapper *id_seg_map; ///< id - script id; seg - index of heap public: // TODO: make private Common::Array<MemObject *> _heap; int reserved_id; int exports_wide; bool isSci1_1; - SegmentId Clones_seg_id; // ID of the (a) clones segment - SegmentId Lists_seg_id; // ID of the (a) list segment - SegmentId Nodes_seg_id; // ID of the (a) node segment - SegmentId Hunks_seg_id; // ID of the (a) hunk segment + SegmentId Clones_seg_id; ///< ID of the (a) clones segment + SegmentId Lists_seg_id; ///< ID of the (a) list segment + SegmentId Nodes_seg_id; ///< ID of the (a) node segment + SegmentId Hunks_seg_id; ///< ID of the (a) hunk segment private: MemObject *allocNonscriptSegment(MemObjectType type, SegmentId *segid); @@ -295,11 +355,12 @@ private: Object *scriptObjInit0(EngineState *s, reg_t obj_pos); Object *scriptObjInit11(EngineState *s, reg_t obj_pos); - /* Check segment validity - ** Parameters: (int) seg: The segment to validate - ** Returns : (bool) false if 'seg' is an invalid segment - ** true if 'seg' is a valid segment - */ + /** + * Check segment validity + * @param[in] seg The segment to validate + * @return false if 'seg' is an invalid segment, true if + * 'seg' is a valid segment + */ bool check(SegmentId seg); void dbgPrint(const char* msg, void *i); // for debug only diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index e35530700e..e618077d54 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -126,4 +126,73 @@ uint16 EngineState::currentRoomNumber() const { return script_000->locals_block->_locals[13].toUint16(); } +kLanguage EngineState::charToLanguage(const char c) const { + switch (c) { + case 'F': + return K_LANG_FRENCH; + case 'S': + return K_LANG_SPANISH; + case 'I': + return K_LANG_ITALIAN; + case 'G': + return K_LANG_GERMAN; + case 'J': + case 'j': + return K_LANG_JAPANESE; + case 'P': + return K_LANG_PORTUGUESE; + default: + return K_LANG_NONE; + } +} + +Common::String EngineState::getLanguageString(const char *str, kLanguage lang) const { + kLanguage secondLang = K_LANG_NONE; + + const char *seeker = str; + while (*seeker) { + if ((*seeker == '%') || (*seeker == '#')) { + secondLang = charToLanguage(*(seeker + 1)); + + if (secondLang != K_LANG_NONE) + break; + } + + seeker++; + } + + if ((secondLang == K_LANG_JAPANESE) && (*(seeker + 1) == 'J')) { + // FIXME: Add Kanji support + lang = K_LANG_ENGLISH; + } + + if (secondLang == lang) + return Common::String(seeker + 2); + + if (seeker) + return Common::String(str, seeker - str); + else + return Common::String(str); +} + +Common::String EngineState::strSplit(const char *str, const char *sep) { + EngineState *s = this; + + kLanguage lang = (kLanguage)GET_SEL32V(s->game_obj, printLang); + kLanguage subLang = (kLanguage)GET_SEL32V(s->game_obj, subtitleLang); + + // Use English when no language settings are present in the game + if (lang == K_LANG_NONE) + lang = K_LANG_ENGLISH; + + Common::String retval = getLanguageString(str, lang); + + if ((subLang != K_LANG_NONE) && (sep != NULL)) { + retval += sep; + retval += getLanguageString(str, subLang); + } + + return retval; +} + } // End of namespace Sci diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index 15c1c2e63e..ecfb9fe6f7 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -88,6 +88,18 @@ enum { SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE = 4 }; +/** Supported languages */ +enum kLanguage { + K_LANG_NONE = 0, + K_LANG_ENGLISH = 1, + K_LANG_FRENCH = 33, + K_LANG_SPANISH = 34, + K_LANG_ITALIAN = 39, + K_LANG_GERMAN = 49, + K_LANG_JAPANESE = 81, + K_LANG_PORTUGUESE = 351 +}; + struct drawn_pic_t { int nr; int palette; @@ -209,6 +221,16 @@ public: uint16 currentRoomNumber() const; + /** + * Processes a multilanguage string based on the current language settings and + * returns a string that is ready to be displayed. + * @param str the multilanguage string + * @param sep optional seperator between main language and subtitle language, + * if NULL is passed no subtitle will be added to the returned string + * @return processed string + */ + Common::String strSplit(const char *str, const char *sep = "\r----------\r"); + /* Debugger data: */ Breakpoint *bp_list; /**< List of breakpoints */ int have_bp; /**< Bit mask specifying which types of breakpoints are used in bp_list */ @@ -239,6 +261,10 @@ public: Kernel *_kernel; EngineState *successor; /**< Successor of this state: Used for restoring */ + +private: + kLanguage charToLanguage(const char c) const; + Common::String getLanguageString(const char *str, kLanguage lang) const; }; /** diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 0b84c0ef3c..cbd0b0cfbb 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -193,7 +193,7 @@ int script_error(EngineState *s, const char *file, int line, const char *reason) } #define CORE_ERROR(area, msg) script_error(s, "[" area "] " __FILE__, __LINE__, msg) -reg_t get_class_address(EngineState *s, int classnr, int lock, reg_t caller) { +reg_t get_class_address(EngineState *s, int classnr, SCRIPT_GET lock, reg_t caller) { if (NULL == s) { warning("vm.c: get_class_address(): NULL passed for \"s\""); @@ -1550,7 +1550,7 @@ SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector select return _lookup_selector_function(s, obj_location.segment, obj, selector_id, fptr); } -SegmentId script_get_segment(EngineState *s, int script_nr, int load) { +SegmentId script_get_segment(EngineState *s, int script_nr, SCRIPT_GET load) { SegmentId segment; if ((load & SCRIPT_GET_LOAD) == SCRIPT_GET_LOAD) diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index dfbbc39780..a3fabbe44b 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -198,7 +198,11 @@ struct selector_map_t { Selector points; /**< Used by AvoidPath() */ Selector syncCue; /**< Used by DoSync() */ - Selector syncTime; /**< Used by DoSync() */ + Selector syncTime; + + Selector printLang; /**< Used for i18n */ + Selector subtitleLang; + Selector parseLang; }; // A reference to an object's variable. @@ -287,8 +291,8 @@ struct Breakpoint { }; /** - * Set this to 1 to abort script execution immediately. Aborting will leave the - * debug exec stack intact. + * Set this to 1 to abort script execution immediately. Aborting will + * leave the debug exec stack intact. * Set it to 2 to force a replay afterwards. */ extern int script_abort_flag; @@ -307,31 +311,36 @@ extern int script_step_counter; /** * Executes function pubfunct of the specified script. - * Parameters: (EngineState *) s: The state which is to be executed with - * (uint16) script: The script which is called - * (uint16) pubfunct: The exported script function which is to be called - * (StackPtr) sp: Stack pointer position - * (reg_t) calling_obj: The heap address of the object which executed the call - * (uint16) argc: Number of arguments supplied - * (StackPtr) argp: Pointer to the first supplied argument - * Returns : (ExecStack *): A pointer to the new exec stack TOS entry + * @param[in] s The state which is to be executed with + * @param[in] script The script which is called + * @param[in] pubfunct The exported script function which is to + * be called + * @param[in] sp Stack pointer position + * @param[in] calling_obj The heap address of the object that + * executed the call + * @param[in] argc Number of arguments supplied + * @param[in] argp Pointer to the first supplied argument + * @return A pointer to the new exec stack TOS entry */ -ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackPtr sp, reg_t calling_obj, - uint16 argc, StackPtr argp); +ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, + StackPtr sp, reg_t calling_obj, uint16 argc, StackPtr argp); /** * Executes a "send" or related operation to a selector. - * Parameters: (EngineState *) s: The EngineState to operate on - * (reg_t) send_obj: Heap address of the object to send to - * (reg_t) work_obj: Heap address of the object initiating the send - * (StackPtr) sp: Stack pointer position - * (int) framesize: Size of the send as determined by the "send" operation - * (StackPtr) argp: Pointer to the beginning of the heap block containing the - * data to be sent. This area is a succession of one or more - * sequences of [selector_number][argument_counter] and then - * "argument_counter" word entries with the parameter values. - * Returns : (ExecStack *): A pointer to the new execution stack TOS entry + * @param[in] s The EngineState to operate on + * @param[in] send_obj Heap address of the object to send to + * @param[in] work_obj Heap address of the object initiating the send + * @param[in] sp Stack pointer position + * @param[in] framesize Size of the send as determined by the "send" + * operation + * @param[in] argp Pointer to the beginning of the heap block + * containing the data to be sent. This area is a + * succession of one or more sequences of + * [selector_number][argument_counter] and then + * "argument_counter" word entries with the + * parameter values. + * @return A pointer to the new execution stack TOS entry */ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPtr sp, int framesize, StackPtr argp); @@ -342,267 +351,300 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, /** * Adds an entry to the top of the execution stack. * - * @param s The state with which to execute - * @param pc The initial program counter - * @param sp The initial stack pointer - * @param objp Pointer to the beginning of the current object - * @param argc Number of parameters to call with - * @param argp Heap pointer to the first parameter - * @param selector The selector by which it was called or - * NULL_SELECTOR if n.a. For debugging. - * @param sendp Pointer to the object which the message was sent to. - * Equal to objp for anything but super. - * @param origin Number of the execution stack element this entry was created by - * (usually the current TOS number, except for multiple sends). - * @param local_segment The segment to use for local variables, - * or SCI_XS_CALLEE_LOCALS to use obj's segment. - * @return a pointer to the new exec stack TOS entry - */ -ExecStack *add_exec_stack_entry(EngineState *s, reg_t pc, StackPtr sp, reg_t objp, int argc, - StackPtr argp, Selector selector, reg_t sendp, int origin, SegmentId local_segment); + * @param[in] s The state with which to execute + * @param[in] pc The initial program counter + * @param[in] sp The initial stack pointer + * @param[in] objp Pointer to the beginning of the current object + * @param[in] argc Number of parameters to call with + * @param[in] argp Heap pointer to the first parameter + * @param[in] selector The selector by which it was called or + * NULL_SELECTOR if n.a. For debugging. + * @param[in] sendp Pointer to the object which the message was + * sent to. Equal to objp for anything but super. + * @param[in] origin Number of the execution stack element this + * entry was created by (usually the current TOS + * number, except for multiple sends). + * @param[in] local_segment The segment to use for local variables, + * or SCI_XS_CALLEE_LOCALS to use obj's segment. + * @return A pointer to the new exec stack TOS entry + */ +ExecStack *add_exec_stack_entry(EngineState *s, reg_t pc, StackPtr sp, + reg_t objp, int argc, StackPtr argp, Selector selector, + reg_t sendp, int origin, SegmentId local_segment); /** * Adds one varselector access to the execution stack. - * Parameters: (EngineState *) s: The EngineState to use - * (reg_t) objp: Pointer to the object owning the selector - * (int) argc: 1 for writing, 0 for reading - * (StackPtr) argp: Pointer to the address of the data to write -2 - * (int) selector: Selector name - * (ObjVarRef& ) address: Heap address of the selector - * (int) origin: Stack frame which the access originated from - * Returns : (ExecStack *): Pointer to the new exec-TOS element * This function is called from send_selector only. + * @param[in] s The EngineState to use + * @param[in] objp Pointer to the object owning the selector + * @param[in] argc 1 for writing, 0 for reading + * @param[in] argp Pointer to the address of the data to write -2 + * @param[in] selector Selector name + * @param[in] address Heap address of the selector + * @param[in] origin Stack frame which the access originated from + * @return Pointer to the new exec-TOS element */ -ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, StackPtr argp, - Selector selector, const ObjVarRef& address, int origin); - +ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, + StackPtr argp, Selector selector, const ObjVarRef& address, + int origin); +/** + * This function executes SCI bytecode + * It executes the code on s->heap[pc] until it hits a 'ret' operation + * while (stack_base == stack_pos). Requires s to be set up correctly. + * @param[in] s The state to use + * @param[in] restoring 1 if s has just been restored, 0 otherwise + */ void run_vm(EngineState *s, int restoring); -/* Executes the code on s->heap[pc] until it hits a 'ret' operation while (stack_base == stack_pos) -** Parameters: (EngineState *) s: The state to use -** (int) restoring: 1 if s has just been restored, 0 otherwise -** Returns : (void) -** This function will execute SCI bytecode. It requires s to be set up -** correctly. -*/ +/** + * Handles a fatal error condition + * @param[in] s The state to recover from + * @param[in] line Source code line number the error occured in + * @param[in] file File the error occured in + */ void vm_handle_fatal_error(EngineState *s, int line, const char *file); -/* Handles a fatal error condition -** Parameters: (EngineState *) s: The state to recover from -** (int) line: Source code line number the error occured in -** (const char *) file: File the error occured in -*/ - - -void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *objp, - int *restadjust, SegmentId *segids, reg_t **variables, reg_t **variables_base, - int *variables_nr, int bp); -/* Debugger functionality -** Parameters: (EngineState *) s: The state at which debugging should take place -** (reg_t *) pc: Pointer to the program counter -** (StackPtr *) sp: Pointer to the stack pointer -** (StackPtr *) pp: Pointer to the frame pointer -** (reg_t *) objp: Pointer to the object base pointer -** (int *) restadjust: Pointer to the &rest adjustment value -** (SegmentId *) segids: four-element array containing segment IDs for locals etc. -** (reg_t **) variables: four-element array referencing registers for globals etc. -** (reg_t **) variables_base: four-element array referencing -** register bases for temps etc. -** (int *) variables_nr: four-element array giving sizes for params etc. (may be NULL) -** (int) bp: Flag, set to 1 when a breakpoint is triggered -** Returns : (void) -*/ + +/** + * Debugger functionality + * @param[in] s The state at which debugging should take + * place + * @param[in] pc Pointer to the program counter + * @param[in] sp Pointer to the stack pointer + * @param[in] pp Pointer to the frame pointer + * @param[in] objp Pointer to the object base pointer + * @param[in] restadjust Pointer to the &rest adjustment value + * @param[in] segids four-element array containing segment IDs + * for locals etc. + * @param[in] variables four-element array referencing registers + * for globals etc. + * @param[in] variables_base four-element array referencing register + * bases for temps etc. + * @param[in] variables_nr four-element array giving sizes for params + * etc. (may be NULL) + * @param[in] bp Flag, set to 1 when a breakpoint is + * triggered + */ +void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, + reg_t *objp, int *restadjust, SegmentId *segids, reg_t **variables, + reg_t **variables_base, int *variables_nr, int bp); + +/** + * Initializes a EngineState block + * @param[in] s The state to initialize + * @return 0 on success, 1 if vocab.996 (the class table) is missing + * or corrupted + */ int script_init_engine(EngineState *s); -/* Initializes a EngineState block -** Parameters: (EngineState *) s: The state to initialize -** Returns : 0 on success, 1 if vocab.996 (the class table) is missing or corrupted -*/ +/** + * Sets the gamestate's save_dir to the parameter path + * @param[in] s The state to set + * @param[in] path Path where save_dir will point to + */ void script_set_gamestate_save_dir(EngineState *s, const char *path); -/* Sets the gamestate's save_dir to the parameter path -** Parameters: (EngineState *) s: The state to set -** (const char *) path: Path where save_dir will point to -** Returns : (void) -*/ +/** + * Frees all additional memory associated with a EngineState block + * @param[in] s The EngineState whose elements should be cleared + */ void script_free_engine(EngineState *s); -/* Frees all additional memory associated with a EngineState block -** Parameters: (EngineState *) s: The EngineState whose elements should be cleared -** Returns : (void) -*/ +/** + * Frees all script memory (heap, hunk, and class tables). + * This operation is implicit in script_free_engine(), but is required for + * restoring the game state. + * @param[in] s The EngineState to free + */ void script_free_vm_memory(EngineState *s); -/* Frees all script memory (heap, hunk, and class tables). -** Parameters: (EngineState *) s: The EngineState to free -** Returns : (void) -** This operation is implicit in script_free_engine(), but is required for restoring -** the game state. -*/ - - -SelectorType lookup_selector(EngineState *s, reg_t obj, Selector selectorid, ObjVarRef *varp, reg_t *fptr); -/* Looks up a selector and returns its type and value -** Parameters: (EngineState *) s: The EngineState to use -** (reg_t) obj: Address of the object to look the selector up in -** (Selector) selectorid: The selector to look up -** Returns : (SelectorType) kSelectorNone if the selector was not found in the object or its superclasses. -** kSelectorVariable if the selector represents an object-relative variable -** kSelectorMethod if the selector represents a method -** (ObjVarRef *) *varp: A reference to the selector, if -** it is a variable -** (reg_t) *fptr: A reference to the function described by that selector, if it is -** a valid function selector. -** *varindex is written to iff it is non-NULL and the selector indicates a property of the object. -** *fptr is written to iff it is non-NULL and the selector indicates a member function of that object. -*/ -enum { +/** + * Looks up a selector and returns its type and value + * varindex is written to iff it is non-NULL and the selector indicates a property of the object. + * @param[in] s The EngineState to use + * @param[in] obj Address of the object to look the selector up in + * @param[in] selectorid The selector to look up + * @param[out] varp A reference to the selector, if it is a + * variable. + * @param[out] fptr A reference to the function described by that + * selector, if it is a valid function selector. + * fptr is written to iff it is non-NULL and the + * selector indicates a member function of that + * object. + * @return kSelectorNone if the selector was not found in + * the object or its superclasses. + * kSelectorVariable if the selector represents an + * object-relative variable. + * kSelectorMethod if the selector represents a + * method + */ +SelectorType lookup_selector(EngineState *s, reg_t obj, Selector selectorid, + ObjVarRef *varp, reg_t *fptr); + +/** + * Parameters for script_get_segment() + */ +typedef enum { SCRIPT_GET_DONT_LOAD = 0, /**< Fail if not loaded */ SCRIPT_GET_LOAD = 1, /**< Load, if neccessary */ SCRIPT_GET_LOCK = 3 /**< Load, if neccessary, and lock */ -}; +} SCRIPT_GET; -SegmentId script_get_segment(EngineState *s, int script_id, int load); -/* Determines the segment occupied by a certain script -** Parameters: (EngineState *) s: The state to operate on -** (int) script_id: The script in question -** (int) load: One of SCRIPT_GET_* -** Returns : The script's segment, or 0 on failure -*/ +/** + * Determines the segment occupied by a certain script + * @param[in] s The state to operate on + * @param[in] script_id The script in question + * @param[in] load One of SCRIPT_GET_* + * @return The script's segment, or 0 on failure + */ +SegmentId script_get_segment(EngineState *s, int script_id, SCRIPT_GET load); +/** + * Looks up an entry of the exports table of a script + * @param[in] s The state to operate on + * @param[in] script_nr The script to look up in + * @param[out] export_index The index of the export entry to look up + * @return The handle + */ reg_t script_lookup_export(EngineState *s, int script_nr, int export_index); -/* Looks up an entry of the exports table of a script -** Parameters: (EngineState *) s: The state to operate on -** (int) script_nr: The script to look up in -** Returns : (int) export_index: index of the export entry to look up -*/ +/** + * Makes sure that a script and its superclasses get loaded to the heap. + * If the script already has been loaded, only the number of lockers is + * increased. All scripts containing superclasses of this script are loaded + * recursively as well, unless 'recursive' is set to zero. The + * complementary function is "script_uninstantiate()" below. + * @param[in] s The state to operate on + * @param[in] script_nr The script number to load + * @return The script's segment ID or 0 if out of heap + */ int script_instantiate(EngineState *s, int script_nr); -/* Makes sure that a script and its superclasses get loaded to the heap -** Parameters: (EngineState *) s: The state to operate on -** (int) script_nr: The script number to load -** Returns : (int) The script's segment ID or 0 if out of heap -** If the script already has been loaded, only the number of lockers is increased. -** All scripts containing superclasses of this script aret loaded recursively as well, -** unless 'recursive' is set to zero. -** The complementary function is "script_uninstantiate()" below. -*/ - +/** + * Decreases the numer of lockers of a script and unloads it if that number + * reaches zero. + * This function will recursively unload scripts containing its + * superclasses, if those aren't locked by other scripts as well. + * @param[in] s The state to operate on + * @param[in] script_nr The script number that is requestet to be unloaded + */ void script_uninstantiate(EngineState *s, int script_nr); -/* Decreases the numer of lockers of a script and unloads it if that number reaches zero -** Parameters: (EngineState *) s: The state to operate on -** (int) script_nr: The script number that is requestet to be unloaded -** Returns : (void) -** This function will recursively unload scripts containing its superclasses, if those -** aren't locked by other scripts as well. -*/ - +/** + * Initializes an SCI game + * This function must be run before script_run() is executed. Graphics data + * is initialized iff s->gfx_state != NULL. + * @param[in] s The state to operate on + * @return 0 on success, 1 if an error occured. + */ int game_init(EngineState *s); -/* Initializes an SCI game -** Parameters: (EngineState *) s: The state to operate on -** Returns : (int): 0 on success, 1 if an error occured. -** This function must be run before script_run() is executed. -** Graphics data is initialized iff s->gfx_state != NULL. -*/ +/** + * Initializes the graphics part of an SCI game + * This function may only be called if game_init() did not initialize + * the graphics data. + * @param[in] s The state to initialize the graphics in + * @return 0 on success, 1 if an error occured + */ int game_init_graphics(EngineState *s); -/* Initializes the graphics part of an SCI game -** Parameters: (EngineState *) s: The state to initialize the graphics in -** Returns : (int) 0 on success, 1 if an error occured -** This function may only be called if game_init() did not initialize -** the graphics data. -*/ +/** + * Initializes the sound part of an SCI game + * This function may only be called if game_init() did not initialize + * the sound data. + * @param[in] s The state to initialize the sound in + * @param[in] sound_flags Flags to pass to the sound subsystem + * @return 0 on success, 1 if an error occured + */ int game_init_sound(EngineState *s, int sound_flags); -/* Initializes the sound part of an SCI game -** Parameters: (EngineState *) s: The state to initialize the sound in -** (int) sound_flags: Flags to pass to the sound subsystem -** Returns : (int) 0 on success, 1 if an error occured -** This function may only be called if game_init() did not initialize -** the graphics data. -*/ - +/** + * Runs an SCI game + * This is the main function for SCI games. It takes a valid state, loads + * script 0 to it, finds the game object, allocates a stack, and runs the + * init method of the game object. In layman's terms, this runs an SCI game. + * Note that, EngineState *s may be changed during the game, e.g. if a game + * state is restored. + * @param[in] s Pointer to the pointer of the state to operate on + * @return 0 on success, 1 if an error occured. + */ int game_run(EngineState **s); -/* Runs an SCI game -** Parameters: (EngineState **) s: Pointer to the pointer of the state to operate on -** Returns : (int): 0 on success, 1 if an error occured. -** This is the main function for SCI games. It takes a valid state, loads script 0 to it, -** finds the game object, allocates a stack, and runs the init method of the game object. -** In layman's terms, this runs an SCI game. -** By the way, *s may be changed during the game, e.g. if a game state is restored. -*/ +/** + * Restores an SCI game state and runs the game + * This restores a savegame; otherwise, it behaves just like game_run(). + * @param[in] s Pointer to the pointer of the state to + * operate on + * @param[in] savegame_name Name of the savegame to restore + * @return 0 on success, 1 if an error occured. + */ int game_restore(EngineState **s, char *savegame_name); -/* Restores an SCI game state and runs the game -** Parameters: (EngineState **) s: Pointer to the pointer of the state to operate on -** (char *) savegame_name: Name of the savegame to restore -** Returns : (int): 0 on success, 1 if an error occured. -** This restores a savegame; otherwise, it behaves just like game_run(). -*/ +/** + * Uninitializes an initialized SCI game + * This function should be run after each script_run() call. + * @param[in] s The state to operate on + * @return 0 on success, 1 if an error occured. + */ int game_exit(EngineState *s); -/* Uninitializes an initialized SCI game -** Parameters: (EngineState *) s: The state to operate on -** Returns : (int): 0 on success, 1 if an error occured. -** This function should be run after each script_run() call. -*/ +/** + * Instructs the virtual machine to abort + */ void quit_vm(); -/* Instructs the virtual machine to abort -** Paramteres: (void) -** Returns : (void) -*/ +/** + * Allocates "kernel" memory and returns a handle suitable to be passed on + * to SCI scripts + * @param[in] s Pointer to the EngineState to operate on + * @param[in] type A free-form type description string (static) + * @param[in] space The space to allocate + * @return The handle + */ reg_t kalloc(EngineState *s, const char *type, int space); -/* Allocates "kernel" memory and returns a handle suitable to be passed on to SCI scripts -** Parameters: (EngineState *) s: Pointer to the EngineState to operate on -** (const char *) type: A free-form type description string (static) -** (int) space: The space to allocate -** Returns : (reg_t) The handle -*/ +/** + * Returns a pointer to "kernel" memory based on the handle + * @param[in] s Pointer to the EngineState to operate on + * @param[in] handle The handle to use + * @return A pointer to the allocated memory + */ byte *kmem(EngineState *s, reg_t handle); -/* Returns a pointer to "kernel" memory based on the handle -** Parameters: (EngineState *) s: Pointer to the EngineState to operate on -** (reg_t) handle: The handle to use -** Returns : (byte *) A pointer to the allocated memory -*/ - +/** + * Frees all "kernel" memory associated with a handle + * @param[in] s Pointer to the EngineState to operate on + * @param[in] handle The handle to free + * @return 0 on success, 1 otherwise + */ int kfree(EngineState *s, reg_t handle); -/* Frees all "kernel" memory associated with a handle -** Parameters: (EngineState *) s: Pointer to the EngineState to operate on -** (reg_t) handle: The handle to free -** Returns : (int) 0 on success, 1 otherwise -*/ +/** + * Determines the name of an object + * @param[in] s Pointer to the EngineState to operate on + * @param[in] pos Location of the object whose name we want to inspect + * @return A name for that object, or a string describing an error + * that occured while looking it up. The string is stored + * in a static buffer and need not be freed (neither may + * it be modified). + */ const char *obj_get_name(EngineState *s, reg_t pos); -/* Determines the name of an object -** Parameters: (EngineState *) s: Pointer to the EngineState to operate on -** (reg_t) pos: Location of the object whose name we want to -** inspect -** Returns : (const char *) A name for that object, or a string describing -** an error that occured while looking it up -** The string is stored in a static buffer and need not be freed (neither -** may it be modified). -*/ +/** + * Retrieves an object from the specified location + * @param[in] s Pointer to the EngineState to operate on + * @param[in] offset The object's offset + * @return The object in question, or NULL if there is none + */ Object *obj_get(EngineState *s, reg_t offset); -/* Retrieves an object from the specified location -** Parameters: (EngineState *) s: Pointer to the EngineState to operate on -** (reg_t) offset: The object's offset -** Returns : (Object *) The object in question, or NULL if there is none -*/ +/** + * Shrink execution stack to size. + * Contains an assert it is not already smaller. + */ void shrink_execution_stack(EngineState *s, uint size); -/* Shrink execution stack to size. -** Contains an assert it is not already smaller. -*/ } // End of namespace Sci diff --git a/engines/sci/gfx/font.h b/engines/sci/gfx/font.h index 935414f550..fe0d81d135 100644 --- a/engines/sci/gfx/font.h +++ b/engines/sci/gfx/font.h @@ -30,6 +30,8 @@ namespace Sci { +/** @name Font operations and stuctures */ +/** @{ */ struct TextFragment { const char *offset; @@ -39,90 +41,109 @@ struct TextFragment { TextFragment(const char *o) : offset(o), length(0) {} }; - -struct gfx_bitmap_font_t { /* gfx_bitmap_font_t: Bitmap font information */ - int ID; /* Unique resource ID */ - - int chars_nr; /* Numer of available characters */ - - int *widths; /* chars_nr character widths, in pixels */ - - int row_size; /* Byte size of each pixel row. For unscaled fonts, this is - ** always 1, 2, or 4. Otherwise, it's a multiple of 4. - */ - - int line_height; /* Height of each text line (usually identical to height) */ - int height; /* Height for all characters, in pixel rows */ - int char_size; /* Amount of memory occupied by one character in data */ - - byte *data; /* Font data, consisting of 'chars_nr' entries of 'height' rows - ** of 'row_size' bytes. For each character ch, its first byte - ** (the topmost row) is located at (data + (charsize * ch)), and - ** its pixel width is widths[ch], provided that (ch < chars_nr). - */ - +/** + * Bitmap font information. + */ +struct gfx_bitmap_font_t { + int ID; /**< Unique resource ID */ + int chars_nr; /**< Numer of available characters */ + int *widths; /**< chars_nr character widths, in pixels */ + int row_size; /** + * Byte size of each pixel row. For unscaled fonts, + * this is always 1, 2, or 4. Otherwise, it's a + * multiple of 4. + */ + int line_height; /** + * Height of each text line (usually identical to + * height) + */ + int height; /**< Height for all characters, in pixel rows */ + int char_size; /** + * Amount of memory occupied by one character + * in data + */ + byte *data; /** + * Font data, consisting of 'chars_nr' entries + * of 'height' rows of 'row_size' bytes. For each + * character ch, its first byte (the topmost row) + * is located at (data + (charsize * ch)), and its + * pixel width is widths[ch], provided that + * (ch < chars_nr). + */ }; -/*******************/ -/* Font operations */ -/*******************/ - -/* SCI0, SCI01 and SCI1 all use the same font format. */ +/** + * Font handling flags. + * + * SCI0, SCI01 and SCI1 all use the same font format. + */ enum fontFlags { - kFontCountWhitespace = 1 << 0, // In SQ3, whitespace is included in text size - kFontNoNewlines = 1 << 1, // Don't treat newline characters - kFontIgnoreLF = 1 << 2 // Interpret CR LF sequences as a single newline, rather than two + kFontCountWhitespace = 1 << 0, //!< In SQ3, whitespace is included in text size + kFontNoNewlines = 1 << 1, //!< Don't treat newline characters + kFontIgnoreLF = 1 << 2 //!< Interpret CR LF sequences as a single newline, rather than two }; +/** + * Generates a bitmap font data structure from a resource. + * + * @param[in] id Resource ID of the resulting font + * @param[in] resource Pointer to the resource data + * @param[in] size Size of the resource block + * @return The resulting font structure, or NULL on error + */ gfx_bitmap_font_t *gfxr_read_font(int id, byte *resource, int size); -/* Generates a bitmap font data structure from a resource -** Parameters: (int) id: Resource ID of the resulting font -** (byte *) resource: Pointer to the resource data -** (int) size: Size of the resource block -** Returns : (gfx_bitmap_font_t *) The resulting font structure, or -** NULL on error -*/ +/** + * Frees a previously allocated font structure. + * + * @param font The font to free + */ void gfxr_free_font(gfx_bitmap_font_t *font); -/* Frees a previously allocated font structure -** Parameters: (gfx_bitmap_font_t *) font: The font to free -** Returns : (void) -*/ +/** + * Calculates the size that would be occupied by drawing a specified + * text. + * + * This function assumes 320x200 mode. + * + * @param[in] font The font to calculate with + * @param[in] max_width Maximum pixel width allowed for the output + * @param[in] text The text to calculate for + * @param[in] flags Any text formatting flags + * @param[out] fragments A newly allocated array of text_fragments, + * containing the start and size of each string + * segment. + * @param[out] width The resulting width + * @param[out] height The resulting height + * @param[out] line_height Pixel height of a single line of text + * @param[out] last_offset Pixel offset after the last drawn line + * @return true if successful, false otherwise + */ bool gfxr_font_calculate_size(Common::Array<TextFragment> &fragments, gfx_bitmap_font_t *font, int max_width, const char *text, int *width, int *height, int *line_height, int *last_offset, int flags); -/* Calculates the size that would be occupied by drawing a specified text -** Parameters: (gfx_bitmap_font_t *) font: The font to calculate with -** (int) max_width: Maximum pixel width allowed for the output -** (const char *) text: The text to calculate for -** (int) flags: Any text formatting flags -** Returns : (text_fragment *) a newly allocated array of text_fragments, -** containing the start and size of each string -** segment -** (int) *width: The resulting width -** (int) *height: The resulting height -** (int) *line_height: Pixel height of a single line of text -** (int) *last_offset: Pixel offset after the last drawn line -** This function assumes 320x200 mode. -*/ - -gfx_pixmap_t *gfxr_draw_font(gfx_bitmap_font_t *font, const char *text, int characters, - PaletteEntry *fg0, PaletteEntry *fg1, PaletteEntry *bg); -/* Draws text in a specific font to a pixmap -** Parameters: (gfx_bitmap_font_t *) font: The font to use for drawing -** (char *) text: The start of the text to draw -** (int) characters: The number of characters to draw -** (gfx_pixmap_color_t *) fg0: The first foreground color -** (gfx_pixmap_color_t *) fg1: The second foreground color -** (gfx_pixmap_color_t *) bg: The background color -** Returns : (gfx_pixmap_t *) The result pixmap, or NULL on error -** The results are written to the pixmap's index buffer. Contents of the -** foreground and background fields are copied into a newly allocated font -** structure, so that the pixmap may be translated directly. -** If any of the colors is null, it will be assumed to be transparent. -** In color index mode, the specified colors have to be preallocated. -*/ + +/** + * Draws text in a specific font to a pixmap. + * + * The results are written to the pixmap's index buffer. Contents of the + * foreground and background fields are copied into a newly allocated font + * structure, so that the pixmap may be translated directly. If any of the + * colors is null, it will be assumed to be transparent. + * In color index mode, the specified colors have to be preallocated. + * + * @param[in] font The font to use for drawing + * @param[in] text The start of the text to draw + * @param[in] characters The number of characters to draw + * @param[in] fg0 The first foreground color + * @param[in] fg1 The second foreground color + * @param[in] bg The background color + * @return The result pixmap, or NULL on error + */ +gfx_pixmap_t *gfxr_draw_font(gfx_bitmap_font_t *font, const char *text, + int characters, PaletteEntry *fg0, PaletteEntry *fg1, + PaletteEntry *bg); +/** @} */ } // End of namespace Sci diff --git a/engines/sci/gfx/gfx_driver.h b/engines/sci/gfx/gfx_driver.h index b74511de77..f7cbd0b6c2 100644 --- a/engines/sci/gfx/gfx_driver.h +++ b/engines/sci/gfx/gfx_driver.h @@ -38,171 +38,202 @@ enum gfx_buffer_t { }; -/* Principial graphics driver architecture -** --------------------------------------- -** -** All graphics drivers must provide -** - One visual front buffer (the actually visible thing) -** - Two dynamic back buffers: -** + visual -** + priority -** - Two static buffers (containing the background image and picviews): -** + visual -** + priority -** -** The control buffer is handled outside the graphics driver architecture. -** Graphics are drawn by first setting the static buffers, then updating -** the back buffers (from the static buffers), adding all picviews and other -** widgets, and finally updating the front buffer. -** -** All coordinates refer to the scaled coordinate system. -** Invalid parameters should produce an error message. -** Support for some valid parameter values is optional (like different line -** modes). If an unsupported but valid parameter is specified, the function -** must use a reasonable default value. -*/ - +/** + * Graphics driver. + * + * Principial graphics driver architecture: + * + * All graphics drivers must provide + * - One visual front buffer (the actually visible thing) + * - Two dynamic back buffers: + * - visual + * - priority + * - Two static buffers (containing the background image and picviews): + * - visual + * - priority + * + * The control buffer is handled outside the graphics driver architecture. + * Graphics are drawn by first setting the static buffers, then updating + * the back buffers (from the static buffers), adding all picviews and other + * widgets, and finally updating the front buffer. + * + * All coordinates refer to the scaled coordinate system. + * Invalid parameters should produce an error message. + * Support for some valid parameter values is optional (like different line + * modes). If an unsupported but valid parameter is specified, the function + * must use a reasonable default value. + */ class GfxDriver { public: - /*** Initialization ***/ - + /** @name Initialization */ + /** @{ */ + /** + * Attempts to initialize a specific graphics mode. + * + * The scaling factors apply to the standard SCI resolution of 320x200 + * pixels and is used for internal representation of graphical data. + * The physical resolution set by the graphics driver may be different + * for practical reasons. + * Must also set _mode, preferably with the gfx_new_mode() function + * specified in gfx_tools.h. + * + * @param[in] xfact Horizontal scaling factor + * @param[in] yfact Vertical scaling factor + * @param[in] bytespp Any of GFX_COLOR_MODE_*. GFX_COLOR_MODE_INDEX + * implies color index mode. + * @return GFX_OK on success, GFX_ERROR if the mode could + * not be set, or GFX_FATAL if the graphics target + * is unuseable. + */ GfxDriver(int xfact, int yfact, int bytespp); - /* Attempts to initialize a specific graphics mode - ** Parameters: (int x int) xres, yres: Horizontal and vertical scaling - ** factors - ** (int) bytespp: Any of GFX_COLOR_MODE_*. GFX_COLOR_MODE_INDEX - ** implies color index mode. - ** Returns : (int) GFX_OK on success, GFX_ERROR if the mode could not be - ** set, or GFX_FATAL if the graphics target is unuseable. - ** The scaling factors apply to the standard SCI resolution of 320x200 pixels - ** and is used for internal representation of graphical data. The physical - ** resolution set by the graphics driver may be different for practical - ** reasons. - ** Must also set _mode, preferably with the gfx_new_mode() function - ** specified in gfx_tools.h. - */ + /** + * Uninitializes the current graphics mode. + * + * This function frees all memory allocated by the graphics driver, + * including mode and palette information, uninstalls all console + * commands introduced by preceeding init() or init_specific() + * commands, and does any clean-up work (like closing visuals or + * returning to text mode) required by the graphics infrastructure used. + */ ~GfxDriver(); - /* Uninitializes the current graphics mode - ** This function frees all memory allocated by the graphics driver, - ** including mode and palette information, uninstalls all console commands - ** introduced by preceeding init() or init_specific() commands, and does any - ** clean-up work (like closing visuals or returning to text mode) required by - ** the graphics infrastructure used. - */ - - - /*** Drawing operations ***/ - + /** @} */ + + /** @name Drawing operations */ + /** @{ */ + + /** + * Draws a single line to the back buffer. + * + * Note that color.priority is relevant and must be drawn if + * (color.mask & GFX_MASK_PRIORITY). Support for line modes other than + * GFX_LINE_MODE_FAST is optional. For non-fine lines, the coordinates + * provided describe the upper left corner of the pixels of the line + * to draw.line_style support is optional, if + * GFX_CAPABILITY_STIPPLED_LINES is not set. + * + * @param[in] start Starting point of the line to draw + * @param[in] end End point of the line to draw + * @param[in] color The color to draw with + * @param[in] line_mode Any of the line modes + * @param[in] line_style Any of the line styles + * @return GFX_OK or GFX_FATAL + */ int drawLine(Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style); - /* Draws a single line to the back buffer. - ** Parameters: (Common::Point) start: Starting point of the line to draw - ** (Common::Point) end: End point of the line to draw - ** (gfx_color_t *) color: The color to draw with - ** (int) line_mode: Any of the line modes - ** (int) line_style: Any of the line styles - ** Returns : (int) GFX_OK or GFX_FATAL - ** Note that color.priority is relevant and must be drawn if - ** (color.mask & GFX_MASK_PRIORITY). - ** Support for line modes other than GFX_LINE_MODE_FAST is optional. - ** For non-fine lines, the coordinates provided describe the upper left - ** corner of the pixels of the line to draw. - ** line_style support is optional, if GFX_CAPABILITY_STIPPLED_LINES is not - ** set. - */ + /** + * Draws a single filled and possibly shaded rectangle to the back + * buffer. + * + * Note that color.priority is relevant and must be drawn if + * (color.mask & GFX_MASK_PRIORITY). color2 is relevant only if + * shade_mode is not GFX_SHADE_FLAT. Support for shade modes other + * than GFX_SHADE_FLAT is optional. + * + * @param[in] rect The rectangle to draw + * @param[in] color1 The first color to draw with + * @param[in] color2 The second color to draw with + * @param[in] shade_mode Any of GFX_SHADE_*. + * @return GFX_OK or GFX_FATAL + */ int drawFilledRect(rect_t rect, gfx_color_t color1, gfx_color_t color2, gfx_rectangle_fill_t shade_mode); - /* Draws a single filled and possibly shaded rectangle to the back buffer. - ** Parameters: (rect_t *) rect: The rectangle to draw - ** (gfx_color_t *) color1, color2: The colors to draw with - ** (int) shade_mode: Any of GFX_SHADE_*. - ** Returns : (int) GFX_OK or GFX_FATAL - ** Note that color.priority is relevant and must be drawn if - ** (color.mask & GFX_MASK_PRIORITY). - ** color2 is relevant only if shade_mode is not GFX_SHADE_FLAT. - ** Support for shade modes other than GFX_SHADE_FLAT is optional. - */ - - /*** Pixmap operations ***/ - + /** @} */ + + /** @name Pixmap operations */ + /** @{ */ + + /** + * Draws part of a pixmap to the static or back buffer. + * + * @param[in] pxm The pixmap to draw + * @param[in] priority The priority to draw with, or GFX_NO_PRIORITY + * to draw on top of everything without setting the + * priority back buffer. + * @param[in] src The pixmap-relative source rectangle + * @param[in] dest The destination rectangle + * @param[in] buffer One of GFX_BUFFER_STATIC and GFX_BUFFER_BACK + * @return GFX_OK or GFX_FATAL, or GFX_ERROR if pxm was + * not (but should have been) registered. + */ int drawPixmap(gfx_pixmap_t *pxm, int priority, rect_t src, rect_t dest, gfx_buffer_t buffer); - /* Draws part of a pixmap to the static or back buffer - ** Parameters: (gfx_pixmap_t *) pxm: The pixmap to draw - ** (int) priority: The priority to draw with, or GFX_NO_PRIORITY - ** to draw on top of everything without setting the - ** priority back buffer - ** (rect_t) src: The pixmap-relative source rectangle - ** (rect_t) dest: The destination rectangle - ** (int) buffer: One of GFX_BUFFER_STATIC and GFX_BUFFER_BACK - ** Returns : (int) GFX_OK or GFX_FATAL, or GFX_ERROR if pxm was not - ** (but should have been) registered. - */ + /** + * Grabs an image from the visual or priority back buffer. + * + * This function is now mandatory. + * + * @param[in] src The rectangle to grab + * @param[in] pxm The pixmap structure the data is to be written to + * @param[in] map GFX_MASK_VISUAL or GFX_MASK_PRIORITY + * @return GFX_OK, GFX_FATAL, or GFX_ERROR for invalid map + * values pxm may be assumed to be empty and + * pre-allocated with an appropriate memory size. + */ int grabPixmap(rect_t src, gfx_pixmap_t *pxm, gfx_map_mask_t map); - /* Grabs an image from the visual or priority back buffer - ** Parameters: (rect_t) src: The rectangle to grab - ** (gfx_pixmap_t *) pxm: The pixmap structure the data is to - ** be written to - ** (int) map: GFX_MASK_VISUAL or GFX_MASK_PRIORITY - ** Returns : (int) GFX_OK, GFX_FATAL, or GFX_ERROR for invalid map values - ** pxm may be assumed to be empty and pre-allocated with an appropriate - ** memory size. - ** This function is now mandatory. - */ - - - /*** Buffer operations ***/ - + /** @} */ + + /** @name Buffer operations */ + /** @{ */ + + /** + * Updates the front buffer or the back buffers. + * + * This function updates either the visual front buffer, or the two + * back buffers, by copying the specified source region to the + * destination region. + * For heuristical reasons, it may be assumed that the x and y fields + * of src and dest will be identical in /most/ cases.If they aren't, + * the priority map will not be required to be copied. + * + * @param[in] src: Source rectangle + * @param[in] dest: Destination point + * @param[in] buffer: One of GFX_BUFFER_FRONT or GFX_BUFFER_BACK + * @return GFX_OK, GFX_ERROR or GFX_FATAL + */ int update(rect_t src, Common::Point dest, gfx_buffer_t buffer); - /* Updates the front buffer or the back buffers - ** Parameters: (rect_t) src: Source rectangle - ** (Common::Point) dest: Destination point - ** (int) buffer: One of GFX_BUFFER_FRONT or GFX_BUFFER_BACK - ** Returns : (int) GFX_OK, GFX_ERROR or GFX_FATAL - ** This function updates either the visual front buffer, or the two back - ** buffers, by copying the specified source region to the destination - ** region. - ** For heuristical reasons, it may be assumed that the x and y fields of - ** src and dest will be identical in /most/ cases. - ** If they aren't, the priority map will not be required to be copied. - */ + /** + * Sets the contents of the static visual and priority buffers. + * + * pic and priority may be modified or written to freely. They may also + * be used as the actual static buffers, since they are not freed and + * reallocated between calls to set_static_buffer() and update(), + * unless exit() was called in between. + * Note that later version of the driver interface may disallow + * modifying pic and priority. pic and priority are always scaled to + * the appropriate resolution + * + * @param[in] pic The image defining the new content of the + * visual back buffer + * @param[in] priority The priority map containing the new content of + * the priority back buffer in the index buffer + * @return GFX_OK or GFX_FATAL + */ int setStaticBuffer(gfx_pixmap_t *pic, gfx_pixmap_t *priority); - /* Sets the contents of the static visual and priority buffers - ** Parameters: (gfx_pixmap_t *) pic: The image defining the new content - ** of the visual back buffer - ** (gfx_pixmap_t *) priority: The priority map containing - ** the new content of the priority back buffer - ** in the index buffer - ** Returns : (int) GFX_OK or GFX_FATAL - ** pic and priority may be modified or written to freely. They may also be - ** used as the actual static buffers, since they are not freed and re- - ** allocated between calls to set_static_buffer() and update(), unless - ** exit() was called in between. - ** Note that later version of the driver interface may disallow modifying - ** pic and priority. - ** pic and priority are always scaled to the appropriate resolution - */ - - - /*** Mouse pointer operations ***/ - + /** @} */ + + /** @name Mouse pointer operations */ + /** @{ */ + + /** + * Sets a new mouse pointer. + * + * If pointer is not NULL, it will have been scaled to the appropriate + * size and registered as a pixmap (if neccessary) beforehand. If this + * function is called for a target that supports only two-color + * pointers, the image is a color index image, where only color index + * values 0, 1, and GFX_COLOR_INDEX_TRANSPARENT are used. + * + * @param[in] pointer The pointer to set, or NULL to set no pointer. + * @param[in] hotspot The coordinates of the hotspot, or NULL to set + * no pointer. + * @return GFX_OK or GFX_FATAL + */ int setPointer(gfx_pixmap_t *pointer, Common::Point *hotspot); - /* Sets a new mouse pointer. - ** Parameters: (gfx_pixmap_t *) pointer: The pointer to set, or NULL to set - ** no pointer - ** (Common::Point *) hotspot: The coordinates of the hotspot, - ** or NULL to set no pointer - ** Returns : (int) GFX_OK or GFX_FATAL - ** If pointer is not NULL, it will have been scaled to the appropriate - ** size and registered as a pixmap (if neccessary) beforehand. - ** If this function is called for a target that supports only two-color - ** pointers, the image is a color index image, where only color index values - ** 0, 1, and GFX_COLOR_INDEX_TRANSPARENT are used. - */ + /** @} */ gfx_mode_t *getMode() { return _mode; } byte *getVisual0() { return _visual[0]; } @@ -212,7 +243,7 @@ private: gfx_pixmap_t *_priority[2]; byte *_visual[2]; - gfx_mode_t *_mode; /* Currently active mode, NULL if no mode is active */ + gfx_mode_t *_mode; /**< Currently active mode, NULL if no mode is active */ }; } // End of namespace Sci diff --git a/engines/sci/gfx/gfx_gui.cpp b/engines/sci/gfx/gfx_gui.cpp index f73a13d6dd..fb05c0fe29 100644 --- a/engines/sci/gfx/gfx_gui.cpp +++ b/engines/sci/gfx/gfx_gui.cpp @@ -266,7 +266,7 @@ static rect_t _move_and_extend_rect(rect_t rect, Common::Point point, int yplus) return gfx_rect(rect.x + point.x, rect.y + point.y, rect.width + 1, rect.height + yplus); } -GfxList *_sciw_add_text_to_list(GfxList *list, GfxPort *port, rect_t zone, char *text, +GfxList *_sciw_add_text_to_list(GfxList *list, GfxPort *port, rect_t zone, const char *text, int font, gfx_alignment_t align, char framed, char inverse, int flags, char gray_text) { gfx_color_t *color1, *color2, *bgcolor; @@ -294,7 +294,7 @@ GfxList *_sciw_add_text_to_list(GfxList *list, GfxPort *port, rect_t zone, char return list; } -GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font, char selected, char inverse, char grayed_out) { +GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone, const char *text, int font, char selected, char inverse, char grayed_out) { gfx_color_t *frame_col = (inverse) ? &(port->_bgcolor) : &(port->_color); GfxList *list; @@ -332,7 +332,7 @@ GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone, char *tex return list; } -GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font, +GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone, const char *text, int font, gfx_alignment_t align, char framed, char inverse) { GfxList *list = gfxw_new_list(_move_and_extend_rect(zone, Common::Point(port->zone.x, port->zone.y), 2), 0); @@ -344,7 +344,7 @@ GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone, char *text, return _sciw_add_text_to_list(list, port, zone, text, font, align, framed, inverse, 0, port->gray_text); } -GfxList *sciw_new_edit_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font, unsigned int cursor, +GfxList *sciw_new_edit_control(GfxPort *port, reg_t ID, rect_t zone, const char *text, int font, unsigned int cursor, char inverse) { GfxText *text_handle; @@ -440,7 +440,7 @@ GfxList *sciw_new_icon_control(GfxPort *port, reg_t ID, rect_t zone, int view, i return list; } -GfxList *sciw_new_list_control(GfxPort *port, reg_t ID, rect_t zone, int font_nr, char **entries_list, +GfxList *sciw_new_list_control(GfxPort *port, reg_t ID, rect_t zone, int font_nr, const char **entries_list, int entries_nr, int list_top, int selection, char inverse) { GfxList *list; diff --git a/engines/sci/gfx/gfx_gui.h b/engines/sci/gfx/gfx_gui.h index e712d30660..68342aa0c0 100644 --- a/engines/sci/gfx/gfx_gui.h +++ b/engines/sci/gfx/gfx_gui.h @@ -23,8 +23,6 @@ * */ -/* SCI-specific widget handling */ - #ifndef SCI_INCLUDE_SCI_WIDGETS_H #define SCI_INCLUDE_SCI_WIDGETS_H @@ -34,152 +32,196 @@ namespace Sci { class Menu; -// The following flags are applicable to windows in SCI0 +/* SCI-specific widget handling */ + +/** + * Flags for windows in SCI0. + */ enum windowFlags { - kWindowTransparent = 0x01, // 0000 0001 - kWindowNoFrame = 0x02, // 0000 0010 - a window without a frame - // Add title bar to window (10 pixels high, framed, text is centered and written in white on dark gray) - kWindowTitle = 0x04, // 0000 0100 - // bits 3-6 are unused - kWindowDontDraw = 0x80, // 1000 0000 - don't draw anything - kWindowNoDropShadow = 0x1000000, // 0001 0000 0000 0000 0000 0000 0000 (not in SCI) + kWindowTransparent = 0x01, //!< 0000 0001 + kWindowNoFrame = 0x02, //!< 0000 0010 - a window without a frame + kWindowTitle = 0x04, /** + * 0000 0100 - Add title bar to + * window (10 pixels high, framed, + * text is centered and written in + * white on dark gray), bits 3-6 + * are unused + */ + kWindowDontDraw = 0x80, //!< 1000 0000 - don't draw anything + kWindowNoDropShadow = 0x1000000, //!< 0001 0000 0000 0000 0000 0000 0000 (not in SCI) kWindowAutoRestore = 0x2000000 }; +/** Button and frame control flags. */ enum controlStateFlags { - kControlStateEnabled = 0x0001, // 0001 - enabled buttons (used by the interpreter) - kControlStateDisabled = 0x0004, // 0010 - grayed out buttons (used by the interpreter) - kControlStateFramed = 0x0008, // 1000 - widgets surrounded by a frame (used by the interpreter) - kControlStateDitherFramed = 0x1000 // 0001 0000 0000 0000 - widgets surrounded by a dithered frame (used in kgraphics) + kControlStateEnabled = 0x0001, //!< 0001 - enabled buttons (used by the interpreter) + kControlStateDisabled = 0x0004, //!< 0010 - grayed out buttons (used by the interpreter) + kControlStateFramed = 0x0008, //!< 1000 - widgets surrounded by a frame (used by the interpreter) + kControlStateDitherFramed = 0x1000 //!< 0001 0000 0000 0000 - widgets surrounded by a dithered frame (used in kgraphics) }; -void sciw_set_status_bar(EngineState *s, GfxPort *status_bar, const Common::String &text, int fgcolor, int bgcolor); -/* Sets the contents of a port used as status bar -** Parmeters: (EngineState *) s: The affected game state -** (GfxPort *) status_bar: The status bar port -** (const char *) text: The text to draw -** Returns : (void) -*/ - -GfxPort *sciw_new_window(EngineState *s, rect_t area, int font, gfx_color_t color, gfx_color_t bgcolor, - int title_font, gfx_color_t title_color, gfx_color_t title_bg_color, - const char *title, int flags); -/* Creates a new SCI style window -** Parameters: (EngineState *) s: The affected game state -** (rect_t) area: The screen area to frame (not including a potential window title) -** (int) font: Default font number to use -** (gfx_color_t) color: The foreground color to use for drawing -** (gfx_color_t) bgcolor: The background color to use -** (int) title_font: The font to use for the title bar (if any) -** (gfx_color_t) title_color: Color to use for the title bar text -** (gfx_color_t) title_bg_color: Color to use for the title bar background -** (const char *) title: The text to write into the title bar -** (int) flags: Any ORred combination of window flags -** Returns : (GfxPort *) A newly allocated port with the requested characteristics -*/ - -/*---------------------*/ -/*** Control widgets ***/ -/*---------------------*/ - -GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font, char selected, char inverse, char gray); -/* Creates a new button control list -** Parameters: (GfxPort *) port: The port containing the color values to use for the -** button (the button is /not/ appended to the port there) -** (reg_t) ID: Button's ID -** (rect_t) zone: The area occupied by the button -** (char *) text: The text to write into the button -** (int) font: The font to use for the button -** (char) selected: Whether the button should be marked as being selected by the keyboard focus -** (char) inverse: Whether to inverse the color scheme -** (char) gray: Whether the button should be grayed out -** Returns : (GfxList *) The button -*/ - -GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font, - gfx_alignment_t align, char frame, char inverse); -/* Creates a new text control list -** Parameters: (GfxPort *) port: The port containing the color values to use -** (reg_t) ID: Text widget ID -** (rect_t) zone: Area occupied by the text -** (char *) text: The text -** (int) font: The font the text is to be drawn in -** (gfx_alignment_t) align: Horizontal text alignment to use -** (char) frame: Whether a dithered frame should surround the text -** (char) inverse: Whether the text colors should be inversed -** Returns : (GfxList *) The text control widget list -*/ - -GfxList *sciw_new_edit_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font, unsigned int cursor, - char inverse); -/* Creates a new edit control list -** Parameters: (GfxPort *) port: The port containing the color values to use -** (reg_t) ID: Text widget ID -** (rect_t) zone: Area occupied by the text -** (char *) text: The text -** (int) font: The font the text is to be drawn in -** (int) cursor: Cursor position -** (char) inverse: Whether the edit widget should be reversed -** Returns : (GfxList *) An appropriate widget list -*/ - -GfxList *sciw_new_icon_control(GfxPort *port, reg_t ID, rect_t zone, int view, int loop, int cel, - char frame, char inverse); -/* Creates a new icon control list -** Parameters: (GfxPort *) port: The port containing the color values to use -** (reg_t) ID: Text widget ID -** (rect_t) zone: Area occupied by the text -** (int x int x int) view, loop, cel: The cel to display -** (char) frame: Whether the widget should be surrounded by a frame -** (char) lina inverse: Whether colors should be inversed -** Returns : (GfxList *) An appropriate widget list -*/ - -GfxList *sciw_new_list_control(GfxPort *port, reg_t ID, rect_t zone, int font_nr, char **entries_list, - int entries_nr, int list_top, int selection, char inverse); -/* Creates a new list control list -** Parameters: (GfxPort *) port: The port containing the color values to use -** (int) ID: Text widget ID -** (rect_t) zone: Area occupied by the text -** (int) font_nr: number of the font to use -** (char **) entries_list: List of strings to contain within the list -** (int) entries_nr: Number of entries in entries_list -** (int) list_top: First list item that is visible -** (int) selection: The list item that is selected -** (char) invserse: The usual meaning -** Returns : (GfxList *) An appropriate widget list -*/ - -/*---------------------*/ -/*** Menubar widgets ***/ -/*---------------------*/ - -void sciw_set_menubar(EngineState *s, GfxPort *status_bar, Menubar *menubar, int selection); -/* Draws the menu bar -** Parameters: (EngineState *) s: The state to operate on -** (GfxPort *) status_bar: The status bar port to modify -** (Menubar *) menubar: The menu bar to use -** (int) selection: Number of the menu to hightlight, or -1 for 'none' -** Returns : (void) -*/ - -GfxPort *sciw_new_menu(EngineState *s, GfxPort *status_bar, Menubar *menubar, int selection); -/* Creates a menu port -** Parameters: (EngineState *) s: The state to operate on -** (GfxPort *) status_bar: The status bar -** (Menubar *) menubar: The menu bar to use -** (int) selection: Number of the menu to interpret -** Returns : (GfxPort *) The result port -*/ - -GfxPort *sciw_toggle_item(GfxPort *menu_port, Menu *menu, int selection, bool selected); -/* Toggle the selection of a menu item from a menu port -** Parameters: (GfxPort *) menu_port: The port to modify -** (Menu *) menu: The menu the menu port corresponds to -** (int) selection: Number of the menu entry to unselect, or -1 to do a NOP -** (bool) selected: Whether to set the item's state to selected or not -** Returns : (GfxPort *) The modified menu -*/ +/** + * Sets the contents of a port used as status bar. + * + * @param[in] s The affected EngineState + * @param[in] status_bar The status bar port + * @param[in] text The text to draw + * @param[in] fgcolor The foreground color + * @param[in] bgcolor The background color + */ +void sciw_set_status_bar(EngineState *s, GfxPort *status_bar, + const Common::String &text, int fgcolor, int bgcolor); + +/** + * Creates a new SCI style window. + * + * @param[in] s The affected EngineState + * @param[in] area The screen area to frame (not including a + * potential window title) + * @param[in] font Default font number to use + * @param[in] color The foreground color to use for drawing + * @param[in] bgcolor The background color to use + * @param[in] title_font The font to use for the title bar (if any) + * @param[in] title_color Color to use for the title bar text + * @param[in] title_bg_color Color to use for the title bar background + * @param[in] title The text to write into the title bar + * @param[in] flags Any ORred combination of window flags + * @return A newly allocated port with the requested characteristics + */ +GfxPort *sciw_new_window(EngineState *s, rect_t area, int font, + gfx_color_t color, gfx_color_t bgcolor, int title_font, + gfx_color_t title_color, gfx_color_t title_bg_color, + const char *title, int flags); + + +/** @name Control widgets */ +/** @{ */ +/** + * Creates a new button control list. + * + * @param[in] port The port containing the color values to use for the + * button (the button is /not/ appended to the port + * there) + * @param[in] ID Button's ID + * @param[in] zone The area occupied by the button + * @param[in] text The text to write into the button + * @param[in] font The font to use for the button + * @param[in] selected Whether the button should be marked as being + * selected by the keyboard focus + * @param[in] inverse Whether to inverse the color scheme + * @param[in] gray Whether the button should be grayed out + * @return The button + */ +GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone, + const char *text, int font, char selected, char inverse, char gray); + +/** + * Creates a new text control list. + * + * @param[in] port The port containing the color values to use + * @param[in] ID Text widget ID + * @param[in] zone Area occupied by the text + * @param[in] text The text + * @param[in] font The font the text is to be drawn in + * @param[in] align Horizontal text alignment to use + * @param[in] frame Whether a dithered frame should surround the text + * @param[in] inverse Whether the text colors should be inversed + * @return The text control widget list + */ +GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone, + const char *text, int font, gfx_alignment_t align, char frame, + char inverse); + +/** + * Creates a new edit control list. + * + * @param[in] port The port containing the color values to use + * @param[in] ID Text widget ID + * @param[in] zone Area occupied by the text + * @param[in] text The text + * @param[in] font The font the text is to be drawn in + * @param[in] cursor Cursor position + * @param[in] inverse Whether the edit widget should be reversed + * @return An appropriate widget list + */ +GfxList *sciw_new_edit_control(GfxPort *port, reg_t ID, rect_t zone, + const char *text, int font, unsigned int cursor, char inverse); + +/** + * Creates a new icon control list. + * + * @param[in] port The port containing the color values to use + * @param[in] ID Text widget ID + * @param[in] zone Area occupied by the text + * @param[in] view The view index + * @param[in] loop The loop index + * @param[in] cel The cel to display + * @param[in] frame Whether the widget should be surrounded by a frame + * @param[in] inverse Whether colors should be inversed + * @return An appropriate widget list + */ +GfxList *sciw_new_icon_control(GfxPort *port, reg_t ID, rect_t zone, + int view, int loop, int cel, char frame, char inverse); + +/** + * Creates a new list control list. + * + * @param[in] port: The port containing the color values to use + * @param[in] ID: Text widget ID + * @param[in] zone: Area occupied by the text + * @param[in] font_nr: Number of the font to use + * @param[in] entries_list: List of strings to contain within the list + * @param[in] entries_nr: Number of entries in entries_list + * @param[in] list_top: First list item that is visible + * @param[in] selection: The list item that is selected + * @param[in] inverse: The usual meaning + * @return An appropriate widget list + */ +GfxList *sciw_new_list_control(GfxPort *port, reg_t ID, rect_t zone, + int font_nr, const char **entries_list, int entries_nr, + int list_top, int selection, char inverse); +/** @} */ + +/** @name Menubar widgets */ +/** @{ */ + +/** + * Draws the menu bar. + * + * @param[in] s: The EngineState to operate on + * @param[in] status_bar: The status bar port to modify + * @param[in] menubar: The menu bar to use + * @param[in] selection: Number of the menu to hightlight, or -1 for + * 'none' + */ +void sciw_set_menubar(EngineState *s, GfxPort *status_bar, Menubar *menubar, + int selection); + +/** + * Creates a menu port. + * + * @param[in] s The state to operate on + * @param[in] status_bar The status bar + * @param[in] menubar The menu bar to use + * @param[in] selection Number of the menu to interpret + * @return The result port + */ +GfxPort *sciw_new_menu(EngineState *s, GfxPort *status_bar, + Menubar *menubar, int selection); + +/** + * Toggle the selection of a menu item from a menu port. + * + * @param[in] menu_port The port to modify + * @param[in] menu The menu the menu port corresponds to + * @param[in] selection Number of the menu entry to unselect, or -1 to do + * a NOP + * @param[in] selected Whether to set the item's state to selected or not + * @return The modified menu + */ +GfxPort *sciw_toggle_item(GfxPort *menu_port, Menu *menu, int selection, + bool selected); +/** @} */ } // End of namespace Sci diff --git a/engines/sci/gfx/gfx_options.h b/engines/sci/gfx/gfx_options.h index 393627a1a2..2e2b853562 100644 --- a/engines/sci/gfx/gfx_options.h +++ b/engines/sci/gfx/gfx_options.h @@ -42,20 +42,20 @@ namespace Sci { -/* Dirty rectangle heuristics: */ - -/* One: Redraw one rectangle surrounding the dirty area (insert is O(1)) */ -#define GFXOP_DIRTY_FRAMES_ONE 1 - -/* Clusters: Accumulate dirty rects, merging those that overlap (insert is O(n)) */ -#define GFXOP_DIRTY_FRAMES_CLUSTERS 2 +/** Dirty rectangle heuristics. */ +enum { + GFXOP_DIRTY_FRAMES_ONE = 1, /**< One: Redraw one rectangle surrounding the dirty area (insert is O(1)) */ + GFXOP_DIRTY_FRAMES_CLUSTERS = 2 /**< Clusters: Accumulate dirty rects, merging those that overlap (insert is O(n)) */ +}; +/** + * All user options to the rendering pipeline + * + * See note in sci_conf.h for config_entry_t before changing types of + * variables + */ struct gfx_options_t { #ifdef CUSTOM_GRAPHICS_OPTIONS - /* gfx_options_t: Contains all user options to the rendering pipeline */ - /* See note in sci_conf.h for config_entry_t before changing types of - ** variables */ - int buffer_pics_nr; /* Number of unused pics to buffer */ /* SCI0 pic resource options */ diff --git a/engines/sci/gfx/gfx_res_options.h b/engines/sci/gfx/gfx_res_options.h index f01f93d21b..a595c56606 100644 --- a/engines/sci/gfx/gfx_res_options.h +++ b/engines/sci/gfx/gfx_res_options.h @@ -23,8 +23,6 @@ * */ -/* Configuration options for per-resource customisations */ - #ifndef SCI_GFX_GFX_RES_OPTIONS_H #define SCI_GFX_GFX_RES_OPTIONS_H @@ -35,13 +33,16 @@ #include "sci/gfx/gfx_resmgr.h" namespace Sci { +/** @name Configuration options for per-resource customisations */ +/** @{ */ struct gfx_res_pattern_t { int min, max; }; -/* GFX resource assignments */ - +/** + * GFX resource assignments. + */ struct gfx_res_assign_t { union { struct { @@ -52,23 +53,24 @@ struct gfx_res_assign_t { }; -/* GFX resource modifications */ - +/** + * GFX resource modifications/ + */ struct gfx_res_conf_t { - int type; /* Resource type-- only one allowed */ + int type; /**< Resource type-- only one allowed */ /* If any of the following is 0, it means that there is no restriction. ** Otherwise, one of the patterns associated with them must match. */ - int patterns_nr; /* Number of patterns (only 'view' patterns for views) */ - int loops_nr, cels_nr; /* Number of loop/cel patterns, for views only. + int patterns_nr; /**< Number of patterns (only 'view' patterns for views) */ + int loops_nr, cels_nr; /**< Number of loop/cel patterns, for views only. ** For pics, loops_nr identifies the palette. */ gfx_res_pattern_t *patterns; union { gfx_res_assign_t assign; - byte factor[3]; /* divide by 16 to retrieve factor */ - } conf; /* The actual configuration */ + byte factor[3]; /**< divide by 16 to retrieve factor */ + } conf; /**< The actual configuration */ gfx_res_conf_t *next; }; @@ -84,16 +86,20 @@ struct gfx_res_fullconf_t { struct gfx_options_t; +/** + * Configures a graphical pixmap according to config options. + * + * Modifies pxm as considered appropriate by configuration options. Does + * not do anything in colour index mode. + * + * @param[in] options The options according to which configuration + * should be performed + * @param[in] pxm The pixmap to configure + * @return 0 on success, non-zero otherwise + */ int gfx_get_res_config(gfx_options_t *options, gfx_pixmap_t *pxm); -/* Configures a graphical pixmap according to config options -** Parameters: (gfx_options_t *) options: The options according to which -** configuration should be performed -** (gfx_resource_type_t) pxm: The pixmap to configure -** Returns : (int) 0 on success, non-zero otherwise -** Modifies pxm as considered appropriate by configuration options. Does -** not do anything in colour index mode. -*/ +/** @} */ } // End of namespace Sci #endif diff --git a/engines/sci/gfx/gfx_resmgr.h b/engines/sci/gfx/gfx_resmgr.h index c5878bf529..1f0f58dce9 100644 --- a/engines/sci/gfx/gfx_resmgr.h +++ b/engines/sci/gfx/gfx_resmgr.h @@ -49,7 +49,7 @@ enum gfx_resource_type_t { GFX_RESOURCE_TYPE_PALETTE, /* FIXME: Add PAL resource */ - GFX_RESOURCE_TYPES_NR /* Number of resource types that are to be supported */ + GFX_RESOURCE_TYPES_NR /**< Number of resource types that are to be supported */ }; #define GFX_RESOURCE_TYPE_0 GFX_RESOURCE_TYPE_VIEW @@ -58,12 +58,13 @@ enum gfx_resource_type_t { #define GFXR_RES_TYPE(id) (id >> 16) #define GFXR_RES_NR(id) (id & 0xffff) - +/** Graphics resource */ struct gfx_resource_t { - int ID; /* Resource ID */ - int lock_sequence_nr; /* See description of lock_counter in GfxResManager */ - int mode; /* A mode type hash */ + int ID; /**< Resource ID */ + int lock_sequence_nr; /**< See description of lock_counter in GfxResManager */ + int mode; /**< A mode type hash */ + /** Scaled pic */ union { gfx_pixmap_t *pointer; gfxr_view_t *view; @@ -71,6 +72,7 @@ struct gfx_resource_t { gfxr_pic_t *pic; } scaled_data; + /** Original pic */ union { gfx_pixmap_t *pointer; gfxr_view_t *view; @@ -85,152 +87,204 @@ struct gfx_options_t; typedef Common::HashMap<int, gfx_resource_t *> IntResMap; - +/** Graphics resource manager */ class GfxResManager { public: - GfxResManager(int version, bool isVGA, gfx_options_t *options, GfxDriver *driver, ResourceManager *resManager); + GfxResManager(int version, bool isVGA, gfx_options_t *options, + GfxDriver *driver, ResourceManager *resManager); ~GfxResManager(); - /* Calculates a unique hash value for the specified options/type setup - ** Parameters: (gfx_resource_type_t) type: The type the hash is to be generated for - ** Returns : (int) A hash over the values of the options entries, covering entries iff - ** they are relevant for the specified type - ** Covering more entries than relevant may slow down the system when options are changed, - ** while covering less may result in invalid cached data being used. - ** Only positive values may be returned, as negative values are used internally by the generic - ** resource manager code. - ** Also, only the lower 20 bits are available to the interpreter. - ** (Yes, this isn't really a "hash" in the traditional sense...) - */ + /** + * Calculates a unique hash value for the specified options/type + * setup. + * + * Covering more entries than relevant may slow down the system when + * options are changed, while covering less may result in invalid + * cached data being used. + * Only positive values may be returned, as negative values are used + * internally by the generic resource manager code. + * Also, only the lower 20 bits are available to the interpreter. + * (Yes, this isn't really a "hash" in the traditional sense...) + * + * @param[in] type The type the hash is to be generated for + * @return A hash over the values of the options entries, + * covering entries iff they are relevant for the + * specified type. + */ int getOptionsHash(gfx_resource_type_t type); - /* 'Tags' all resources for deletion - ** Paramters: (void) - ** Returns : (void) - ** Tagged resources are untagged if they are referenced. - */ + /** + * 'Tags' all resources for deletion. + * + * Tagged resources are untagged if they are referenced. + */ void tagResources() { _tagLockCounter++; } - /* Retrieves an SCI0/SCI01 mouse cursor - ** Parameters: (int) num: The cursor number - ** Returns : (gfx_font_t *) The approprate cursor as a pixmap, or NULL on error - */ + /** + * Retrieves an SCI0/SCI01 mouse cursor. + * + * @param[in] num The cursor number + * @return The approprate cursor as a pixmap, or NULL on error + */ gfx_pixmap_t *getCursor(int num); - /* Retrieves the static palette from the interpreter-specific code - ** Parameters: (int *) colors_nr: Number of colors to use - ** (int) nr: The palette to read - ** Returns : (Palette *) static palette - ** if a static palette must be used, NULL otherwise - */ + /** + * Retrieves the static palette from the interpreter-specific code. + * + * @param[in] colors_nr Number of colors to use + * @param[in] num The palette to read + * @return Static palette if a static palette must be + * used, NULL otherwise + */ Palette *getPalette(int *colors_nr, int num = 999); - /* Retrieves a font - ** Parameters: (int) nr: The font number - ** (int) scaled: Whether the font should be font-scaled - ** Returns : (gfx_font_t *) The appropriate font, or NULL on error - */ + /** + * Retrieves a font. + * + * @param[in] num The font number + * @param[in] scaled Whether the font should be font-scaled + * @return The appropriate font, or NULL on error + */ gfx_bitmap_font_t *getFont(int num, bool scaled = false); - /* Retrieves a translated view cel - ** Parameters: - ** (int) nr: The view number - ** (int *) loop: Pointer to a variable containing the loop number - ** (int *) cel: Pointer to a variable containing the cel number - ** (int) palette: The palette to use - ** Returns : (gfx_view_t *) The relevant view, or NULL if nr was invalid - ** loop and cel are given as pointers in order to allow the underlying variables to be - ** modified if they are invalid (this is relevant for SCI version 0, where invalid - ** loop and cel numbers have to be interpreted as 'maximum' or 'minimum' by the interpreter) - */ + /** + * Retrieves a translated view cel. + * + * @param[in] nr The view number + * @param[in] loop Pointer to a variable containing the loop number + * @param[in] cel Pointer to a variable containing the cel number + * @param[in] palette The palette to use + * @return The relevant view, or NULL if nr was invalid + * loop and cel are given as pointers in order to + * allow the underlying variables to be modified + * if they are invalid (this is relevant for SCI + * version 0, where invalid loop and cel numbers + * have to be interpreted as 'maximum' or 'minimum' + * by the interpreter) + */ gfxr_view_t *getView(int nr, int *loop, int *cel, int palette); - /* Retrieves a displayable (translated) pic resource - ** Parameters: (int) nr: Number of the pic resource - ** (int) maps: The maps to translate (ORred GFX_MASK_*) - ** (int) flags: Interpreter-dependant pic flags - ** (int) default_palette: The default palette to use for drawing (if applicable) - ** (bool) scaled: Whether to return the scaled maps, or the unscaled - ** ones (which may be identical) for some special operations. - ** Returns : (gfxr_pic_t *) The appropriate pic resource with all maps as index (but not - ** neccessarily translated) data. - */ - gfxr_pic_t *getPic(int num, int maps, int flags, int default_palette, bool scaled = false); - - - /* Retrieves a displayable (translated) pic resource written ontop of an existing pic - ** Parameters: (int) old_nr: Number of the pic resource to write on - ** (int) new_nr: Number of the pic resource that is to be added - ** (int) flags: Interpreter-dependant pic flags - ** (int) default_palette: The default palette to use for drawing (if applicable) - ** (int) scaled: Whether to return the scaled maps, or the unscaled - ** ones (which may be identical) for some special operations. - ** Returns : (gfxr_pic_t *) The appropriate pic resource with all maps as index (but not - ** neccessarily translated) data. - ** This function invalidates the cached pic pointed to by old_nr in the cache. While subsequent - ** addToPic() writes will still modify the 'invalidated' pic, gfxr_get_pic() operations will - ** cause it to be removed from the cache and to be replaced by a clean version. - */ - gfxr_pic_t *addToPic(int old_nr, int new_nr, int flags, int old_default_palette, int default_palette); - - /* Calculate a picture - ** Parameters: (gfxr_pic_t *) scaled_pic: The pic structure that is to be written to - ** (gfxr_pic_t *) unscaled_pic: The pic structure the unscaled pic is to be written to, - ** or NULL if it isn't needed. - ** (int) flags: Pic drawing flags (interpreter dependant) - ** (int) default_palette: The default palette to use for pic drawing (interpreter dependant) - ** (int) nr: pic resource number - ** Returns : (int) GFX_ERROR if the resource could not be found, GFX_OK otherwise - */ - int calculatePic(gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic, int flags, int default_palette, int nr); - - /* Determines whether support for pointers with more than two colors is required - ** Returns : (bool) false if no support for multi-colored pointers is required, true - ** otherwise - */ + /** + * Retrieves a displayable (translated) pic resource. + * + * @param[in] num Number of the pic resource + * @param[in] maps The maps to translate (ORred GFX_MASK_*) + * @param[in] flags Interpreter-dependant pic flags + * @param[in] default_palette The default palette to use for drawing + * (if applicable) + * @param[in] scaled Whether to return the scaled maps, or + * the unscaled ones (which may be + * identical) for some special operations. + * @return The appropriate pic resource with all + * maps as index (but not neccessarily + * translated) data. + */ + gfxr_pic_t *getPic(int num, int maps, int flags, int default_palette, + bool scaled = false); + + + /** + * Retrieves a displayable (translated) pic resource written ontop of + * an existing pic. + * + * This function invalidates the cached pic pointed to by old_nr in the + * cache. While subsequent addToPic() writes will still modify the + * 'invalidated' pic, gfxr_get_pic() operations will cause it to be + * removed from the cache and to be replaced by a clean version. + * + * @param[in] old_nr Number of the pic resource to write on + * @param[in] new_nr Number of the pic resource that is to + * be added + * @param[in] flags Interpreter-dependant pic flags + * @param[in] old_default_palette The default palette of the pic before + * translation + * @param[in] default_palette The default palette to use for drawing + * (if applicable) + * @return The appropriate pic resource with all + * maps as index (but not neccessarily + * translated) data. + */ + gfxr_pic_t *addToPic(int old_nr, int new_nr, int flags, + int old_default_palette, int default_palette); + + /** + * Calculate a picture + * + * @param[in] scaled_pic The pic structure that is to be + * written to + * @param[in] unscaled_pic The pic structure the unscaled pic is + * to be written to, or NULL if it isn't + * needed. + * @param[in] flags Pic drawing flags (interpreter + * dependant) + * @param[in] default_palette The default palette to use for pic + * drawing (interpreter dependant) + * @param[in] nr pic resource number + * @return GFX_ERROR if the resource could not be + * found, GFX_OK otherwise + */ + int calculatePic(gfxr_pic_t *scaled_pic, gfxr_pic_t *unscaled_pic, + int flags, int default_palette, int nr); + + /** + * Determines whether support for pointers with more than two colors + * is required. + * + * @return false if no support for multi-colored pointers is required, + * true otherwise + */ bool multicoloredPointers() { return _version > SCI_VERSION_1; } - /* Frees all resources currently allocated - ** Parameter: (void) - ** Returns : (void) - ** This function is intended to be used primarily for debugging. - */ + /** + * Frees all resources currently allocated. + * + * This function is intended to be used primarily for debugging. + */ void freeAllResources(); - /* Frees all tagged resources. - ** Parameters: (void) - ** Returns : (void) - ** Resources are tagged by calling gfx_tag_resources(), and untagged by calling the - ** approprate dereferenciation function. - ** Note that this function currently only affects view resources, as pic resources are - ** treated differently, while font and cursor resources are relatively rare. - */ + /** + * Frees all tagged resources. + * + * Resources are tagged by calling gfx_tag_resources(), and untagged by + * calling the approprate dereferenciation function. + * Note that this function currently only affects view resources, as + * pic resources are treated differently, while font and cursor + * resources are relatively rare. + */ void freeTaggedResources(); - /* Frees a previously allocated resource manager, and all allocated resources. - ** Parameters: (void) - ** Return : (void) - */ + /** + * Frees a previously allocated resource manager, and all allocated + * resources. + */ void freeResManager(); - const PaletteEntry &getColor(int color) { return _staticPalette->getColor(color); } + /** + * Retrieves a color from the static palette + */ + const PaletteEntry &getColor(int color) + { + return _staticPalette->getColor(color); + } - // Set static palette and merge it into the global palette + /** + * Set static palette and merge it into the global palette + */ void setStaticPalette(Palette *newPalette); - /* - ** Sets the picture port bounds - */ + /** + * Sets the picture port bounds + */ void changePortBounds(int x1, int y1, int x2, int y2) { _portBounds = Common::Rect(x1, y1, x2, y2); } @@ -252,7 +306,15 @@ public: } #endif - int getColorCount() { return _staticPalette ? _staticPalette->size() : 0; } + /** + * Gets the number of colors in the static palette. + * + * @return Number of pallete entries + */ + int getColorCount() + { + return _staticPalette ? _staticPalette->size() : 0; + } private: int _version; @@ -260,11 +322,11 @@ private: gfx_options_t *_options; GfxDriver *_driver; Palette *_staticPalette; - int _lockCounter; /* Global lock counter; increased for each new resource allocated. - ** The newly allocated resource will then be assigned the new value - ** of the lock_counter, as will any resources referenced afterwards. - */ - int _tagLockCounter; /* lock counter value at tag time */ + int _lockCounter; /**< Global lock counter; increased for each new + * resource allocated. The newly allocated resource will + * then be assigned the new value of the lock_counter, + * as will any resources referenced afterwards. */ + int _tagLockCounter; /**< lock counter value at tag time */ Common::Rect _portBounds; IntResMap _resourceMaps[GFX_RESOURCE_TYPES_NR]; diff --git a/engines/sci/gfx/gfx_resource.h b/engines/sci/gfx/gfx_resource.h index 8ce4a8ea83..780060bc4f 100644 --- a/engines/sci/gfx/gfx_resource.h +++ b/engines/sci/gfx/gfx_resource.h @@ -23,7 +23,9 @@ * */ -/* SCI Resource library */ +/** @file gfx_resource.h + * SCI Resource library. + */ #ifndef SCI_GFX_GFX_RESOURCE_H #define SCI_GFX_GFX_RESOURCE_H @@ -44,6 +46,7 @@ namespace Sci { #define GFXR_DITHER_MODE_D16 0 /* Sierra SCI style */ #define GFXR_DITHER_MODE_F256 1 /* Flat color interpolation */ #define GFXR_DITHER_MODE_D256 2 /* 256 color dithering */ + /* Dithering patterns */ #define GFXR_DITHER_PATTERN_SCALED 0 /* Dither per pixel on the 320x200 grid */ #define GFXR_DITHER_PATTERN_1 1 /* Dither per pixel on the target */ @@ -64,52 +67,53 @@ namespace Sci { extern int sci0_palette; -/* (gfx_pic_0.c) The 16 EGA base colors */ +/** The 16 EGA base colors */ extern Palette* gfx_sci0_image_pal[]; extern gfx_pixmap_color_t gfx_sci0_image_colors[][16]; -/* (gfx_pic_0.c) The 256 interpolated colors (initialized when -** gfxr_init_pic() is called for the first time, or when gfxr_init_static_palette() is called) -*/ +/** + * The 256 interpolated colors (initialized when gfxr_init_pic() is called + * for the first time, or when gfxr_init_static_palette() is called) + */ extern Palette* gfx_sci0_pic_colors; - struct gfxr_pic0_params_t { gfx_line_mode_t line_mode; /* one of GFX_LINE_MODE_* */ gfx_brush_mode_t brush_mode; }; +/** A SCI resource pic */ struct gfxr_pic_t { - int ID; /* pic number (NOT resource ID, just number) */ + int ID; /**< pic number (NOT resource ID, just number) */ gfx_mode_t *mode; - gfx_pixmap_t *visual_map; - gfx_pixmap_t *priority_map; - gfx_pixmap_t *control_map; - + gfx_pixmap_t *visual_map; /**< Visual part of pic */ + gfx_pixmap_t *priority_map; /**< Priority map for pic */ + gfx_pixmap_t *control_map; /**< Control map for pic */ + + /** + * Auxiliary map. + * Bit 0: Vis + * Bit 1: Pri + * Bit 2: Ctrl + * Bit 3-5: 'filled' (all three bits are set to 1) + */ byte aux_map[GFXR_AUX_MAP_SIZE]; - /* Auxiliary map details: - ** Bit 0: Vis - ** Bit 1: Pri - ** Bit 2: Ctrl - ** Bit 3-5: 'filled' (all three bits are set to 1) - */ - // rect_t bounds; // unused - void *undithered_buffer; /* copies visual_map->index_data before dithering */ + void *undithered_buffer; /**< copies visual_map->index_data before dithering */ int undithered_buffer_size; int *priorityTable; }; - +/** A animation loop */ struct gfxr_loop_t { - int cels_nr; - gfx_pixmap_t **cels; + int cels_nr; /**< Number of 'cels' or frames in the animation */ + gfx_pixmap_t **cels; /**< Pointer to the pixmaps for the cels */ }; - +/** A graphics view */ struct gfxr_view_t { int ID; @@ -122,172 +126,197 @@ struct gfxr_view_t { int translation[GFX_SCI0_IMAGE_COLORS_NR]; }; +/** + * Initializes the static 256 color palette. + */ void gfxr_init_static_palette(); -/* Initializes the static 256 color palette -** Parameters: (void) -** Returns : (void) -*/ - -gfxr_pic_t *gfxr_init_pic(gfx_mode_t *mode, int ID, int sci1); -/* Initializes a gfxr_pic_t for a specific mode -** Parameters: (gfx_mode_t *) mode: The specific graphics mode -** (int) ID: The ID to assign to the resulting pixmaps -** Returns : (gfxr_pic_t *) The allocated pic resource, or NULL on error. -** This function allocates memory for use by resource drawer functions. -*/ -void gfxr_free_pic(gfxr_pic_t *pic); -/* Uninitializes a pic resource -** Parameters: (gfxr_pic_t *) pic: The pic to free -** Returns : (void) -*/ - -void gfxr_free_view(gfxr_view_t *view); -/* Frees all memory associated with a view -** Paremeters: (gfxr_view_t *) view: The view to free -** Returns : (void) -*/ +/** @name Resource picture management functions */ +/** @{ */ +/** + * Initializes a gfxr_pic_t for a specific mode. + * + * This function allocates memory for use by resource drawer functions. + * + * @param[in] mode The specific graphics mode + * @param[in] ID The ID to assign to the resulting pixmaps + * @param[in] sci1 true if a SCI1 pic, false otherwise + * @return The allocated pic resource, or NULL on error. + */ +gfxr_pic_t *gfxr_init_pic(gfx_mode_t *mode, int ID, bool sci1); +/** + * Uninitializes a pic resource. + * + * @param[in] pic The pic to free + */ +void gfxr_free_pic(gfxr_pic_t *pic); +/** + * Frees all memory associated with a view. + * + * @param[in] view The view to free + */ +void gfxr_free_view(gfxr_view_t *view); +/** @} */ +/** @name SCI0 resource picture operations */ +/** @{ */ -/*********************/ -/* SCI0 operations */ -/*********************/ +/** + * Clears all pic buffers of one pic/ + * + * This function should be called before gfxr_draw_pic0, unless cumulative + * drawing is intended + * + * @param[in] pic The picture to clear + * @param[in] titlebar_size How much space to reserve for the title bar + */ +void gfxr_clear_pic0(gfxr_pic_t *pic, int titlebar_size); +/** + * Draws a pic resource (all formats prior to SCI1.1). + * + * The result is stored in gfxr_visual_map, gfxr_priority_map, and + * gfxr_control_map. The palette entry of gfxr_visual_map is never used. + * Note that the picture will not be drawn dithered; use gfxr_dither_pic0 + * for that. + * + * @param[in] pic The pic to draw to + * @param[in] fill_normally If 1, the pic is drawn normally; if 0, all + * fill operations will fill with black + * @param[in] default_palette The default palette to use for drawing + * @param[in] size Resource size + * @param[in] resource Pointer to the resource data + * @param[in] style The drawing style + * @param[in] resid The resource ID + * @param[in] sci1 true if SCI1, false otherwise + * @param[in] static_pal The static palette + * @param[in] portBounds The bounds of the port being drawn to + */ +void gfxr_draw_pic01(gfxr_pic_t *pic, int fill_normally, + int default_palette, int size, byte *resource, + gfxr_pic0_params_t *style, int resid, int sci1, + Palette *static_pal, Common::Rect portBounds); -void gfxr_clear_pic0(gfxr_pic_t *pic, int titlebar_size); -/* Clears all pic buffers of one pic -** Parameters: (gfxr_pic_t) pic: The picture to clear -** (int) titlebar_size: How much space to reserve for the title bar -** Returns : (void) -** This function should be called before gfxr_draw_pic0, unless cumulative -** drawing is intended -*/ - - -void gfxr_draw_pic01(gfxr_pic_t *pic, int fill_normally, int default_palette, - int size, byte *resource, gfxr_pic0_params_t *style, int resid, int sci1, - Palette *static_pal, Common::Rect portBounds); -/* Draws a pic resource (all formats prior to SCI1.1) -** Parameters: (gfxr_pic_t *) pic: The pic to draw to -** (int) fill_normally: If 1, the pic is drawn normally; if 0, all -** fill operations will fill with black -** (int) default_palette: The default palette to use for drawing -** (int) size: Resource size -** (byte *) resource: Pointer to the resource data -** (gfxr_pic0_params_t *) style: The drawing style -** (int) resid: The resource ID -** (int) sci1: Nonzero if SCI1 -** (Palette *) static_pal: The static palette -** (int) static_pal_nr: Number of entries in static palette -** Returns : (void) -** The result is stored in gfxr_visual_map, gfxr_priority_map, and gfxr_control_map. -** The palette entry of gfxr_visual_map is never used. -** Note that the picture will not be drawn dithered; use gfxr_dither_pic0 for that. -*/ - -void gfxr_draw_pic11(gfxr_pic_t *pic, int fill_normally, int default_palette, - int size, byte *resource, gfxr_pic0_params_t *style, int resid, - Palette *static_pal, Common::Rect portBounds); -/* Draws a pic resource (SCI1.1) -** Parameters: (gfxr_pic_t *) pic: The pic to draw to -** (int) fill_normally: If 1, the pic is drawn normally; if 0, all -** fill operations will fill with black -** (int) default_palette: The default palette to use for drawing -** (int) size: Resource size -** (byte *) resource: Pointer to the resource data -** (gfxr_pic0_params_t *) style: The drawing style -** (int) resid: The resource ID -** (Palette *) static_pal: The static palette -** (int) static_pal_nr: Number of entries in static palette -** Returns : (void) -** The result is stored in gfxr_visual_map, gfxr_priority_map, and gfxr_control_map. -** The palette entry of gfxr_visual_map is never used. -** Note that the picture will not be drawn dithered; use gfxr_dither_pic0 for that. -*/ +/** + * Draws a pic resource (SCI1.1). + * + * The result is stored in gfxr_visual_map, gfxr_priority_map, and + * gfxr_control_map. The palette entry of gfxr_visual_map is never used. + * Note that the picture will not be drawn dithered; use gfxr_dither_pic11 + * for that. + * + * @param[in] pic The pic to draw to + * @param[in] fill_normally If 1, the pic is drawn normally; if 0, all + * fill operations will fill with black + * @param[in] default_palette The default palette to use for drawing + * @param[in] size Resource size + * @param[in] resource Pointer to the resource data + * @param[in] style The drawing style + * @param[in] resid The resource ID + * @param[in] static_pal The static palette + * @param[in] portBounds Bounds of the port being drawn to + */ +void gfxr_draw_pic11(gfxr_pic_t *pic, int fill_normally, + int default_palette, int size, byte *resource, + gfxr_pic0_params_t *style, int resid, Palette *static_pal, + Common::Rect portBounds); +/** + * Removes artifacts from a scaled pic. + * + * Using information from the (correctly rendered) src pic, this function + * implements some heuristics to remove artifacts from dest. Must be used + * before dither_pic0 is called, because it operates on the index buffer. + * + * @param[in] dest The scaled pic + * @param[in] src An unscaled pic + */ void gfxr_remove_artifacts_pic0(gfxr_pic_t *dest, gfxr_pic_t *src); -/* Removes artifacts from a scaled pic -** Parameters: (gfxr_pic_t *) dest: The scaled pic -** (gfxr_pic_t *) src: An unscaled pic -** Returns : (void) -** Using information from the (correctly rendered) src pic, this function implements -** some heuristics to remove artifacts from dest. Must be used before dither_pic0 is -** called, because it operates on the index buffer. -*/ +/** + * Dithers a gfxr_visual_map. + * + * @param[in] pic The pic to dither + * @param[in] mode One of GFXR_DITHER_MODE + * @param[in] pattern One of GFXR_DITHER_PATTERN + */ void gfxr_dither_pic0(gfxr_pic_t *pic, int mode, int pattern); -/* Dithers a gfxr_visual_map -** Parameters: (gfxr_pic_t *) pic: The pic to dither -** (int) mode: One of GFXR_DITHER_MODE -** (int) pattern: One of GFXR_DITHER_PATTERN -** Returns : (void) -*/ +/** + * Calculates a SCI0 view. + * + * @param[in] id Resource ID of the view + * @param[in] resource Pointer to the resource to read + * @param[in] size Size of the resource + * @param[in] palette The palette to use + * @return The resulting view + */ gfxr_view_t *gfxr_draw_view0(int id, byte *resource, int size, int palette); -/* Calculates an SCI0 view -** Parameters: (int) id: Resource ID of the view -** (byte *) resource: Pointer to the resource to read -** (int) size: Size of the resource -** (int) palette: The palette to use -** Returns : (gfxr_view_t *) The resulting view -*/ - -gfx_pixmap_t *gfxr_draw_cursor(int id, byte *resource, int size, bool isSci01); -/* Calculates n SCI cursor -** Parameters: (int) id: The cursor's resource ID -** (byte *) resource: Pointer to the resource data -** (int) size: Resource size -** (bool) isSci01: Set to true to load a SCI1 cursor -** Returns : (gfx_pixmap_t *) A newly allocated pixmap containing an index -** color representation of the cursor -*/ - -/*********************/ -/* SCI1 operations */ -/*********************/ +/** + * Calculates a SCI cursor. + * + * @param[in] id The cursor's resource ID + * @param[in] resource Pointer to the resource data + * @param[in] size Resource size + * @param[in] isSci01 Set to true to load a SCI1 cursor + * @return A newly allocated pixmap containing an index color + * representation of the cursor + */ +gfx_pixmap_t *gfxr_draw_cursor(int id, byte *resource, int size, + bool isSci01); +/** @} */ + + +/** @name SCI1/1.1 resource picture operations */ +/** @{ */ + +/** + * Reads an SCI1 palette. + * + * @param[in] id Resource ID for the palette (or the view it was + * found in) + * @param[in] resource Source data + * @param[in] size Size of the memory block pointed to by resource + * @return Palette with the colors + */ Palette *gfxr_read_pal1(int id, byte *resource, int size); -/* Reads an SCI1 palette -** Parameters: (int) id: Resource ID for the palette (or the view it was found in) -** (int *) colors_nr: Pointer to the variable the number of colors -** will be stored in -** (byte *) resource: Source data -** (int) size: Size of the memory block pointed to by resource -** Returns : (Palette *) *colors_nr Palette with the colors -*/ +/** + * Reads an SCI1 palette. + * + * @param[in] file Palette file + * @return Palette with the colors + */ Palette *gfxr_read_pal1_amiga(Common::File &file); -/* Reads an SCI1 palette -** Parameters: (int *) colors_nr: Pointer to the variable the number of colors -** will be stored in -** (FILE *) f: Palette file -** Returns : (Palette *) Palette with the colors -*/ +/** + * Reads an SCI1.1 palette. + * + * @param[in] id Resource ID for the palette (or the view it was + * found in) + * @param[in] resource Source data + * @param[in] size Size of the memory block pointed to by resource + * @return Palette with the colors + */ Palette *gfxr_read_pal11(int id, byte *resource, int size); -/* Reads an SCI1.1 palette -** Parameters: (int) id: Resource ID for the palette (or the view it was found in) -** (int *) colors_nr: Pointer to the variable the number of colors -** will be stored in -** (byte *) resource: Source data -** (int) size: Size of the memory block pointed to by resource -** Returns : (Palette *) Palette with the colors -*/ +/** + * Calculates an SCI1 view. + * + * @param[in] id Resource ID of the view + * @param[in] resource Pointer to the resource to read + * @param[in] size Size of the resource + * @param[in] static_pal The static palette + * @param[in] isSci11 true if SCI1.1, false otherwise + * @return The resulting view + */ gfxr_view_t *gfxr_draw_view1(int id, byte *resource, int size, Palette *static_pal, bool isSci11); -/* Calculates an SCI1 view -** Parameters: (int) id: Resource ID of the view -** (byte *) resource: Pointer to the resource to read -** (int) size: Size of the resource -** (Palette *) static_pal: The static palette -** (int) static_pal_nr: Number of entries in static palette -** Returns : (gfxr_view_t *) The resulting view -*/ gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *resource, byte *cel_base, int size, gfxr_view_t *view, bool isAmiga, bool isSci11); - +/** @} */ } // End of namespace Sci diff --git a/engines/sci/gfx/gfx_state_internal.h b/engines/sci/gfx/gfx_state_internal.h index d03c5e9519..3f00b5213c 100644 --- a/engines/sci/gfx/gfx_state_internal.h +++ b/engines/sci/gfx/gfx_state_internal.h @@ -34,14 +34,16 @@ namespace Sci { -#define GFXW_FLAG_VISIBLE (1<<0) -#define GFXW_FLAG_OPAQUE (1<<1) -#define GFXW_FLAG_CONTAINER (1<<2) -#define GFXW_FLAG_DIRTY (1<<3) -#define GFXW_FLAG_TAGGED (1<<4) -#define GFXW_FLAG_MULTI_ID (1<<5) /**< Means that the ID used herein may be used more than once, i.e. is not unique */ -#define GFXW_FLAG_IMMUNE_TO_SNAPSHOTS (1<<6) /**< Snapshot restoring doesn't kill this widget, and +5 bonus to saving throws vs. Death Magic */ -#define GFXW_FLAG_NO_IMPLICIT_SWITCH (1<<7) /**< Ports: Don't implicitly switch to this port when disposing windows */ +enum gfxw_flag_t { + GFXW_FLAG_VISIBLE = (1<<0), + GFXW_FLAG_OPAQUE = (1<<1), + GFXW_FLAG_CONTAINER = (1<<2), + GFXW_FLAG_DIRTY = (1<<3), + GFXW_FLAG_TAGGED = (1<<4), + GFXW_FLAG_MULTI_ID = (1<<5), /**< Means that the ID used herein may be used more than once, i.e. is not unique */ + GFXW_FLAG_IMMUNE_TO_SNAPSHOTS = (1<<6), /**< Snapshot restoring doesn't kill this widget, and +5 bonus to saving throws vs. Death Magic */ + GFXW_FLAG_NO_IMPLICIT_SWITCH = (1<<7) /**< Ports: Don't implicitly switch to this port when disposing windows */ +}; struct gfxw_snapshot_t { int serial; /**< The first serial number to kill */ @@ -82,6 +84,7 @@ struct GfxPort; typedef int gfxw_bin_op(GfxWidget *, GfxWidget *); +/** SCI graphics widget */ struct GfxWidget { public: int _magic; /**< Extra check after typecasting */ @@ -101,27 +104,28 @@ public: /** * The widget automatically removes itself from its owner, if it has one. - * Deleting a container will recursively free all of its - * contents. + * Deleting a container will recursively free all of its contents. */ virtual ~GfxWidget(); /** * Draws the widget. * - * The widget is drawn iff it is flagged as dirty. Invoking this operation on - * a container widget will recursively draw all of its contents. + * The widget is drawn iff it is flagged as dirty. Invoking this operation + * on a container widget will recursively draw all of its contents. * - * @param pos The position to draw to (added to the widget's internal position) + * @param[in] pos The position to draw to (added to the widget's + * internal position) */ virtual int draw(const Common::Point &pos) = 0; /** * Tags the specified widget. * - * If invoked on a container widget, this will also tag all of the container's - * contents (but not the contents' contents!) - * FIXME: Actually, the code in GfxContainer::tag contradicts the last claim! + * If invoked on a container widget, this will also tag all of the + * container's contents (but not the contents' contents!) + * FIXME: Actually, the code in GfxContainer::tag contradicts the last + * claim! */ virtual void tag() { _flags |= GFXW_FLAG_TAGGED; @@ -130,10 +134,10 @@ public: /** * Prints a string representation of the widget with sciprintf. * - * Will recursively print all of the widget's contents if the widget contains - * further sub-widgets + * Will recursively print all of the widget's contents if the widget + * contains further sub-widgets * - * @param indentation Number of double spaces to indent + * @param[in] indentation Number of double spaces to indent */ virtual void print(int indentation) const; @@ -143,55 +147,63 @@ public: * This comparison only applies to some widgets; compare_to(a,a)=0 is not * guaranteed. It may be used for sorting for all widgets. * - * @param other other widget - * @return <0, 0, or >0 if other is, respectively, less than, equal - * to, or greater than self + * @param other The other widget + * @return <0, 0, or >0 if other is, respectively, less than, equal + * to, or greater than self */ gfxw_bin_op *compare_to; /** * Compares two compareable widgets for equality. * - * This operation checks whether two widgets describe the same graphical data. - * It is used to determine whether a new widget should be discarded because it - * describes the same graphical data as an old widget that has already been - * drawn. For lists, it also checks whether all contents are in an identical - * order. + * This operation checks whether two widgets describe the same graphical + * data. It is used to determine whether a new widget should be discarded + * because it describes the same graphical data as an old widget that has + * already been drawn. For lists, it also checks whether all contents are + * in an identical order. * - * @param other other widget - * @return false if the widgets are not equal, true if they match + * @param[in] other The other widget + * @return false if the widgets are not equal, true if they match */ gfxw_bin_op *equals; /** - * Determine whether other should replace this even though they are equivalent. + * Determine whether other should replace this even though they are + * equivalent. * * When 'equals' returns true, this means that no new widget will be added. * However, in some cases newer widgets may contain information that should - * cause the older widget to be removed nonetheless; this is indicated by this - * function. + * cause the older widget to be removed nonetheless; this is indicated by + * this function. * - * @param other other widget - * @return false if this should be kept, true if this should be replaced by the 'other' + * @param[in] other The other widget + * @return false if this should be kept, true if this should be + * replaced by the 'other' */ gfxw_bin_op *should_replace; /** - * Tests whether drawing this after other would reduce all traces of other. + * Tests whether drawing this after other would reduce all traces of + * other. * - * /a superarea_of b <=> for each pixel of b there exists an opaque pixel in a at the same location + * /a superarea_of b <=> for each pixel of b there exists an opaque pixel + * in a at the same location * - * @param other the widget to compare for containment - * @return true if this is superarea_of other, false otherwise + * @param[in] other The widget to compare for containment + * @return true if this is superarea_of other, false otherwise */ gfxw_bin_op *superarea_of; /** * Sets the visual for the widget - * This function is called by container->add() and need not be invoked explicitly. - * It also makes sure that dirty rectangles are passed to parent containers. + * + * This function is called by container->add() and need not be invoked + * explicitly. It also makes sure that dirty rectangles are passed to + * parent containers. + * + * @param[in] visual GfxVisual to set for the widget */ - virtual int setVisual(GfxVisual *); + virtual int setVisual(GfxVisual *visual); //protected: void printIntern(int indentation) const; @@ -200,6 +212,7 @@ public: #define GFXW_IS_BOX(widget) ((widget)->_type == GFXW_BOX) +/** SCI box widget */ struct GfxBox : public GfxWidget { gfx_color_t _color1, _color2; gfx_box_shade_t _shadeType; @@ -213,6 +226,7 @@ public: #define GFXW_IS_PRIMITIVE(widget) ((widget)->_type == GFXW_RECT || (widget)->_type == GFXW_LINE) +/** SCI graphics primitive */ struct GfxPrimitive : public GfxWidget { gfx_color_t _color; gfx_line_mode_t _lineMode; @@ -227,6 +241,7 @@ public: #define GFXW_IS_VIEW(widget) ((widget)->_type == GFXW_VIEW || (widget)->_type == GFXW_STATIC_VIEW \ || (widget)->_type == GFXW_DYN_VIEW || (widget)->_type == GFXW_PIC_VIEW) +/** SCI graphics view */ struct GfxView : public GfxWidget { Common::Point _pos; /**< Implies the value of 'bounds' in GfxWidget */ gfx_color_t _color; @@ -242,6 +257,7 @@ public: }; #define GFXW_IS_DYN_VIEW(widget) ((widget)->_type == GFXW_DYN_VIEW || (widget)->_type == GFXW_PIC_VIEW) +/** SCI dynamic view */ struct GfxDynView : public GfxView { /* FIXME: This code is specific to SCI */ rect_t draw_bounds; /* The correct position to draw to */ @@ -265,6 +281,7 @@ public: #define GFXW_IS_TEXT(widget) ((widget)->_type == GFXW_TEXT) +/** SCI text widget */ struct GfxText : public GfxWidget { int _font; int lines_nr, lineheight, lastline_width; @@ -293,7 +310,7 @@ typedef int gfxw_unary_container_op(GfxContainer *); typedef int gfxw_container_op(GfxContainer *, GfxWidget *); typedef int gfxw_rect_op(GfxContainer *, rect_t, int); - +/** SCI container widget */ struct GfxContainer : public GfxWidget { rect_t zone; /**< The writeable zone (absolute) for contained objects */ DirtyRectList _dirtyRects; /**< List of dirty rectangles */ @@ -324,7 +341,7 @@ public: #define GFXW_IS_LIST(widget) ((widget)->_type == GFXW_LIST || (widget)->_type == GFXW_SORTED_LIST) #define GFXW_IS_SORTED_LIST(widget) ((widget)->_type == GFXW_SORTED_LIST) - +/** SCI graphics list */ struct GfxList : public GfxContainer { public: GfxList(rect_t area, bool sorted); @@ -334,6 +351,7 @@ public: }; #define GFXW_IS_VISUAL(widget) ((widget)->_type == GFXW_VISUAL) +/** SCI graphic visual */ struct GfxVisual : public GfxContainer { Common::Array<GfxPort *> _portRefs; /**< References to ports */ int _font; /**< Default font */ @@ -353,6 +371,7 @@ public: }; #define GFXW_IS_PORT(widget) ((widget)->_type == GFXW_PORT) +/** SCI graphics port */ struct GfxPort : public GfxContainer { GfxList *_decorations; /**< optional window decorations - drawn before the contents */ GfxWidget *port_bg; /**< Port background widget or NULL */ @@ -366,16 +385,20 @@ struct GfxPort : public GfxContainer { byte gray_text; /**< Whether text is 'grayed out' (dithered) */ public: - /* Creates a new port widget with the default settings - ** Paramaters: (GfxVisual *) visual: The visual the port is added to - ** (GfxPort *) predecessor: The port's predecessor - ** (rect_t) area: The screen area covered by the port (absolute position) - ** (gfx_color_t) fgcolor: Foreground drawing color - ** (gfx_color_t) bgcolor: Background color - ** A port differentiates itself from a list in that it contains additional information, - ** and an optional title (stored in a display list). - ** Ports are assigned implicit IDs identifying their position within the port stack. - */ + /** + * Creates a new port widget with the default settings + * + * A port differentiates itself from a list in that it contains additional + * information, and an optional title (stored in a display list). + * Ports are assigned implicit IDs identifying their position within the + * port stack. + * + * @param[in] visual The visual the port is added to + * @param[in] area The screen area covered by the port (absolute + * position) + * @param[in] fgcolor Foreground drawing color + * @param[in] bgcolor Background color + */ GfxPort(GfxVisual *visual, rect_t area, gfx_color_t fgcolor, gfx_color_t bgcolor); ~GfxPort(); diff --git a/engines/sci/gfx/gfx_system.h b/engines/sci/gfx/gfx_system.h index 3922b21db2..6b7724a6bd 100644 --- a/engines/sci/gfx/gfx_system.h +++ b/engines/sci/gfx/gfx_system.h @@ -36,7 +36,7 @@ namespace Sci { #define GFX_DEBUG /* General output macros */ -# define GFXERROR sciprintf("GFX Error: %s, L%d:", __FILE__, __LINE__); error +#define GFXERROR sciprintf("GFX Error: %s, L%d:", __FILE__, __LINE__); error /***********************/ /*** Data structures ***/ @@ -50,32 +50,35 @@ namespace Sci { ** enabled */ #define GFX_MODE_FLAG_REVERSE_ALPHA (1<<1) -/** Graphics mode description */ -struct gfx_mode_t { +/** Graphics mode description + * + * Color masks: + * Each of the mask/shift pairs describe where the corresponding color + * values are stored for the described mode. Internally, color + * calculations are done by using 32 bit values for r, g, b, a. After + * the internal values have been calculated, they are shifted RIGHT + * by the xxx_shift amount described above, then ANDed with the + * corresponding color mask; finally, all three results are ORred to- + * gether. The alpha values are used as appropriate; if alpha_mask is + * zero, then images use a special alpha map. + */ - int xfact, yfact; /* Horizontal and vertical scaling factors */ - int xsize, ysize; /* Horizontal and vertical size */ - int bytespp; /* Bytes per pixel */ +struct gfx_mode_t { - uint32 flags; /* GFX_MODE_FLAG_* Flags- see above */ + int xfact, yfact; /**< Horizontal and vertical scaling factors */ + int xsize, ysize; /**< Horizontal and vertical size */ + int bytespp; /**< Bytes per pixel */ + uint32 flags; /**< GFX_MODE_FLAG_* Flags- see above */ - Palette *palette; // Palette or NULL to indicate non-palette mode. - // Palette mode is only supported for bytespp = 1 + /** + * Palette or NULL to indicate non-palette mode. + * Palette mode is only supported for bytespp = 1 + */ + Palette *palette; - /* Color masks */ uint32 red_mask, green_mask, blue_mask, alpha_mask; short red_shift, green_shift, blue_shift, alpha_shift; - - /* Each of the mask/shift pairs describe where the corresponding color - ** values are stored for the described mode. Internally, color - ** calculations are done by using 32 bit values for r, g, b, a. After - ** the internal values have been calculated, they are shifted RIGHT - ** by the xxx_shift amount described above, then ANDed with the - ** corresponding color mask; finally, all three results are ORred to- - ** gether. The alpha values are used as appropriate; if alpha_mask is - ** zero, then images use a special alpha map. */ - }; @@ -84,16 +87,16 @@ struct gfx_mode_t { /** Pixmap-specific color entries */ struct gfx_pixmap_color_t{ - int global_index; /* Global index color or GFX_COLOR_INDEX_UNMAPPED. */ - uint8 r, g, b; /* Real color */ + int global_index; /**< Global index color or GFX_COLOR_INDEX_UNMAPPED. */ + uint8 r, g, b; /**< Real color */ }; /** Full color */ struct gfx_color_t { PaletteEntry visual; - uint8 alpha; /* transparency = (1-opacity) */ + uint8 alpha; /**< transparency = (1-opacity) */ int8 priority, control; - byte mask; /* see mask values below */ + byte mask; /**< see mask values below */ }; @@ -104,11 +107,15 @@ struct rect_t { int width, height; /* width, height: (x,y,width,height)=(5,5,1,1) occupies 1 pixel */ }; -/* Generates a rect_t from index data -** Parameters: (int x int) x,y: Upper left point of the rectangle -** (int x int) width, height: Horizontal and vertical extension of the rectangle -** Returns : (rect_t) A rectangle matching the supplied parameters -*/ +/** + * Generates a rect_t from index data + * + * @param[in] x Left side of the rectangle + * @param[in] y Top side of the rectangle + * @param[in] width Horizontal extent of the rectangle + * @param[in] height Verical extent of the rectangle + * @return A rectangle matching the supplied parameters + */ static inline rect_t gfx_rect(int x, int y, int width, int height) { rect_t rect; @@ -120,11 +127,16 @@ static inline rect_t gfx_rect(int x, int y, int width, int height) { return rect; } -// Temporary helper functions to ease the transition from rect_t to Common::Rect +/** + * Temporary helper function to ease the transition from rect_t to Common::Rect + */ static inline rect_t toSCIRect(Common::Rect in) { return gfx_rect(in.left, in.top, in.width(), in.height()); } +/** + * Temporary helper function to ease the transition from rect_t to Common::Rect + */ static inline Common::Rect toCommonRect(rect_t in) { return Common::Rect(in.x, in.y, in.x + in.width, in.y + in.height); } @@ -133,10 +145,13 @@ static inline Common::Rect toCommonRect(rect_t in) { #define OVERLAP(a, b, z, zl) (a.z >= b.z && a.z < (b.z + b.zl)) -/* Determines whether two rects overlap -** Parameters: (rect_t x rect_t) a,b: The two rect_ts to check for overlap -** Returns : (int) 1 if they overlap, 0 otherwise -*/ +/** + * Determines whether two rects overlap + * + * @param[in] a First rect to check for overlap + * @param[in] b Second rect to check for overlap + * @return 1 if they overlap, 0 otherwise + */ static inline int gfx_rects_overlap(rect_t a, rect_t b) { return (OVERLAP(a, b, x, width) || OVERLAP(b, a, x, width)) && (OVERLAP(a, b, y, height) || OVERLAP(b, a, y, height)); } @@ -150,86 +165,95 @@ extern rect_t gfx_rect_fullscreen; #define GFX_PIC_COLORS 256 -#define GFX_PIXMAP_FLAG_SCALED_INDEX (1<<0) /* Index data is scaled already */ -#define GFX_PIXMAP_FLAG_INSTALLED (1<<2) /* Pixmap has been registered */ -#define GFX_PIXMAP_FLAG_PALETTIZED (1<<6) /* Indicates a palettized view */ +#define GFX_PIXMAP_FLAG_SCALED_INDEX (1<<0) /* Index data is scaled already */ +#define GFX_PIXMAP_FLAG_INSTALLED (1<<2) /* Pixmap has been registered */ +#define GFX_PIXMAP_FLAG_PALETTIZED (1<<6) /* Indicates a palettized view */ #define GFX_PIXMAP_COLOR_KEY_NONE -1 /* No transpacency colour key */ #define GFX_CURSOR_TRANSPARENT 255 // Cursor colour key -struct gfx_pixmap_t { /* gfx_pixmap_t: Pixel map */ +/** Pixel map */ +struct gfx_pixmap_t { - /*** Meta information ***/ - int ID; /* Resource ID, or GFX_RESID_NONE for anonymous graphical data */ - short loop, cel; /* loop and cel number for views */ + /** @name Meta information + * @{*/ + int ID; /**< Resource ID, or GFX_RESID_NONE for anonymous graphical data */ + short loop; /**< loop number for view */ + short cel; /**< cel number for view */ + /** @}*/ - - /*** Color map ***/ + /** @name Color map + * @{*/ Palette *palette; - int colors_nr() const { return palette ? palette->size() : 0; } - /* color entries, or NULL if the - ** default palette is to be used. - ** A maximum of 255 colors is allowed; color - ** index 0xff is reserved for transparency. - ** As a special exception, 256 colors are - ** allowed for background pictures (which do - ** not use transparency) - */ - uint32 flags; - - /*** Hot spot ***/ - int xoffset, yoffset; /* x and y coordinates of the 'hot spot' (unscaled) */ - /*** Index data ***/ - int index_width, index_height; /* width and height of the indexed original image */ - byte *index_data; /* Color-index data, or NULL if read from an - ** external source - */ - - /*** Drawable data ***/ - int width, height; /* width and height of the actual image */ - int data_size; /* Amount of allocated memory */ - byte *data; /* Drawable data, or NULL if not converted. */ - - byte *alpha_map; /* Byte map with alpha values. It is used only if the - ** graphics mode's alpha_mask is zero. - */ + /** + * color entries, or NULL if the default palette is to be used. A maximum + * of 255 colors is allowed; color index 0xff is reserved for transparency. + * As a special exception, 256 colors are allowed for background pictures + * (which do not use transparency) + */ + int colors_nr() const { return palette ? palette->size() : 0; } - int color_key; - int palette_revision; // Revision of palette at the time data was generated + uint32 flags; + /* @} */ + + /** @name Hot spot + * x and y coordinates of the 'hot spot' (unscaled) + * @{*/ + int xoffset, yoffset; + /** @} */ + + /** @name Index data + * @{ + */ + int index_width; /**< width of the indexed original image */ + int index_height; /**< height of the indexed original image */ + byte *index_data; /**< Color-index data, or NULL if read from an external source */ + /** @} */ + + /** @name Drawable data + * @{ + */ + int width; /**< width of the actual image */ + int height; /**< height of the actual image */ + int data_size; /**< Amount of allocated memory */ + byte *data; /**< Drawable data, or NULL if not converted. */ + + byte *alpha_map; /**< Byte map with alpha values. It is used only if the graphics mode's alpha_mask is zero. */ + + int color_key; /**< The color to make transparent */ + int palette_revision; /**< Revision of palette at the time data was generated */ + /** @} */ }; -/***********************/ -/*** Constant values ***/ -/***********************/ -/* Return values */ +/** @name Constant values + * @{ */ + +/** Return values */ enum gfx_return_value_t { - GFX_OK = 0, /* Indicates "operation successful" */ - GFX_ERROR = -1, /* Indicates "operation failed" */ - GFX_FATAL = -2 - /* Fatal error: Used by graphics drivers to indicate that they were unable to - ** do anything useful - */ + GFX_OK = 0, /**< Indicates "operation successful" */ + GFX_ERROR = -1, /**< Indicates "operation failed" */ + GFX_FATAL = -2 /**< Fatal error: Used by graphics drivers to indicate + that they were unable to do anything useful */ }; - -enum gfx_map_mask_t {/* Map masks */ +/** Map masks */ +enum gfx_map_mask_t { GFX_MASK_NONE = 0, GFX_MASK_VISUAL = 1, GFX_MASK_PRIORITY = 2, GFX_MASK_CONTROL = 4 }; -/* 'no priority' mode */ +/** 'no priority' mode */ enum { GFX_NO_PRIORITY = -1 }; -/* Text alignment values */ - +/** Text alignment values */ enum gfx_alignment_t { ALIGN_RIGHT = -1, ALIGN_TOP = -1, @@ -240,16 +264,16 @@ enum gfx_alignment_t { enum gfx_line_mode_t { - GFX_LINE_MODE_CORRECT, /* Scaled separately */ - GFX_LINE_MODE_FAST, /* Scaled by (xfact+yfact)/2 */ - GFX_LINE_MODE_FINE /* Always drawn at width 1 */ + GFX_LINE_MODE_CORRECT, /**< Scaled separately */ + GFX_LINE_MODE_FAST, /**< Scaled by (xfact+yfact)/2 */ + GFX_LINE_MODE_FINE /**< Always drawn at width 1 */ }; enum gfx_brush_mode_t { - GFX_BRUSH_MODE_SCALED, /* Just scale the brush pixels */ - GFX_BRUSH_MODE_ELLIPSES, /* Replace pixels with ellipses */ - GFX_BRUSH_MODE_RANDOM_ELLIPSES, /* Replace pixels with ellipses moved and re-scaled randomly */ - GFX_BRUSH_MODE_MORERANDOM /* Distribute randomly */ + GFX_BRUSH_MODE_SCALED, /**< Just scale the brush pixels */ + GFX_BRUSH_MODE_ELLIPSES, /**< Replace pixels with ellipses */ + GFX_BRUSH_MODE_RANDOM_ELLIPSES, /**< Replace pixels with ellipses moved and re-scaled randomly */ + GFX_BRUSH_MODE_MORERANDOM /**< Distribute randomly */ }; @@ -260,18 +284,19 @@ enum gfx_line_style_t { enum gfx_rectangle_fill_t { - GFX_SHADE_FLAT, /* Don't shade */ - GFX_SHADE_VERTICALLY, /* Shade vertically */ - GFX_SHADE_HORIZONTALLY /* Shade horizontally */ + GFX_SHADE_FLAT, /**< Don't shade */ + GFX_SHADE_VERTICALLY, /**< Shade vertically */ + GFX_SHADE_HORIZONTALLY /**< Shade horizontally */ }; enum gfx_color_mode_t { - GFX_COLOR_MODE_AUTO = 0, /* Auto-detect- handled by the gfxop library */ - GFX_COLOR_MODE_INDEX = 1, /* Index mode */ - GFX_COLOR_MODE_HIGH = 2, /* High color mode (15bpp or 16 bpp) */ - GFX_COLOR_MODE_TRUE = 4 /* True color mode (24 bpp padded to 32 bpp) */ + GFX_COLOR_MODE_AUTO = 0, /**< Auto-detect- handled by the gfxop library */ + GFX_COLOR_MODE_INDEX = 1, /**< Index mode */ + GFX_COLOR_MODE_HIGH = 2, /**< High color mode (15bpp or 16 bpp) */ + GFX_COLOR_MODE_TRUE = 4 /**< True color mode (24 bpp padded to 32 bpp) */ }; +/** @} */ } // End of namespace Sci diff --git a/engines/sci/gfx/gfx_tools.h b/engines/sci/gfx/gfx_tools.h index 8582dfa565..9b4ce32e89 100644 --- a/engines/sci/gfx/gfx_tools.h +++ b/engines/sci/gfx/gfx_tools.h @@ -23,9 +23,6 @@ * */ -/* SCI graphics subsystem helper functions */ - - #ifndef SCI_GFX_GFX_TOOLS_H #define SCI_GFX_GFX_TOOLS_H @@ -36,162 +33,198 @@ namespace Sci { +/** @name SCI graphics subsystem helper functions */ +/** @{ */ + enum gfx_xlate_filter_t { GFX_XLATE_FILTER_NONE, GFX_XLATE_FILTER_LINEAR, GFX_XLATE_FILTER_TRILINEAR }; +/** + * Allocates a new gfx_mode_t structure with the specified parameters + * + * @param[in] xfact Horizontal scaling factors + * @param[in] yfact Vertical scaling factors + * @param[in] format Pixel format description + * @param[in] palette Number of palette colors, 0 if we're not in palette mode + * @param[in] flags GFX_MODE_FLAG_* values ORred together, or just 0 + * @return A newly allocated gfx_mode_t structure + */ gfx_mode_t *gfx_new_mode(int xfact, int yfact, const Graphics::PixelFormat &format, Palette *palette, int flags); -/* Allocates a new gfx_mode_t structure with the specified parameters -** Parameters: (int x int) xfact x yfact: Horizontal and vertical scaling factors -** (Graphics::PixelFormat) format: pixel format description -** (int) palette: Number of palette colors, 0 if we're not in palette mode -** (int) flags: GFX_MODE_FLAG_* values ORred together, or just 0 -** Returns : (gfx_mode_t *) A newly allocated gfx_mode_t structure -*/ - +/** + * Clips a rect_t + * + * @param[in] box Pointer to the box to clip + * @param[in] maxx Maximum allowed width + * @param[in] maxy Maximum allowed height + */ void gfx_clip_box_basic(rect_t *box, int maxx, int maxy); -/* Clips a rect_t -** Parameters: (rect_t *) box: Pointer to the box to clip -** (int x int) maxx, maxy: Maximum allowed width and height -** Returns : (void) -*/ - +/** + * Frees all memory allocated by a mode structure + * @param[in] mode The mode to free + */ void gfx_free_mode(gfx_mode_t *mode); -/* Frees all memory allocated by a mode structure -** Parameters: (gfx_mode_t *) mode: The mode to free -** Returns : (void) -*/ - +/** + * Creates a new pixmap structure + * + * The following fiels are initialized: + * ID, loop, cel, index_width, index_height, xl, yl, data <- NULL, + * alpha_map <- NULL, internal.handle <- 0, internal.info <- NULL, + * colors <- NULL, index_scaled <- 0 + * + * @param[in] xl Width (in SCI coordinates) of the pixmap + * @param[in] yl Height (in SCI coordinates) of the pixmap + * @param[in] resid The pixmap's resource ID, or GFX_RESID_NONE + * @param[in] loop For views: The pixmap's loop number + * @param[in] cel For cels: The pixmap's cel number + * @return The newly allocated pixmap + */ gfx_pixmap_t *gfx_new_pixmap(int xl, int yl, int resid, int loop, int cel); -/* Creates a new pixmap structure -** Parameters: (int x int) xl x yl: The dimensions (in SCI coordinates) of the pixmap -** (int) resid: The pixmap's resource ID, or GFX_RESID_NONE -** (int) loop: For views: The pixmap's loop number -** (int) cel: For cels: The pixmap's cel number -** Returns : (gfx_pixmap_t *) The newly allocated pixmap -** The following fiels are initialized: -** ID, loop, cel, index_width, index_height, xl, yl, data <- NULL, -** alpha_map <- NULL, internal.handle <- 0, internal.info <- NULL, colors <- NULL, -** index_scaled <- 0 -*/ +/** + * Clones a pixmap, minus its index data, palette and driver-specific + * handles + * + * @param[in] pixmap The pixmap to clone + * @param[in] mode The mode to be applied to the pixmap + * @return The clone + */ gfx_pixmap_t *gfx_clone_pixmap(gfx_pixmap_t *pixmap, gfx_mode_t *mode); -/* Clones a pixmap, minus its index data, palette and driver-specific handles -** Parameters: (gfx_pixmap_t *) pixmap: The pixmap to clone -** (gfx_mode_t *) mode: The mode to be applied to the pixmap -** Returns : (gfx_pixmap_t *) The clone -*/ - +/** + * Allocates the index_data field of a pixmap + * + * @param[in] pixmap The pixmap to allocate for + * @return The pixmap + */ gfx_pixmap_t *gfx_pixmap_alloc_index_data(gfx_pixmap_t *pixmap); -/* Allocates the index_data field of a pixmap -** Parameters: (gfx_pixmap_t *) pixmap: The pixmap to allocate for -** Returns : (gfx_pixmap_t *) pixmap -*/ +/** + * Frees the index_data field of a pixmap + * + * @param[in] pixmap The pixmap to modify + * @return The pixmap + */ gfx_pixmap_t *gfx_pixmap_free_index_data(gfx_pixmap_t *pixmap); -/* Frees the index_data field of a pixmap -** Parameters: (gfx_pixmap_t *) pixmap: The pixmap to modify -** Returns : (gfx_pixmap_t *) pixmap -*/ +/** + * Allocates the data field of a pixmap + * + * @param[in] pixmap The pixmap to allocate for + * @param[in] mode The mode the memory is to be allocated for + * @return The pixmap + */ gfx_pixmap_t *gfx_pixmap_alloc_data(gfx_pixmap_t *pixmap, gfx_mode_t *mode); -/* Allocates the data field of a pixmap -** Parameters: (gfx_pixmap_t *) pixmap: The pixmap to allocate for -** (gfx_mode_t *) mode: The mode the memory is to be allocated for -** Returns : (gfx_pixmap_t *) pixmap -*/ +/** + * Frees the memory allocated for a pixmap's data field + * + * @param[in] pixmap The pixmap to modify + * @return The pixmap + */ gfx_pixmap_t *gfx_pixmap_free_data(gfx_pixmap_t *pixmap); -/* Frees the memory allocated for a pixmap's data field -** Parameters: (gfx_pixmap_t *) pixmap: The pixmap to modify -** Returns : (gfx_pixmap_t *) pixmap -*/ +/** + * Frees all memory associated with a pixmap + * + * @param[in] pxm The pixmap to free + */ void gfx_free_pixmap(gfx_pixmap_t *pxm); -/* Frees all memory associated with a pixmap -** Parameters: (gfx_pixmap_t *) pxm: The pixmap to free -** Returns : (void) -*/ - -void gfx_draw_line_pixmap_i(gfx_pixmap_t *pxm, Common::Point start, Common::Point end, int color); -/* Draws a line to a pixmap's index data buffer -** Parameters: (gfx_pixmap_t *) pxm: The pixmap to draw to -** (Common::Point) start: Starting point of the line to draw -** (Common::Point) end: End point of the line to draw -** (int) color: The byte value to write -** Returns : (void) -** Remember, this only draws to the /index/ buffer, not to the drawable buffer. -** The line is not clipped. Invalid x, y, x1, y1 values will result in memory corruption. -*/ +/** + * Draws a line to a pixmap's index data buffer + * + * Remember, this only draws to the /index/ buffer, not to the drawable buffer. + * The line is not clipped. Invalid x, y, x1, y1 values will result in memory + * corruption. + * + * @param[in] pxm The pixmap to draw to + * @param[in] start Starting point of the line to draw + * @param[in] end End point of the line to draw + * @param[in] color The byte value to write + */ +void gfx_draw_line_pixmap_i(gfx_pixmap_t *pxm, Common::Point start, + Common::Point end, int color); + +/** + * Draws a filled rectangular area to a pixmap's index buffer + * + * This function only draws to the index buffer. + * + * @param[in] pxm The pixmap to draw to + * @param[in] box The box to fill + * @param[in] color The color to use for drawing + */ void gfx_draw_box_pixmap_i(gfx_pixmap_t *pxm, rect_t box, int color); -/* Draws a filled rectangular area to a pixmap's index buffer -** Parameters: (gfx_pixmap_t *) pxm: The pixmap to draw to -** (rect_t) box: The box to fill -** (int) color: The color to use for drawing -** Returns : (void) -** This function only draws to the index buffer. -*/ +/** + * Copies part of a pixmap to another pixmap, with clipping + * + * @param[in] dest The destination pixmap + * @param[in] src The source pixmap + * @param[in] box The area to copy + */ void gfx_copy_pixmap_box_i(gfx_pixmap_t *dest, gfx_pixmap_t *src, rect_t box); -/* Copies part of a pixmap to another pixmap, with clipping -** Parameters: (gfx_pixmap_t *) dest: The destination pixmap -** (gfx_pixmap_t *) src: The source pixmap -** (rect_t) box: The area to copy -** Returns : (void) -*/ +/** + * Translates a pixmap's index data to drawable graphics data + * + * @param[in] pxm The pixmap to translate + * @param[in] mode The mode according which to scale + * @param[in] filter How to filter the data + */ void gfx_xlate_pixmap(gfx_pixmap_t *pxm, gfx_mode_t *mode, gfx_xlate_filter_t filter); -/* Translates a pixmap's index data to drawable graphics data -** Parameters: (gfx_pixmap_t *) pxm: The pixmap to translate -** (gfx_mode_t *) mode: The mode according which to scale -** (gfx_xlate_filter_t) filter: How to filter the data -** Returns : (void) -*/ -#define GFX_CROSSBLIT_FLAG_DATA_IS_HOMED (1<<0) -/* Means that the first byte in the visual data refers to the -** point corresponding to (dest.x, dest.y) */ +#define GFX_CROSSBLIT_FLAG_DATA_IS_HOMED (1<<0) /**< Means that the first byte in the visual data refers to the point corresponding to (dest.x, dest.y) */ +/** + * Transfers the non-transparent part of a pixmap to a linear pixel + * buffer. + * + * A 'linear buffer' in this context means a data buffer containing an entire + * screen (visual or priority), with fixed offsets between each data row, and + * linear access. + * + * @param[in] mode The graphics mode of the target buffer + * @param[in] pxm The pixmap to transfer + * @param[in] priority The pixmap's priority + * @param[in] src_coords The source coordinates within the pixmap + * @param[in] dest_coords The destination coordinates (no scaling) + * @param[in] dest Memory position of the upper left pixel of + * the linear pixel buffer + * @param[in] dest_line_width Byte offset of the very first pixel in the + * second line of the linear pixel buffer, + * relative to dest. + * @param[in] priority_dest Destination buffer for the pixmap's priority + * values + * @param[in] priority_line_width Byte offset of the first pixel in the second + * line of the priority buffer + * @param[in] priority_skip Amount of bytes allocated by each priority + * value + * @param[in] flags Any crossblit flags + * @return GFX_OK, or GFX_ERROR if the specified mode + * was invalid or unsupported + */ int gfx_crossblit_pixmap(gfx_mode_t *mode, gfx_pixmap_t *pxm, int priority, rect_t src_coords, rect_t dest_coords, byte *dest, int dest_line_width, byte *priority_dest, int priority_line_width, int priority_skip, int flags); -/* Transfers the non-transparent part of a pixmap to a linear pixel buffer -** Parameters: (gfx_mode_t *) mode: The graphics mode of the target buffer -** (gfx_pixmap_t *) pxm: The pixmap to transfer -** (int priority): The pixmap's priority -** (rect_t) src_coords: The source coordinates within the pixmap -** (rect_t) dest_coords: The destination coordinates (no scaling) -** (byte *) dest: Memory position of the upper left pixel of the -** linear pixel buffer -** (int) dest_line_width: Byte offset of the very first pixel in the -** second line of the linear pixel buffer, -** relative to dest. -** (byte *) priority_dest: Destination buffer for the pixmap's priority -** values -** (int) priority_line_width: Byte offset of the first pixel in the -** second line of the priority buffer -** (int) priority_skip: Amount of bytes allocated by each priority value -** (int) flags: Any crossblit flags -** Returns : (int) GFX_OK, or GFX_ERROR if the specified mode was invalid or unsupported -** A 'linear buffer' in this context means a data buffer containing an entire -** screen (visual or priority), with fixed offsets between each data row, and -** linear access. -*/ + +/** + * Scales the index data associated with a pixmap + * + * @param[in] pixmap The pixmap whose index data should be scaled + * @param[in] mode The mode to scale it to + * @return The pixmap + */ gfx_pixmap_t *gfx_pixmap_scale_index_data(gfx_pixmap_t *pixmap, gfx_mode_t *mode); -/* Scales the index data associated with a pixmap -** Parameters: (gfx_pixmap_t *) pixmap: The pixmap whose index data should be scaled -** (gfx_mode_t *) mode: The mode to scale it to -** Returns : (gfx_pixmap_t *) pixmap -*/ +/** @} */ } // End of namespace Sci #endif // SCI_GFX_GFX_TOOLS_H diff --git a/engines/sci/gfx/gfx_widgets.h b/engines/sci/gfx/gfx_widgets.h index bd884ffbb4..80129152cb 100644 --- a/engines/sci/gfx/gfx_widgets.h +++ b/engines/sci/gfx/gfx_widgets.h @@ -23,7 +23,6 @@ * */ -/* Graphical state management */ #ifndef SCI_GFX_GFX_WIDGETS_H #define SCI_GFX_GFX_WIDGETS_H @@ -34,6 +33,8 @@ #include "sci/gfx/operations.h" namespace Sci { +/** @name Widget Graphical State Management */ +/** @{ */ struct GfxState; struct GfxBox; @@ -155,241 +156,324 @@ extern Common::Point gfxw_point_zero; /*-- Primitive types --*/ +/** + * Creates a new box + * + * The graphics state, if non-NULL, is used here for some optimizations. + * + * @param[in] state The (optional) state + * @param[in] area The box's dimensions, relative to its container + * widget + * @param[in] color1 The primary color + * @param[in] color2 The secondary color (ignored if shading is disabled) + * @param[in] shade_type The shade type for the box + * @return The resulting box widget + */ GfxBox *gfxw_new_box(GfxState *state, rect_t area, gfx_color_t color1, gfx_color_t color2, gfx_box_shade_t shade_type); -/* Creates a new box -** Parameters: (GfxState *) state: The (optional) state -** (rect_t) area: The box's dimensions, relative to its container widget -** (gfx_color_t) color1: The primary color -** (gfx_color_t) color1: The secondary color (ignored if shading is disabled) -** (gfx_box_shade_t) shade_type: The shade type for the box -** Returns : (GfxBox *) The resulting box widget -** The graphics state- if non-NULL- is used here for some optimizations. -*/ -GfxPrimitive *gfxw_new_rect(rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style); -/* Creates a new rectangle -** Parameters: (rect_t) rect: The rectangle area -** (gfx_color_t) color: The rectangle's color -** (gfx_line_mode_t) line_mode: The line mode for the lines that make up the rectangle -** (gfx_line_style_t) line_style: The rectangle's lines' style -** Returns : (GfxPrimitive *) The newly allocated rectangle widget (a Primitive) -*/ +/** + * Creates a new rectangle + * + * @param[in] rect The rectangle area + * @param[in] color The rectangle's color + * @param[in] line_mode The line mode for the lines that make up the + * rectangle + * @param[in] line_style The rectangle's lines' style + * @return The newly allocated rectangle widget (a Primitive) + */ +GfxPrimitive *gfxw_new_rect(rect_t rect, gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style); -GfxPrimitive *gfxw_new_line(Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style); -/* Creates a new line -** Parameters: (Common::Point * Common::Point) (start, line): The line origin and end point -** (gfx_color_t) color: The line's color -** (gfx_line_mode_t) line_mode: The line mode to use for drawing -** (gfx_line_style_t) line_style: The line style -** Returns : (GfxPrimitive *) The newly allocated line widget (a Primitive) -*/ +/** + * Creates a new line + * + * @param[in] start The line's origin + * @param[in] end The line's end point + * @param[in] color The line's color + * @param[in] line_mode The line mode to use for drawing + * @param[in] line_style The line style + * @return The newly allocated line widget (a Primitive) + */ +GfxPrimitive *gfxw_new_line(Common::Point start, Common::Point end, + gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style); +/** View flags */ +enum { + GFXW_VIEW_FLAG_STATIC = (1 << 0), /**< Whether the view should be static */ + GFXW_VIEW_FLAG_DONT_MODIFY_OFFSET = (1 << 1) /**< Whether the view should _not_ apply its x/y offset modifyers */ +}; -/* Whether the view should be static */ -#define GFXW_VIEW_FLAG_STATIC (1 << 0) - -/* Whether the view should _not_ apply its x/y offset modifyers */ -#define GFXW_VIEW_FLAG_DONT_MODIFY_OFFSET (1 << 1) - -GfxView *gfxw_new_view(GfxState *state, Common::Point pos, int view, int loop, int cel, int palette, int priority, int control, - gfx_alignment_t halign, gfx_alignment_t valign, int flags); -/* Creates a new view (a cel, actually) -** Parameters: (GfxState *) state: The graphics state -** (Common::Point) pos: The position to place the view at -** (int x int x int) view, loop, cel: The global cel ID -** (int) priority: The priority to use for drawing, or -1 for none -** (int) control: The value to write to the control map, or -1 for none -** (gfx_alignment_t x gfx_alignment_t) halign, valign: Horizontal and vertical -** cel alignment -** (int) flags: Any combination of GFXW_VIEW_FLAGs -** Returns : (gfxw_cel_t *) A newly allocated cel according to the specs -*/ +/** + * Creates a new view (a cel, actually) + * + * @param[in] state The graphics state + * @param[in] pos The position to place the view at + * @param[in] view The global cel ID + * @param[in] loop The global cel ID + * @param[in] cel The global cel ID + * @param[in] palette The palette to use + * @param[in] priority The priority to use for drawing, or -1 for none + * @param[in] control The value to write to the control map, or -1 for none + * @param[in] halign Horizontal cel alignment + * @param[in] valign Vertical cel alignment + * @param[in] flags Any combination of GFXW_VIEW_FLAGs + * @return A newly allocated cel according to the specs + */ +GfxView *gfxw_new_view(GfxState *state, Common::Point pos, int view, int loop, + int cel, int palette, int priority, int control, gfx_alignment_t halign, + gfx_alignment_t valign, int flags); -GfxDynView *gfxw_new_dyn_view(GfxState *state, Common::Point pos, int z, int view, int loop, int cel, int palette, - int priority, int control, gfx_alignment_t halign, gfx_alignment_t valign, int sequence); -/* Creates a new dyn view -** Parameters: (GfxState *) state: The graphics state -** (Common::Point) pos: The position to place the dynamic view at -** (int) z: The z coordinate -** (int x int x int) view, loop, cel: The global cel ID -** (int) priority: The priority to use for drawing, or -1 for none -** (int) control: The value to write to the control map, or -1 for none -** (gfx_alignment_t x gfx_alignment_t) halign, valign: Horizontal and vertical -** cel alignment -** (int) sequence: Sequence number: When sorting dynviews, this number is -** considered last for sorting (ascending order) -** Returns : (gfxw_cel_t *) A newly allocated cel according to the specs -** Dynamic views are non-pic views with a unique global identifyer. This allows for drawing -** optimizations when they move or change shape. -*/ -GfxText *gfxw_new_text(GfxState *state, rect_t area, int font, const char *text, gfx_alignment_t halign, - gfx_alignment_t valign, gfx_color_t color1, gfx_color_t color2, - gfx_color_t bgcolor, int flags); -/* Creates a new text widget -** Parameters: (GfxState *) state: The state the text is to be calculated from -** (rect_t) area: The area the text is to be confined to (the yl value is only -** relevant for text aligment, though) -** (int) font: The number of the font to use -** (gfx_alignment_t x gfx_alignment_t) halign, valign: Horizontal and -** vertical text alignment -** (gfx_color_t x gfx_color_t) color1, color2: Text foreground colors (if not equal, -** The foreground is dithered between them) -** (gfx_color_t) bgcolor: Text background color -** (int) flags: GFXR_FONT_FLAGs, orred together (see gfx_resource.h) -** Returns : (GfxText *) The resulting text widget -*/ +/** + * Creates a new dyn view + * + * Dynamic views are non-pic views with a unique global identifyer. This allows for drawing optimizations when they move or change shape. + * + * @param[in] state The graphics state + * @param[in] pos The position to place the dynamic view at + * @param[in] z The z coordinate + * @param[in] view The global cel ID + * @param[in] loop The global cel ID + * @param[in] cel The global cel ID + * @param[in] palette The palette to use + * @param[in] priority The priority to use for drawing, or -1 for none + * @param[in] control The value to write to the control map, or -1 for none + * @param[in] halign Horizontal cel alignment + * @param[in] valign Vertical cel alignment + * @param[in] sequence Sequence number: When sorting dynviews, this number is + * considered last for sorting (ascending order) + * @return A newly allocated cel according to the specs + */ +GfxDynView *gfxw_new_dyn_view(GfxState *state, Common::Point pos, int z, + int view, int loop, int cel, int palette, int priority, int control, + gfx_alignment_t halign, gfx_alignment_t valign, int sequence); +/** + * Creates a new text widget + * + * @param[in] state The state the text is to be calculated from + * @param[in] area The area the text is to be confined to (the yl value is + * only relevant for text aligment, though) + * @param[in] font The number of the font to use + * @param[in] text String to put in text widget + * @param[in] halign Horizontal text alignment + * @param[in] valign Vertical text alignment + * @param[in] color1 Text foreground colors (if not equal, the foreground is + * dithered between them) + * @param[in] color2 Text foreground colors (if not equal, the foreground is + * dithered between them) + * @param[in] bgcolor Text background color + * @param[in] flags GFXR_FONT_FLAGs, orred together (see gfx_resource.h) + * @return The resulting text widget + */ +GfxText *gfxw_new_text(GfxState *state, rect_t area, int font, const char *text, + gfx_alignment_t halign, gfx_alignment_t valign, gfx_color_t color1, + gfx_color_t color2, gfx_color_t bgcolor, int flags); + +/** + * Determines text widget meta-information + * + * @param[in] state The state to operate on + * @param[in] text The widget to query + * @param[out] lines_nr Number of lines used in the text + * @param[out] lineheight Pixel height (SCI scale) of each text line + * @param[out] offset Pixel offset (SCI scale) of the space after the last + * character in the last line + */ void gfxw_text_info(GfxState *state, GfxText *text, int *lines_nr, int *lineheight, int *offset); -/* Determines text widget meta-information -** Parameters: (GfxState *) state: The state to operate on -** (gfx_text_t *) text: The widget to query -** Returns : (int) lines_nr: Number of lines used in the text -** (int) lineheight: Pixel height (SCI scale) of each text line -** (int) offset: Pixel offset (SCI scale) of the space after the -** last character in the last line -*/ +/** + * Sets a widget's ID + * + * A widget ID is unique within the container it is stored in, if and only if it + * was added to that container with gfxw_add(). This function handles widget == + * NULL gracefully (by doing nothing and returning NULL). + * + * @param[in] widget The widget whose ID should be set + * @param[in] ID The ID to set + * @param[in] subID The ID to set + * @return The widget + */ GfxWidget *gfxw_set_id(GfxWidget *widget, int ID, int subID); -/* Sets a widget's ID -** Parmaeters: (GfxWidget *) widget: The widget whose ID should be set -** (int x int) ID, subID: The ID to set -** Returns : (GfxWidget *) widget -** A widget ID is unique within the container it is stored in, if and only if it was -** added to that container with gfxw_add(). -** This function handles widget = NULL gracefully (by doing nothing and returning NULL). -*/ +/** + * Finds a widget with a specific ID in a container and removes it from there + * + * Search is non-recursive; widgets with IDs hidden in subcontainers will not + * be found. + * + * @param[in] container The container to search in + * @param[in] ID The ID to look for + * @param[in] subID The subID to look for, or GFXW_NO_ID for any + * @return The resulting widget or NULL if no match was found + */ GfxWidget *gfxw_remove_id(GfxContainer *container, int ID, int subID); -/* Finds a widget with a specific ID in a container and removes it from there -** Parameters: (GfxContainer *) container: The container to search in -** (int) ID: The ID to look for -** (int) subID: The subID to look for, or GFXW_NO_ID for any -** Returns : (GfxWidget *) The resulting widget or NULL if no match was found -** Search is non-recursive; widgets with IDs hidden in subcontainers will not be found. -*/ +/** + * Initializes a dyn view's interpreter attributes + * + * @param[in] widget The widget affected + * @param[in] under_bits Interpreter-dependant data + * @param[in] under_bitsp Interpreter-dependant data + * @param[in] signal Interpreter-dependant data + * @param[in] signalp Interpreter-dependant data + * @return The widget + */ +GfxDynView *gfxw_dyn_view_set_params(GfxDynView *widget, int under_bits, + const ObjVarRef& under_bitsp, int signal, const ObjVarRef& signalp); -GfxDynView *gfxw_dyn_view_set_params(GfxDynView *widget, int under_bits, const ObjVarRef& under_bitsp, int signal, const ObjVarRef& signalp); -/* Initializes a dyn view's interpreter attributes -** Parameters: (GfxDynView *) widget: The widget affected -** (int x void * x int x void *) under_bits, inder_bitsp, signal, signalp: Interpreter-dependant data -** Returns : (GfxDynView *) widget -*/ - +/** + * Makes a widget invisible without removing it from the list of widgets + * + * Has no effect on invisible widgets + * + * @param[in] widget The widget to invisibilize + * @return The widget + */ GfxWidget *gfxw_hide_widget(GfxWidget *widget); -/* Makes a widget invisible without removing it from the list of widgets -** Parameters: (GfxWidget *) widget: The widget to invisibilize -** Returns : (GfxWidget *) widget -** Has no effect on invisible widgets -*/ +/** + * Makes an invisible widget reappear + * + * Does not affect visible widgets + * + * @param[in] widget The widget to show again + * @return The widget + */ GfxWidget *gfxw_show_widget(GfxWidget *widget); -/* Makes an invisible widget reappear -** Parameters: (GfxWidget *) widget: The widget to show again -** Returns : (GfxWidget *) widget -** Does not affect visible widgets -*/ +/** + * Marks a widget as "abandoned" + * + * @param[in] widget The widget to abandon + * @return The widget + */ GfxWidget *gfxw_abandon_widget(GfxWidget *widget); -/* Marks a widget as "abandoned" -** Parameters: (GfxWidget *) widget: The widget to abandon -** Returns : (GfxWidget *) widget -*/ - -/*-- Container types --*/ -#define GFXW_LIST_UNSORTED 0 -#define GFXW_LIST_SORTED 1 +/** Container types */ +enum { + GFXW_LIST_UNSORTED = 0, + GFXW_LIST_SORTED = 1 +}; +/** + * Creates a new list widget + * + * List widgets are also referred to as Display Lists. + * + * @param[in] area The area covered by the list (absolute position) + * @param[in] sorted Whether the list should be a sorted list + * @return A newly allocated list widget + */ GfxList *gfxw_new_list(rect_t area, int sorted); -/* Creates a new list widget -** Parameters: (rect_t) area: The area covered by the list (absolute position) -** (int) sorted: Whether the list should be a sorted list -** Returns : (GfxList *) A newly allocated list widget -** List widgets are also referred to as Display Lists. -*/ +/** + * Retrieves the default port from a visual + * + * The 'default port' is the last port to be instantiated; usually the topmost + * or highest-ranking port. + * + * @param[in] visual The visual the port should be retrieved from + * @return The default port, or NULL if no port is present + */ GfxPort *gfxw_find_default_port(GfxVisual *visual); -/* Retrieves the default port from a visual -** Parameters: (GfxVisual *) visual: The visual the port should be retrieved from -** Returns : (GfxPort *) The default port, or NULL if no port is present -** The 'default port' is the last port to be instantiated; usually the topmost -** or highest-ranking port. -*/ +/** + * Sets rectangle to be restored upon port removal + * + * @param[in] visual The visual to operate on + * @param[in] window The affected window + * @param[in] auto_rect The area to restore + */ void gfxw_port_set_auto_restore(GfxVisual *visual, GfxPort *window, rect_t auto_rect); -/* Sets rectangle to be restored upon port removal -** Parameters: (state_t *) s: The state to operate on -** (GfxPort *) window: The affected window -** (rect_t) auto_rect: The area to restore -** Returns : (void) -*/ +/** + * Removes a port from a visual + * + * @param[in] visual The visual the port should be removed from + * @param[in] port The port to remove + * @return port's parent port, or NULL if it had none + */ GfxPort *gfxw_remove_port(GfxVisual *visual, GfxPort *port); -/* Removes a port from a visual -** Parameters: (GfxVisual *) visual: The visual the port should be removed from -** (GfxPort *) port: The port to remove -** Returns : (GfxPort *) port's parent port, or NULL if it had none -*/ +/** + * Removes the widget from the specified port + * + * @param[in] container The container it should be removed from + * @param[in] widget The widget to remove + */ void gfxw_remove_widget_from_container(GfxContainer *container, GfxWidget *widget); -/* Removes the widget from the specified port -** Parameters: (GfxContainer *) container: The container it should be removed from -** (GfxWidget *) widget: The widget to remove -** Returns : (void) -*/ +/** + * Makes a "snapshot" of a visual + * + * It's not really a full qualified snaphot, though. See gfxw_restore_snapshot + * for a full discussion. This operation also increases the global serial number + * counter by one. + * + * @param[in] visual The visual a snapshot is to be taken of + * @param[in] area The area a snapshot should be taken of + * @return The resulting, newly allocated snapshot + */ gfxw_snapshot_t *gfxw_make_snapshot(GfxVisual *visual, rect_t area); -/* Makes a "snapshot" of a visual -** Parameters: (GfxVisual *) visual: The visual a snapshot is to be taken of -** (rect_t) area: The area a snapshot should be taken of -** Returns : (gfxw_snapshot_t *) The resulting, newly allocated snapshot -** It's not really a full qualified snaphot, though. See gfxw_restore_snapshot -** for a full discussion. -** This operation also increases the global serial number counter by one. -*/ +/** + * Predicate to test whether a widget would be destroyed by applying a snapshot + * + * @param[in] snapshot The snapshot to test against + * @param[in] widget The widget to test + * @return An appropriate boolean value + */ int gfxw_widget_matches_snapshot(gfxw_snapshot_t *snapshot, GfxWidget *widget); -/* Predicate to test whether a widget would be destroyed by applying a snapshot -** Parameters: (gfxw_snapshot_t *) snapshot: The snapshot to test against -** (GfxWidget *) widget: The widget to test -** Retunrrs : (int) An appropriate boolean value -*/ +/** + * Restores a snapshot to a visual + * + * The snapshot is not really restored; only more recent widgets touching + * the snapshotted area are destroyed. + * + * @param[in] visual The visual to operate on + * @param[in] snapshot The snapshot to restore + * @return The snapshot (still needs to be freed) + */ gfxw_snapshot_t *gfxw_restore_snapshot(GfxVisual *visual, gfxw_snapshot_t *snapshot); -/* Restores a snapshot to a visual -** Parameters: (GfxVisual *) visual: The visual to operate on -** (gfxw_snapshot_t *) snapshot: The snapshot to restore -** Returns : (gfxw_snapshot_t *) snapshot (still needs to be freed) -** The snapshot is not really restored; only more recent widgets touching -** the snapshotted area are destroyed. -*/ +/** + * As widget->widfree(widget), but destroys all overlapping widgets + * + * This operation calls widget->widfree(widget), but it also destroys all + * widgets with a higher or equal priority drawn after this widget. + * + * @param[in] widget The widget to use + */ void gfxw_annihilate(GfxWidget *widget); -/* As widget->widfree(widget), but destroys all overlapping widgets -** Parameters: (GfxWidget *) widget: The widget to use -** Returns : (void) -** This operation calls widget->widfree(widget), but it also destroys -** all widgets with a higher or equal priority drawn after this widget. -*/ +/** + * Turns a dynview into a picview + * + * The only changes are in function and type variables, actually. + * + * @param[in] dynview The victim + * @return The victim, after his transformation + */ GfxDynView *gfxw_picviewize_dynview(GfxDynView *dynview); -/* Turns a dynview into a picview -** Parameters: (GfxDynView *) dynview: The victim -** Returns : (GfxDynView *) The victim, after his transformation -** The only changes are in function and type variables, actually. -*/ -void gfxw_port_auto_restore_background(GfxVisual *visual, GfxPort *window, rect_t auto_rect); -/* Tags a window widget as automatically restoring the visual background upon removal -** Parameters: (gfx_visual_t *) visual: The base visual -** (GfxPort *) window: The window to tag -** (rect_t) auto_rect: The background to remember -** Also records the specified background rectangle, for later recovery -*/ +/** + * Tags a window widget as automatically restoring the visual background + * upon removal. + * + * Also records the specified background rectangle, for later recovery. + * + * @param[in] visual The base visual + * @param[in] window The window to tag + * @param[in] auto_rect The background to remember + + */ +void gfxw_port_auto_restore_background(GfxVisual *visual, GfxPort *window, + rect_t auto_rect); +/** @} */ } // End of namespace Sci #endif // SCI_GFX_GFX_WIDGETS_H diff --git a/engines/sci/gfx/menubar.h b/engines/sci/gfx/menubar.h index 02d99332d9..44ecd8f1bb 100644 --- a/engines/sci/gfx/menubar.h +++ b/engines/sci/gfx/menubar.h @@ -50,9 +50,7 @@ struct EngineState; /* The number of pixels added to the left of the first menu */ #define MENU_BOX_CENTER_PADDING 10 -/* Number of pixels to leave in between the left and the right centered text content in boxes -** that use right centered content -*/ +/* Number of pixels to leave in between the left and the right centered text content in boxes that use right centered content */ #define MENU_BOX_LEFT_PADDING 0 /* Number of pixels to pad to the left */ @@ -88,16 +86,16 @@ enum MenuType { class MenuItem : public Common::Serializable { public: - MenuType _type; /* Normal or hbar */ - Common::String _keytext; /* right-centered part of the text (the key) */ + MenuType _type; /**< Normal or hbar */ + Common::String _keytext; /**< right-centered part of the text (the key) */ int _flags; - byte _said[MENU_SAID_SPEC_SIZE]; /* Said spec for this item */ + byte _said[MENU_SAID_SPEC_SIZE]; /**< Said spec for this item */ reg_t _saidPos; Common::String _text; reg_t _textPos; - int _modifiers; /* Hotkey for this item */ - int _key; /* Hotkey for this item */ + int _modifiers; /**< Hotkey for this item */ + int _key; /**< Hotkey for this item */ int _enabled; int _tag; @@ -108,9 +106,10 @@ public: /** * Determines whether a message/modifiers key pair matches a menu item's key parameters. - * @param message The message to match - * @param modifiers The modifier flags to match - * @return true on match, false otherwise + * + * @param[in] message The message to match + * @param[in] modifiers The modifier flags to match + * @return true on match, false otherwise */ bool matchKey(int message, int modifiers); }; @@ -156,59 +155,68 @@ public: /** * Adds a menu to the menubar. - * Parameters: (GfxState *) state: The state the fonts are stored in - * (char *) title: The menu title - * (char *) entries: A string of menu entries - * (int) font: The font which is to be used for drawing - * (reg_t) entries_base: Segmented VM address of the entries string - * Returns : (void) + * * The menu entries use the following special characters: * '`' : Right justify the following part * ':' : End of this entry * '#' : Function key (replaced by 'F') * '^' : Control key (replaced by \002, which looks like "CTRL") * '=' : Initial tag value - * and the special string "--!", which represents a horizontal bar in the menu. + * and the special string "--!", which represents a horizontal bar in the + * menu. + * + * @param[in] state The state the fonts are stored in + * @param[in] title The menu title + * @param[in] entries A string of menu entries + * @param[in] font The font which is to be used for drawing + * @param[in] entries_base Segmented VM address of the entries string */ void addMenu(GfxState *state, const char *title, const char *entries, int font, reg_t entries_base); /** - * Sets the (currently unidentified) foo and bar values. - * Parameters: (state_t *) s: The current state - * (int) menu: The menu number to edit - * (int) item: The menu item to change - * (int) attribute: The attribute to modify - * (int) value: The value the attribute should be set to - * Returns : (int) 0 on success, 1 if either menu or item were invalid + * Sets the attributes for a menu item. + * + * @param[in] s The current state + * @param[in] menu The menu number to edit + * @param[in] item The menu item to change + * @param[in] attribute The attribute to modify + * @param[in] value The value the attribute should be set to + * @return 0 on success, 1 if either menu or item were invalid */ int setAttribute(EngineState *s, int menu, int item, int attribute, reg_t value); /** - * Sets the (currently unidentified) foo and bar values. - * Parameters: (int) menu: The menu number - * (int) item: The menu item to read - * (int) attribute: The attribute to read from - * Returns : (int) The attribute value, or -1 on error + * Gets an attribute for a menuitem. + * + * @param[in] menu The menu number + * @param[in] item The menu item to read + * @param[in] attribute The attribute to read from + * @return The attribute value, or -1 on error */ reg_t getAttribute(int menu, int item, int attribute) const; /** * Determines whether the specified menu entry may be activated. - * @return true if the menu item may be selected, false otherwise + * + * @return true if the menu item may be selected, false otherwise */ bool itemValid(int menu, int item) const; /** * Maps the pointer position to a (menu,item) tuple. - * @param pointerPos the current pointer position - * @param menu_nr the current menu (updated by this function if necessary) - * @param item_nr the current menu item (updated by this function if necessary) - * @param port the port of the currently active menu (if any) - * @return true if the pointer is outside a valid port, false otherwise. + * + * @param[in] pointerPos the current pointer position + * @param[in] menu_nr the current menu (updated by this function if + * necessary) + * @param[in] item_nr the current menu item (updated by this function + * if necessary) + * @param[in] port the port of the currently active menu (if any) + * @return true if the pointer is outside a valid port, + * false otherwise. */ bool mapPointer(const Common::Point &pointerPos, int &menu_nr, int &item_nr, GfxPort *port) const; diff --git a/engines/sci/gfx/operations.h b/engines/sci/gfx/operations.h index d559d3b6d2..491b485da0 100644 --- a/engines/sci/gfx/operations.h +++ b/engines/sci/gfx/operations.h @@ -93,10 +93,10 @@ typedef Common::List<rect_t> DirtyRectList; struct GfxState { gfx_options_t *options; - Common::Point pointer_pos; /* Mouse pointer coordinates */ + Common::Point pointer_pos; /**< Mouse pointer coordinates */ - rect_t clip_zone_unscaled; /* The current UNSCALED clipping zone */ - rect_t clip_zone; /* The current SCALED clipping zone; a cached scaled version of clip_zone_unscaled */ + rect_t clip_zone_unscaled; /**< The current UNSCALED clipping zone */ + rect_t clip_zone; /**< The current SCALED clipping zone; a cached scaled version of clip_zone_unscaled */ GfxDriver *driver; @@ -104,543 +104,640 @@ struct GfxState { GfxResManager *gfxResMan; - gfx_pixmap_t *priority_map; /* back buffer priority map (unscaled) */ - gfx_pixmap_t *static_priority_map; /* static buffer priority map (unscaled) */ - gfx_pixmap_t *control_map; /* back buffer control map (only exists unscaled in the first place) */ + gfx_pixmap_t *priority_map; /**< back buffer priority map (unscaled) */ + gfx_pixmap_t *static_priority_map; /**< static buffer priority map (unscaled) */ + gfx_pixmap_t *control_map; /**< back buffer control map (only exists unscaled in the first place) */ - int tag_mode; /* Set to 1 after a new pic is drawn and the resource manager - ** has tagged all resources. Reset after the next front buffer - ** update is done, when all resources that are still tagged are - ** flushed. */ + int tag_mode; /**< Set to 1 after a new pic is drawn and the resource manager has tagged all resources. Reset after the next front buffer update is done, when all resources that are still tagged are flushed. */ - int disable_dirty; /* Set to 1 to disable dirty rect accounting */ + int disable_dirty; /**< Set to 1 to disable dirty rect accounting */ - int pic_nr; /* Number of the current pic */ - int palette_nr; /* Palette number of the current pic */ + int pic_nr; /**< Number of the current pic */ + int palette_nr; /**< Palette number of the current pic */ Common::List<sci_event_t> _events; - gfx_pixmap_t *fullscreen_override; /* An optional override picture which must have unscaled - ** full-screen size, which overrides all other visibility, and - ** which is generally slow */ + gfx_pixmap_t *fullscreen_override; /**< An optional override picture which must have unscaled full-screen size, which overrides all other visibility, and which is generally slow */ - gfxr_pic_t *pic, *pic_unscaled; /* The background picture and its unscaled equivalent */ - rect_t pic_port_bounds; /* Picture port bounds */ + gfxr_pic_t *pic, *pic_unscaled; /**< The background picture and its unscaled equivalent */ + rect_t pic_port_bounds; /**< Picture port bounds */ - DirtyRectList _dirtyRects; /* Dirty rectangles */ + DirtyRectList _dirtyRects; /**< Dirty rectangles */ }; -/**************************/ -/* Fundamental operations */ -/**************************/ - -int gfxop_init(int version, bool isVGA, GfxState *state, gfx_options_t *options, ResourceManager *resManager, - int xfact = 1, int yfact = 1, gfx_color_mode_t bpp = GFX_COLOR_MODE_INDEX); -/* Initializes a graphics mode -** Parameters: (int) version: The interpreter version -** (GfxState *) state: The state to initialize -** (int x int) xfact, yfact: Horizontal and vertical scale factors -** (gfx_color_mode_t) bpp: Bytes per pixel to initialize with, or -** 0 (GFX_COLOR_MODE_AUTO) to auto-detect -** (gfx_options_t *) options: Rendering options -** (void *) misc_info: Additional information for the interpreter -** part of the resource loader -** Returns : (int) GFX_OK on success, GFX_ERROR if that particular mode is -** unavailable, or GFX_FATAL if the graphics driver is unable -** to provide any useful graphics support -*/ +/** @name Fundamental operations */ +/** @{ */ + +/** + * Initializes a graphics mode. + * + * @param[in] version The interpreter version + * @param[in] isVGA true if using VGA resolution + * @param[in] state The state to initialize + * @param[in] xfact Horizontal scale factor + * @param[in] yfact Vertical scale factors + * @param[in] bpp Bytes per pixel to initialize with, or 0 + * (GFX_COLOR_MODE_AUTO) to auto-detect + * @param[in] options Rendering options + * @param[in] resManager Resource manager to use + * @return GFX_OK on success, GFX_ERROR if that particular mode + * is unavailable, or GFX_FATAL if the graphics driver + * is unable to provide any useful graphics support + */ +int gfxop_init(int version, bool isVGA, GfxState *state, gfx_options_t *options, + ResourceManager *resManager, int xfact = 1, int yfact = 1, + gfx_color_mode_t bpp = GFX_COLOR_MODE_INDEX); + +/** + * Deinitializes a currently active driver. + * + * @param[in] state The state encapsulating the driver in question + * @return GFX_OK + */ int gfxop_exit(GfxState *state); -/* Deinitializes a currently active driver -** Parameters: (GfxState *) state: The state encapsulating the driver in question -** Returns : (int) GFX_OK -*/ +/** + * Calculates a bit mask calculated from some pixels on the specified + * map. + * + * @param[in] state The state containing the pixels to scan + * @param[in] area The area to check + * @param[in] map The GFX_MASKed map(s) to test + * @return An integer value where, for each 0 <= i <= 15, bit i is set + * iff there exists a map for which the corresponding bit was + * set in the 'map' parameter and for which there exists a + * pixel within the specified area so that the pixel's lower 4 + * bits, interpreted as an integer value, equal i. (Short + * version: This is an implementation of "on_control()"). + */ int gfxop_scan_bitmask(GfxState *state, rect_t area, gfx_map_mask_t map); -/* Calculates a bit mask calculated from some pixels on the specified map -** Parameters: (GfxState *) state: The state containing the pixels to scan -** (rect_t) area: The area to check -** (gfx_map_mask_t) map: The GFX_MASKed map(s) to test -** Returns : (int) An integer value where, for each 0<=i<=15, bit #i is set -** iff there exists a map for which the corresponding bit was set -** in the 'map' parameter and for which there exists a pixel within -** the specified area so that the pixel's lower 4 bits, interpreted -** as an integer value, equal i. -** (Short version: This is an implementation of "on_control()"). -*/ +/** + * Sets the currently visible map. + * + * 'visible_map' can be any of GFX_MASK_VISUAL, GFX_MASK_PRIORITY and + * GFX_MASK_CONTROL; the appropriate map (as far as its contents are known to + * the graphics subsystem) is then subsequently drawn to the screen at each + * update. If this is set to anything other than GFX_MASK_VISUAL, slow + * full-screen updates are performed. Mostly useful for debugging. The screen + * needs to be updated for the changes to take effect. + * + * @param[in] state The state to modify + * @param[in] map The GFX_MASK to set + * @return GFX_OK, or GFX_ERROR if map was invalid + */ int gfxop_set_visible_map(GfxState *state, gfx_map_mask_t map); -/* Sets the currently visible map -** Parameters: (GfxState *) state: The state to modify -** (gfx_map_mask_t) map: The GFX_MASK to set -** Returns : (int) GFX_OK, or GFX_ERROR if map was invalid -** 'visible_map' can be any of GFX_MASK_VISUAL, GFX_MASK_PRIORITY and GFX_MASK_CONTROL; the appropriate -** map (as far as its contents are known to the graphics subsystem) is then subsequently drawn to the -** screen at each update. If this is set to anything other than GFX_MASK_VISUAL, slow full-screen updates -** are performed. Mostly useful for debugging. -** The screen needs to be updated for the changes to take effect. -*/ +/** + * Sets a new clipping zone. + * + * @param[in] state The affected state + * @param[in] zone The new clipping zone + * @return GFX_OK + */ int gfxop_set_clip_zone(GfxState *state, rect_t zone); -/* Sets a new clipping zone -** Parameters: (GfxState *) state: The affected state -** (rect_t) zone: The new clipping zone -** Returns : (int) GFX_OK -*/ +/** @} */ + -/******************************/ -/* Generic drawing operations */ -/******************************/ +/** @name Generic drawing operations */ +/** @{ */ +/** + * Renders a clipped line to the back buffer. + * + * @param[in] state The state affected + * @param[in] start Starting point of the line + * @param[in] end End point of the line + * @param[in] color The color to use for drawing + * @param[in] line_mode Any valid line mode to use + * @param[in] line_style The line style to use + * @return GFX_OK or GFX_FATAL + */ int gfxop_draw_line(GfxState *state, Common::Point start, Common::Point end, gfx_color_t color, gfx_line_mode_t line_mode, gfx_line_style_t line_style); -/* Renders a clipped line to the back buffer -** Parameters: (GfxState *) state: The state affected -** (Common::Point) start: Starting point of the line -** (Common::Point) end: End point of the line -** (gfx_color_t) color: The color to use for drawing -** (gfx_line_mode_t) line_mode: Any valid line mode to use -** (gfx_line_style_t) line_style: The line style to use -** Returns : (int) GFX_OK or GFX_FATAL -*/ -int gfxop_draw_rectangle(GfxState *state, rect_t rect, gfx_color_t color, gfx_line_mode_t line_mode, - gfx_line_style_t line_style); -/* Draws a non-filled rectangular box to the back buffer -** Parameters: (GfxState *) state: The affected state -** (rect_t) rect: The rectangular area the box is drawn to -** (gfx_color_t) color: The color the box is to be drawn in -** (gfx_line_mode_t) line_mode: The line mode to use -** (gfx_line_style_t) line_style: The line style to use for the box -** Returns : (int) GFX_OK or GFX_FATAL -** Boxes drawn in thin lines will surround the minimal area described by rect. -*/ +/** + * Draws a non-filled rectangular box to the back buffer. + * + * Boxes drawn in thin lines will surround the minimal area described by rect. + * + * @param[in] state The affected state + * @param[in] rect The rectangular area the box is drawn to + * @param[in] color The color the box is to be drawn in + * @param[in] line_mode The line mode to use + * @param[in] line_style The line style to use for the box + * @return GFX_OK or GFX_FATAL + */ +int gfxop_draw_rectangle(GfxState *state, rect_t rect, gfx_color_t color, + gfx_line_mode_t line_mode, gfx_line_style_t line_style); -int gfxop_draw_box(GfxState *state, rect_t box, gfx_color_t color1, gfx_color_t color2, - gfx_box_shade_t shade_type); -/* Draws a filled box to the back buffer -** Parameters: (GfxState *) state: The affected state -** (rect_t) box: The area to draw to -** (gfx_color_t) color1: The primary color to use for drawing -** (gfx_color_t) color2: The secondary color to draw in -** (gfx_box_shade_t) shade_type: The shading system to use -** (e.g. GFX_BOX_SHADE_FLAT) -** Returns : (int) GFX_OK or GFX_FATAL -** The draw mask, control, and priority values are derived from color1. -*/ +/** + * Draws a filled box to the back buffer. + * + * The draw mask, control, and priority values are derived from color1. + * + * @param[in] state The affected state + * @param[in] box The area to draw to + * @param[in] color1 The primary color to use for drawing + * @param[in] color2 The secondary color to draw in + * @param[in] shade_type The shading system to use (e.g. GFX_BOX_SHADE_FLAT) + * @return GFX_OK or GFX_FATAL + */ +int gfxop_draw_box(GfxState *state, rect_t box, gfx_color_t color1, + gfx_color_t color2, gfx_box_shade_t shade_type); +/** + * Fills a box in the back buffer with a specific color. + * + * This is a simple wrapper function for gfxop_draw_box + * + * @param[in] state The state to draw to + * @param[in] box The box to fill + * @param[in] color The color to use for filling + * @return GFX_OK or GFX_FATAL + */ int gfxop_fill_box(GfxState *state, rect_t box, gfx_color_t color); -/* Fills a box in the back buffer with a specific color -** Parameters: (GfxState *) state: The state to draw to -** (rect_t) box: The box to fill -** (gfx_color_t) color: The color to use for filling -** Returns : (int) GFX_OK or GFX_FATAL -** This is a simple wrapper function for gfxop_draw_box -*/ +/** + * Copies a box from the static buffer to the back buffer. + * + * @param[in] state The affected state + * @param[in] box The box to propagate from the static buffer + * @return GFX_OK or GFX_FATAL + */ int gfxop_clear_box(GfxState *state, rect_t box); -/* Copies a box from the static buffer to the back buffer -** Parameters: (GfxState *) state: The affected state -** (rect_t) box: The box to propagate from the static buffer -** Returns : (int) GFX_OK or GFX_FATAL -*/ +/** + * Updates all dirty rectangles. + * + * In order to track dirty rectangles, they must be enabled in the options. This + * function instructs the resource manager to free all tagged data on certain + * occasions (see gfxop_new_pic). + * + * @param[in] state The relevant state + * @return GFX_OK or GFX_FATAL if reported by the driver + */ int gfxop_update(GfxState *state); -/* Updates all dirty rectangles -** Parameters: (GfxState) *state: The relevant state -** Returns : (int) GFX_OK or GFX_FATAL if reported by the driver -** In order to track dirty rectangles, they must be enabled in the options. -** This function instructs the resource manager to free all tagged data -** on certain occasions (see gfxop_new_pic). -*/ +/** + * Propagates a box from the back buffer to the front (visible) buffer. + * + * This function instructs the resource manager to free all tagged data on + * certain occasions (see gfxop_new_pic). When called with dirty rectangle + * management enabled, it will automatically propagate all dirty rectangles as + * well, UNLESS dirty frame accounting has been disabled explicitly. + * + * @param[in] state The affected state + * @param[in] box The box to propagate to the front buffer + * @return GFX_OK or GFX_FATAL + */ int gfxop_update_box(GfxState *state, rect_t box); -/* Propagates a box from the back buffer to the front (visible) buffer -** Parameters: (GfxState *) state: The affected state -** (rect_t) box: The box to propagate to the front buffer -** Returns : (int) GFX_OK or GFX_FATAL -** This function instructs the resource manager to free all tagged data -** on certain occasions (see gfxop_new_pic). -** When called with dirty rectangle management enabled, it will automatically -** propagate all dirty rectangles as well, UNLESS dirty frame accounting has -** been disabled explicitly. -*/ +/** + * Enables dirty frame accounting. + * + * Dirty frame accounting is enabled by default. + * + * @param[in] state The state dirty frame accounting is to be enabled in + * @return GFX_OK or GFX_ERROR if state was invalid + */ int gfxop_enable_dirty_frames(GfxState *state); -/* Enables dirty frame accounting -** Parameters: (GfxState *) state: The state dirty frame accounting is to be enabled in -** Returns : (int) GFX_OK or GFX_ERROR if state was invalid -** Dirty frame accounting is enabled by default. -*/ +/** + * Disables dirty frame accounting. + * + * @param[in] state The state dirty frame accounting is to be disabled in + * @return GFX_OK or GFX_ERROR if state was invalid + */ int gfxop_disable_dirty_frames(GfxState *state); -/* Disables dirty frame accounting -** Parameters: (GfxState *) state: The state dirty frame accounting is to be disabled in -** Returns : (int) GFX_OK or GFX_ERROR if state was invalid -*/ +/** @} */ -/********************/ -/* Color operations */ -/********************/ - -int gfxop_set_color(GfxState *state, gfx_color_t *color, int r, int g, int b, int a, - int priority, int control); -/* Maps an r/g/b value to a color and sets a gfx_color_t structure -** Parameters: (GfxState *) state: The current state -** (gfx_color_t *) color: Pointer to the structure to write to -** (int x int x int) r,g,b: The red/green/blue color intensity values -** of the result color (0x00 (minimum) to 0xff (max)) -** If any of these values is less than zero, the -** resulting color will not affect the visual map when -** used for drawing -** (int) a: The alpha (transparency) value, with 0x00 meaning absolutely -** opaque and 0xff meaning fully transparent. Alpha blending support -** is optional for drivers, so these are the only two values that -** are guaranteed to work as intended. Any value in between them -** must guarantee the following opaqueness: -** opaqueness(x-1) >= opaqueness(x) >= opaqueness (x+1) -** (i.e. ([0,255], less-transparent-than) must define a partial order) -** (int) priority: The priority to use for drawing, or -1 for none -** (int) control: The control to use for drawing, or -1 to disable drawing to the -** control map -** Returns : (int) GFX_OK or GFX_ERROR if state is invalid -** In palette mode, this may allocate a new color. Use gfxop_free_color() described below to -** free that color. -*/ +/** @name Color operations */ +/** @{ */ + +/** + * Maps an r/g/b value to a color and sets a gfx_color_t structure. + * + * In palette mode, this may allocate a new color. Use gfxop_free_color() to + * free that color. If any of the r/g/b values are less than zero, the resulting + * color will not affect the visual map when used for drawing + * + * @param[in] state The current state + * @param[in] color Pointer to the structure to write to + * @param[in] r The red color intensity values of the result color + * @param[in] g The green color intensity values of the result color + * @param[in] b The blue color intensity values of the result color + * @param[in] a The alpha (transparency) value, with 0x00 meaning + * absolutely opaque and 0xff meaning fully transparent. + * Alpha blending support is optional for drivers, so these + * are the only two values that are guaranteed to work as + * intended. Any value in between them must guarantee the + * following opaqueness: opaqueness(x-1) >= opaqueness(x) + * >= opaqueness (x+1) (i.e. ([0,255], + * less-transparent-than) must define a partial order) + * @param[in] priority The priority to use for drawing, or -1 for none + * @param[in] control The control to use for drawing, or -1 to disable drawing + * to the control map + * @return GFX_OK or GFX_ERROR if state is invalid + */ +int gfxop_set_color(GfxState *state, gfx_color_t *color, int r, int g, int b, + int a, int priority, int control); +/** + * Designates a color as a 'system color'. + * + * system colors are permanent colors that cannot be deallocated. as such, they must be used with caution. + * + * @param[in] state The affected state + * @param[in] index The index for the new system color + * @param[in] color The color to designate as a system color + * @return GFX_OK or GFX_ERROR if state is invalid + */ int gfxop_set_system_color(GfxState *state, unsigned int index, gfx_color_t *color); -/* Designates a color as a 'system color' -** Parameters: (GfxState *) state: The affected state -** (unsigned int) index: The index for the new system color -** (gfx_color_t *) color: The color to designate as a system color -** Returns : (int) GFX_OK or GFX_ERROR if state is invalid -** System colors are permanent colors that cannot be deallocated. As such, they must be used -** with caution. -*/ +/** + * Frees a color allocated by gfxop_set_color(). + * + * This function is a no-op in non-index mode, or if color is a system color. + * + * @param[in] state The state affected + * @param[in] color The color to de-allocate + * @return GFX_OK or GFX_ERROR if state is invalid + */ int gfxop_free_color(GfxState *state, gfx_color_t *color); -/* Frees a color allocated by gfxop_set_color() -** Parmaeters: (GfxState *) state: The state affected -** (gfx_color_t *) color: The color to de-allocate -** Returns : (int) GFX_OK or GFX_ERROR if state is invalid -** This function is a no-op in non-index mode, or if color is a system color. -*/ - +/** @} */ -/**********************/ -/* Pointer and IO ops */ -/**********************/ +/** @name Pointer and IO ops */ +/** @{ */ +/** + * Suspends program execution for the specified amount of milliseconds. + * + * The mouse pointer will be redrawn continually, if applicable + * + * @param[in] state The state affected + * @param[in] msecs The amount of milliseconds to wait + * @return GFX_OK or GFX_ERROR + */ int gfxop_sleep(GfxState *state, uint32 msecs); -/* Suspends program execution for the specified amount of milliseconds -** Parameters: (GfxState *) state: The state affected -** (uint32) usecs: The amount of milliseconds to wait -** Returns : (int) GFX_OK or GFX_ERROR -** The mouse pointer will be redrawn continually, if applicable -*/ +/** + * Sets the mouse pointer to a cursor resource. + * + * @param[in] state The affected state + * @param[in] nr Number of the cursor resource to use + * @return GFX_OK, GFX_ERROR if the resource did not exist and was not + * GFXOP_NO_POINTER, or GFX_FATAL on fatal error conditions. + * Use nr = GFX_NO_POINTER to disable the mouse pointer + * (default). + */ int gfxop_set_pointer_cursor(GfxState *state, int nr); -/* Sets the mouse pointer to a cursor resource -** Parameters: (GfxState *) state: The affected state -** (int) nr: Number of the cursor resource to use -** Returns : (int) GFX_OK, GFX_ERROR if the resource did not -** exist and was not GFXOP_NO_POINTER, or GFX_FATAL on -** fatal error conditions. -** Use nr = GFX_NO_POINTER to disable the mouse pointer (default). -*/ +/** + * Sets the mouse pointer to a view resource. + * + * Use gfxop_set_pointer_cursor(state, GFXOP_NO_POINTER) to disable the pointer. + * + * @param[in] state The affected state + * @param[in] nr Number of the view resource to use + * @param[in] loop View loop to use + * @param[in] cel View cel to use + * @param[in] hotspot Manually set hotspot to use, or NULL for default. + * @return GFX_OK or GFX_FATAL + */ int gfxop_set_pointer_view(GfxState *state, int nr, int loop, int cel, Common::Point *hotspot); -/* Sets the mouse pointer to a view resource -** Parameters: (GfxState *) state: The affected state -** (int) nr: Number of the view resource to use -** (int) loop: View loop to use -** (int) cel: View cel to use -** (Common::Point *) hotspot: Manually set hotspot to use, or NULL for default. -** Returns : (int) GFX_OK or GFX_FATAL -** Use gfxop_set_pointer_cursor(state, GFXOP_NO_POINTER) to disable the -** pointer. -*/ +/** + * Teleports the mouse pointer to a specific position. + * + * Depending on the graphics driver, this operation may be without any effect + * + * @param[in] state The state the pointer is in + * @param[in] pos The position to teleport it to + * @return Any error code or GFX_OK + */ int gfxop_set_pointer_position(GfxState *state, Common::Point pos); -/* Teleports the mouse pointer to a specific position -** Parameters: (GfxState *) state: The state the pointer is in -** (Common::Point) pos: The position to teleport it to -** Returns : (int) Any error code or GFX_OK -** Depending on the graphics driver, this operation may be without -** any effect -*/ +/** + * Retrieves the next input event from the driver. + * + * @param[in] state The affected state + * @param[in] mask The event mask to poll from (see uinput.h) + * @return The next event in the driver's event queue, or a NONE event + * if no event matching the mask was found. + */ sci_event_t gfxop_get_event(GfxState *state, unsigned int mask); -/* Retrieves the next input event from the driver -** Parameters: (GfxState *) state: The affected state -** (int) mask: The event mask to poll from (see uinput.h) -** Returns : (sci_event_t) The next event in the driver's event queue, or -** a NONE event if no event matching the mask was found. -*/ +/** @} */ +/** @name View operations */ +/** @{ */ -/*******************/ -/* View operations */ -/*******************/ - +/** + * Determines the number of loops associated with a view. + * + * @param[in] state The state to use + * @param[in] nr Number of the view to investigate + * @return The number of loops, or GFX_ERROR if the view didn't exist + */ int gfxop_lookup_view_get_loops(GfxState *state, int nr); -/* Determines the number of loops associated with a view -** Parameters: (GfxState *) state: The state to use -** (int) nr: Number of the view to investigate -** Returns : (int) The number of loops, or GFX_ERROR if the view didn't exist -*/ +/** + * Determines the number of cels associated stored in a loop. + * + * @param[in] state The state to look up in + * @param[in] nr Number of the view to look up in + * @param[in] loop Number of the loop the number of cels of are to be + * investigated + * @return The number of cels in that loop, or GFX_ERROR if either the + * view or the loop didn't exist + */ int gfxop_lookup_view_get_cels(GfxState *state, int nr, int loop); -/* Determines the number of cels associated stored in a loop -** Parameters: (GfxState *) state: The state to look up in -** (int) nr: Number of the view to look up in -** (int) loop: Number of the loop the number of cels of -** are to be investigated -** Returns : (int) The number of cels in that loop, or GFX_ERROR if either -** the view or the loop didn't exist -*/ +/** + * Clips the view/loop/cel position of a cel. + * + * *loop is clipped first, then *cel. The resulting setup will be a valid view + * configuration. + * + * @param[in] state The state to use + * @param[in] nr Number of the view to use + * @param[in] loop Pointer to the variable storing the loop number to verify + * @param[in] cel Pointer to the variable storing the cel number to check + * @return GFX_OK or GFX_ERROR if the view didn't exist + */ int gfxop_check_cel(GfxState *state, int nr, int *loop, int *cel); -/* Clips the view/loop/cel position of a cel -** Parameters: (GfxState *) state: The state to use -** (int) nr: Number of the view to use -** (int *) loop: Pointer to the variable storing the loop -** number to verify -** (int *) cel: Pointer to the variable storing the cel -** number to check -** Returns : (int) GFX_OK or GFX_ERROR if the view didn't exist -** *loop is clipped first, then *cel. The resulting setup will be a valid -** view configuration. -*/ +/** + * Resets loop/cel values to zero if they have become invalid. + * + * @param[in] state The state to use + * @param[in] nr Number of the view to use + * @param[in] loop Pointer to the variable storing the loop number to verify + * @param[in] cel Pointer to the variable storing the cel number to check + * @return GFX_OK or GFX_ERROR if the view didn't exist *loop is + * clipped first, then *cel. The resulting setup will be a + * valid view configuration. + */ int gfxop_overflow_cel(GfxState *state, int nr, int *loop, int *cel); -/* Resets loop/cel values to zero if they have become invalid -** Parameters: (GfxState *) state: The state to use -** (int) nr: Number of the view to use -** (int *) loop: Pointer to the variable storing the loop -** number to verify -** (int *) cel: Pointer to the variable storing the cel -** number to check -** Returns : (int) GFX_OK or GFX_ERROR if the view didn't exist -** *loop is clipped first, then *cel. The resulting setup will be a valid -** view configuration. -*/ +/** + * Retrieves the width and height of a cel. + * + * @param[in] state The state to use + * @param[in] nr Number of the view + * @param[in] loop Loop number to examine + * @param[in] cel The cel (inside the loop) to look up + * @param[in] width The variable the width will be stored in + * @param[in] height The variable the height will be stored in + * @param[in] offset The variable the cel's x/y offset will be stored in + * @return GFX_OK if the lookup succeeded, GFX_ERROR if the + * nr/loop/cel combination was invalid + */ int gfxop_get_cel_parameters(GfxState *state, int nr, int loop, int cel, int *width, int *height, Common::Point *offset); -/* Retrieves the width and height of a cel -** Parameters: (GfxState *) state: The state to use -** (int) nr: Number of the view -** (int) loop: Loop number to examine -** (int) cel: The cel (inside the loop) to look up -** (int *) width: The variable the width will be stored in -** (int *) height: The variable the height will be stored in -** (Common::Point *) offset: The variable the cel's x/y offset will be stored in -** Returns : (int) GFX_OK if the lookup succeeded, GFX_ERROR if the nr/loop/cel -** combination was invalid -*/ -int gfxop_draw_cel(GfxState *state, int nr, int loop, int cel, Common::Point pos, - gfx_color_t color, int palette); -/* Draws (part of) a cel to the back buffer -** Parameters: (GfxState *) state: The state encapsulating the driver to draw with -** (int) nr: Number of the view to draw -** (int) loop: Loop of the cel to draw -** (int) cel: The cel number of the cel to draw -** (Common::Point) pos: The positino the cel is to be drawn to -** (gfx_color_t color): The priority and control values to use for drawing -** (int) palette: The palette to use -** Returns : (int) GFX_OK or GFX_FATAL -*/ +/** + * Draws (part of) a cel to the back buffer. + * + * @param[in] state The state encapsulating the driver to draw with + * @param[in] nr Number of the view to draw + * @param[in] loop Loop of the cel to draw + * @param[in] cel The cel number of the cel to draw + * @param[in] pos The positino the cel is to be drawn to + * @param[in] color The priority and control values to use for drawing + * @param[in] palette The palette to use + * @return GFX_OK or GFX_FATAL + */ +int gfxop_draw_cel(GfxState *state, int nr, int loop, int cel, + Common::Point pos, gfx_color_t color, int palette); -int gfxop_draw_cel_static(GfxState *state, int nr, int loop, int cel, Common::Point pos, - gfx_color_t color, int palette); -/* Draws a cel to the static buffer; no clipping is performed -** Parameters: (GfxState *) state: The state encapsulating the driver to draw with -** (int) nr: Number of the view to draw -** (int) loop: Loop of the cel to draw -** (int) cel: The cel number of the cel to draw -** (Common::Point) pos: The positino the cel is to be drawn to -** (gfx_color_t color): The priority and control values to use for drawing -** (int) palette: The palette to use -** Returns : (int) GFX_OK or GFX_FATAL -** Let me repeat, no clipping (except for the display borders) is performed. -*/ +/** + * Draws a cel to the static buffer; no clipping is performed. + * + * No clipping (except for the display borders) is performed. + * + * @param[in] state The state encapsulating the driver to draw with + * @param[in] nr Number of the view to draw + * @param[in] loop Loop of the cel to draw + * @param[in] cel The cel number of the cel to draw + * @param[in] pos The positino the cel is to be drawn to + * @param[in] color The priority and control values to use for drawing + * @param[in] palette The palette to use + * @return GFX_OK or GFX_FATAL + */ +int gfxop_draw_cel_static(GfxState *state, int nr, int loop, int cel, + Common::Point pos, gfx_color_t color, int palette); -int gfxop_draw_cel_static_clipped(GfxState *state, int nr, int loop, int cel, Common::Point pos, - gfx_color_t color, int palette); -/* Draws (part of) a clipped cel to the static buffer -** Parameters: (GfxState *) state: The state encapsulating the driver to draw with -** (int) nr: Number of the view to draw -** (int) loop: Loop of the cel to draw -** (int) cel: The cel number of the cel to draw -** (Common::Point) pos: The positino the cel is to be drawn to -** (gfx_color_t color): The priority and control values to use for drawing -** (int) palette: The palette to use -** Returns : (int) GFX_OK or GFX_FATAL -** This function does clip. -*/ +/** + * Draws (part of) a clipped cel to the static buffer. + * + * This function does clip. + * + * @param[in] state The state encapsulating the driver to draw with + * @param[in] nr Number of the view to draw + * @param[in] loop Loop of the cel to draw + * @param[in] cel The cel number of the cel to draw + * @param[in] pos The positino the cel is to be drawn to + * @param[in] color The priority and control values to use for drawing + * @param[in] palette The palette to use + * @return GFX_OK or GFX_FATAL + */ +int gfxop_draw_cel_static_clipped(GfxState *state, int nr, int loop, int cel, + Common::Point pos, gfx_color_t color, int palette); +/** @} */ -/******************/ -/* Pic operations */ -/******************/ -/* These operations are exempt from clipping */ +/** @name Pic operations + * These operations are exempt from clipping */ +/** @{ */ +/** + * Draws a pic and writes it over the static buffer. + * + * This function instructs the resource manager to tag all data as "unused". + * See the resource manager tag functions for a full description. + * + * @param[in] state The state affected + * @param[in] nr Number of the pic to draw + * @param[in] flags Interpreter-dependant flags to use for drawing + * @param[in] default_palette The default palette for drawing + * @return GFX_OK or GFX_FATAL + */ int gfxop_new_pic(GfxState *state, int nr, int flags, int default_palette); -/* Draws a pic and writes it over the static buffer -** Parameters: (GfxState *) state: The state affected -** (int) nr: Number of the pic to draw -** (int) flags: Interpreter-dependant flags to use for drawing -** (int) default_palette: The default palette for drawing -** Returns : (int) GFX_OK or GFX_FATAL -** This function instructs the resource manager to tag all data as "unused". -** See the resource manager tag functions for a full description. -*/ +/** + * Retrieves all meta-information assigned to the current pic. + * + * @param[in] state The state affected + * @return NULL if the pic doesn't exist or has no meta-information, + * the meta-info otherwise. This meta-information is referred + * to as 'internal data' in the pic code + */ int *gfxop_get_pic_metainfo(GfxState *state); -/* Retrieves all meta-information assigned to the current pic -** Parameters: (GfxState *) state: The state affected -** Returns : (int *) NULL if the pic doesn't exist or has no meta-information, -** the meta-info otherwise -** This meta-information is referred to as 'internal data' in the pic code -*/ +/** + * Adds a pic to the static buffer. + * + * @param[in] state The state affected + * @param[in] nr Number of the pic to add + * @param[in] flags Interpreter-dependant flags to use for drawing + * @param[in] default_palette The default palette for drawing + * @return GFX_OK or GFX_FATAL + */ int gfxop_add_to_pic(GfxState *state, int nr, int flags, int default_palette); -/* Adds a pic to the static buffer -** Parameters: (GfxState *) state: The state affected -** (int) nr: Number of the pic to add -** (int) flags: Interpreter-dependant flags to use for drawing -** (int) default_palette: The default palette for drawing -** Returns : (int) GFX_OK or GFX_FATAL -*/ - +/** @} */ +/** @name Text operations */ +/** @{ */ -/*******************/ -/* Text operations */ -/*******************/ - - +/** + * Returns the fixed line height for one specified font. + * + * @param[in] state The state to work on + * @param[in] font_nr Number of the font to inspect + * @return GFX_ERROR, GFX_FATAL, or the font line height + */ int gfxop_get_font_height(GfxState *state, int font_nr); -/* Returns the fixed line height for one specified font -** Parameters: (GfxState *) state: The state to work on -** (int) font_nr: Number of the font to inspect -** Returns : (int) GFX_ERROR, GFX_FATAL, or the font line height -*/ +/** + * Calculates the width and height of a specified text in a specified + * font. + * + * @param[in] state The state to use + * @param[in] font_nr Font number to use for the calculation + * @param[in] text The text to examine + * @param[in] flags ORred GFXR_FONT_FLAGs + * @param[in] maxwidth The maximum pixel width to allow for the text + * @param[out] width The resulting width + * @param[out] height The resulting height + * @param[out] lines_nr Number of lines used in the text + * @param[out] lineheight Pixel height (SCI scale) of each text line + * @param[out] lastline_width Pixel offset (SCI scale) of the space after + * the last character in the last line + * @return GFX_OK or GFX_ERROR if the font didn't exist + */ int gfxop_get_text_params(GfxState *state, int font_nr, const char *text, int maxwidth, int *width, int *height, int flags, int *lines_nr, int *lineheight, int *lastline_width); -/* Calculates the width and height of a specified text in a specified font -** Parameters: (GfxState *) state: The state to use -** (int) font_nr: Font number to use for the calculation -** (const char *) text: The text to examine -** (int) flags: ORred GFXR_FONT_FLAGs -** (int) maxwidth: The maximum pixel width to allow for the text -** Returns : (int) GFX_OK or GFX_ERROR if the font didn't exist -** (int) *width: The resulting width -** (int) *height: The resulting height -** (int) *lines_nr: Number of lines used in the text -** (int) *lineheight: Pixel height (SCI scale) of each text line -** (int) *lastline_wdith: Pixel offset (SCI scale) of the space -** after the last character in the last line -*/ -TextHandle *gfxop_new_text(GfxState *state, int font_nr, const Common::String &text, int maxwidth, - gfx_alignment_t halign, gfx_alignment_t valign, gfx_color_t color1, - gfx_color_t color2, gfx_color_t bg_color, int flags); -/* Generates a new text handle that can be used to draw any text -** Parameters: (GfxState *) state: The state to use -** (int) font_nr: Font number to use for the calculation -** (const char *) text: The text to examine -** (int) maxwidth: The maximum pixel width to allow for the text -** (gfx_alignment_t) halign: The horizontal text alignment -** (gfx_alignment_t) valign: The vertical text alignment -** (gfx_color_t x gfx_color_t) color1, color2: The text's foreground colors -** (the function will dither between those two) -** (gfx_color_t) bg_color: The background color -** (int) flags: ORred GFXR_FONT_FLAGs -** Returns : (TextHandle *) A newly allocated TextHandle, or -** NULL if font_nr was invalid -** The control and priority values for the text will be extracted from color1. -** Note that the colors must have been allocated properly, or the text may display in -** incorrect colors. -*/ +/** + * Generates a new text handle that can be used to draw any text. + * + * The control and priority values for the text will be extracted from color1. + * Note that the colors must have been allocated properly, or the text may + * display in incorrect colors. + * + * @param[in] state The state to use + * @param[in] font_nr Font number to use for the calculation + * @param[in] text The text to examine + * @param[in] maxwidth: The maximum pixel width to allow for the text + * @param[in] halign The horizontal text alignment + * @param[in] valign The vertical text alignment + * @param[in] color1 The text's foreground colors (the function will dither + * between color1 and 2) + * @param[in] color2 The text's foreground colors (the function will dither + * between color1 and 2) + * @param[in] bg_color The background color + * @param[in] flags ORred GFXR_FONT_FLAGs + * @return A newly allocated TextHandle, or NULL if font_nr was + * invalid + */ +TextHandle *gfxop_new_text(GfxState *state, int font_nr, + const Common::String &text, int maxwidth, gfx_alignment_t halign, + gfx_alignment_t valign, gfx_color_t color1, gfx_color_t color2, + gfx_color_t bg_color, int flags); +/** + * Frees a previously allocated text handle and all related resources. + * + * @param[in] state The state to use + * @param[in] handle The handle to free + * @return GFX_OK + */ int gfxop_free_text(GfxState *state, TextHandle *handle); -/* Frees a previously allocated text handle and all related resources -** Parameters: (GfxState *) state: The state to use -** (TextHandle *) handle: The handle to free -** Returns : (int) GFX_OK -*/ +/** + * Draws text stored in a text handle. + * + * @param[in] state The target state + * @param[in] handle The text handle to use for drawing + * @param[in] zone The rectangular box to draw to. In combination with + * halign and valign, this defines where the text is drawn + * to. + * @return GFX_OK or GFX_FATAL + */ int gfxop_draw_text(GfxState *state, TextHandle *handle, rect_t zone); -/* Draws text stored in a text handle -** Parameters: (GfxState *) state: The target state -** (TextHandle *) handle: The text handle to use for drawing -** (rect_t) zone: The rectangular box to draw to. In combination with -** halign and valign, this defines where the text is -** drawn to. -** Returns : (int) GFX_OK or GFX_FATAL -*/ +/** @} */ -/****************************/ -/* Manual pixmap operations */ -/****************************/ +/** @name Manual pixmap operations */ +/** @{ */ +/** + * Grabs a screen section from the back buffer and stores it in a pixmap. + * + * Obviously, this only affects the visual map + * + * @param[in] state The affected state + * @param[in] area The area to grab + * Returns A result pixmap, or NULL on error + */ gfx_pixmap_t *gfxop_grab_pixmap(GfxState *state, rect_t area); -/* Grabs a screen section from the back buffer and stores it in a pixmap -** Parameters: (GfxState *) state: The affected state -** (rect_t) area: The area to grab -** Returns : (gfx_pixmap_t *) A result pixmap, or NULL on error -** Obviously, this only affects the visual map -*/ -int gfxop_draw_pixmap(GfxState *state, gfx_pixmap_t *pxm, rect_t zone, Common::Point pos); -/* Draws part of a pixmap to the screen -** Parameters: (GfxState *) state: The affected state -** (gfx_pixmap_t *) pxm: The pixmap to draw -** (rect_t) zone: The segment of the pixmap to draw -** (Common::Point) pos: The position the pixmap should be drawn to -** Returns : (int) GFX_OK or any error code -*/ +/** + * Draws part of a pixmap to the screen. + * + * @param[in] state The affected state + * @param[in] pxm The pixmap to draw + * @param[in] zone The segment of the pixmap to draw + * @param[in] pos The position the pixmap should be drawn to + * @return GFX_OK or any error code + */ +int gfxop_draw_pixmap(GfxState *state, gfx_pixmap_t *pxm, rect_t zone, + Common::Point pos); +/** + * Frees a pixmap returned by gfxop_grab_pixmap(). + * + * @param[in] state The affected state + * @param[in] pxm The pixmap to free + * @return GFX_OK, or GFX_ERROR if the state was invalid + */ int gfxop_free_pixmap(GfxState *state, gfx_pixmap_t *pxm); -/* Frees a pixmap returned by gfxop_grab_pixmap() -** Parameters: (GfxState *) state: The affected state -** (gfx_pixmap_t *) pxm: The pixmap to free -** Returns : (int) GFX_OK, or GFX_ERROR if the state was invalid -*/ +/** @} */ -/******************************/ -/* Dirty rectangle operations */ -/******************************/ + +/** @name Dirty rectangle operations */ +/** @{ */ /** * Adds a dirty rectangle to 'base' according to a strategy. - * @param list the list to add to - * @param box the dirty frame to addable - * @param strategy the dirty frame heuristic to use (see gfx_options.h) + * + * @param[in] list the list to add to + * @param[in] box the dirty frame to addable + * @param[in] strategy the dirty frame heuristic to use (see gfx_options.h) */ void gfxdr_add_dirty(DirtyRectList &list, rect_t box, int strategy); +/** + * Clips a rectangle against another one. + * + * @param[in] rect The rectangle to clip + * @param[in] clipzone The outer bounds rect must be in + * @return 1 if rect is empty now, 0 otherwise + */ int _gfxop_clip(rect_t *rect, rect_t clipzone); -/* Clips a rectangle against another one -** Parameters: (rect_t *) rect: The rectangle to clip -** (rect_t) clipzone: The outer bounds rect must be in -** Reuturns : (int) 1 if rect is empty now, 0 otherwise -*/ +/** @} */ } // End of namespace Sci diff --git a/engines/sci/gfx/palette.h b/engines/sci/gfx/palette.h index 127871bce4..65d1cac18e 100644 --- a/engines/sci/gfx/palette.h +++ b/engines/sci/gfx/palette.h @@ -42,15 +42,18 @@ struct PaletteEntry { : r(R), g(G), b(B), parent_index(-1), refcount(PALENTRY_FREE) { } - // Color data + /** @name Color data */ + /** @{ */ byte r, g, b; + /** @} */ - // Index in parent palette, or -1 + /** Index in parent palette, or -1 */ int parent_index; - // Number of references from child palettes. (This includes palettes - // of pixmaps.) - // Special values: PALENTRY_LOCKED, PALENTRY_FREE + /** + * Number of references from child palettes. (This includes palettes + * of pixmaps.) + * Special values: PALENTRY_LOCKED, PALENTRY_FREE */ int refcount; }; @@ -98,10 +101,9 @@ private: Palette *_parent; - bool _dirty; // Palette has changed - int _refcount; // Number of pixmaps (or other objects) using this palette - int _revision; // When this is incremented, all child references are - // invalidated + bool _dirty; /**< Palette has changed */ + int _refcount; /**< Number of pixmaps (or other objects) using this palette */ + int _revision; /**< When this is incremented, all child references are invalidated */ }; diff --git a/engines/sci/gfx/res_pic.cpp b/engines/sci/gfx/res_pic.cpp index 762cb7b55d..5ee2665b50 100644 --- a/engines/sci/gfx/res_pic.cpp +++ b/engines/sci/gfx/res_pic.cpp @@ -152,7 +152,7 @@ void gfxr_init_static_palette() { } -gfxr_pic_t *gfxr_init_pic(gfx_mode_t *mode, int ID, int sci1) { +gfxr_pic_t *gfxr_init_pic(gfx_mode_t *mode, int ID, bool sci1) { gfxr_pic_t *pic = (gfxr_pic_t*)malloc(sizeof(gfxr_pic_t)); pic->mode = mode; diff --git a/engines/sci/gfx/res_view.cpp b/engines/sci/gfx/res_view.cpp index f282369e15..b30c57f38d 100644 --- a/engines/sci/gfx/res_view.cpp +++ b/engines/sci/gfx/res_view.cpp @@ -331,7 +331,7 @@ gfx_pixmap_t *gfxr_draw_cel1(int id, int loop, int cel, int mirrored, byte *reso int yl = READ_LE_UINT16(cel_base + 2); int pixmap_size = xl * yl; int xdisplace = isSci11 ? READ_LE_UINT16(cel_base + 4) : (int8) cel_base[4]; - int ydisplace = isSci11 ? READ_LE_UINT16(cel_base + 6) : (int8) cel_base[5]; + int ydisplace = isSci11 ? READ_LE_UINT16(cel_base + 6) : cel_base[5]; int runlength_offset = isSci11 ? READ_LE_UINT16(cel_base + 24) : 8; int literal_offset = isSci11 ? READ_LE_UINT16(cel_base + 28) : 8; gfx_pixmap_t *retval = gfx_pixmap_alloc_index_data(gfx_new_pixmap(xl, yl, id, loop, cel)); diff --git a/engines/sci/gfx/seq_decoder.h b/engines/sci/gfx/seq_decoder.h index 16574007fe..b9feadb5f3 100644 --- a/engines/sci/gfx/seq_decoder.h +++ b/engines/sci/gfx/seq_decoder.h @@ -28,6 +28,9 @@ namespace Sci { +/** + * Decoder for image sequences + */ class SeqDecoder { public: SeqDecoder() : _fileStream(0), _palette(0) { } @@ -37,7 +40,9 @@ public: gfx_pixmap_t *getFrame(bool &hasNext); private: - bool decodeFrame(byte *runlength_data, int runlength_size, byte *literal_data, int literal_size, byte *dest, int xl, int yl, int color_key); + bool decodeFrame(byte *runlength_data, int runlength_size, + byte *literal_data, int literal_size, byte *dest, int xl, int yl, + int color_key); Common::SeekableReadStream *_fileStream; Palette *_palette; diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp index 5edf1b7145..3c377e8ef2 100644 --- a/engines/sci/resource.cpp +++ b/engines/sci/resource.cpp @@ -56,13 +56,6 @@ const char *sci_version_types[] = { const int sci_max_resource_nr[] = {65536, 1000, 2048, 2048, 2048, 65536, 65536, 65536}; -enum SolFlags { - kSolFlagCompressed = 1 << 0, - kSolFlagUnknown = 1 << 1, - kSolFlag16Bit = 1 << 2, - kSolFlagIsSigned = 1 << 3 -}; - static const char *sci_error_types[] = { "No error", "I/O error", @@ -217,7 +210,7 @@ bool ResourceManager::loadFromPatchFile(Resource *res) { return loadPatch(res, file); } -bool ResourceManager::loadFromAudioVolume(Resource *res, Common::File &file) { +bool ResourceManager::loadFromAudioVolumeSCI11(Resource *res, Common::File &file) { ResourceType type = (ResourceType)(file.readByte() & 0x7f); if (((res->id.type == kResourceTypeAudio || res->id.type == kResourceTypeAudio36) && (type != kResourceTypeAudio)) || ((res->id.type == kResourceTypeSync || res->id.type == kResourceTypeSync36) && (type != kResourceTypeSync))) { @@ -243,6 +236,21 @@ bool ResourceManager::loadFromAudioVolume(Resource *res, Common::File &file) { return loadPatch(res, file); } +bool ResourceManager::loadFromAudioVolumeSCI1(Resource *res, Common::File &file) { + res->data = new byte[res->size]; + + if (res->data == NULL) { + error("Can't allocate %d bytes needed for loading %s", res->size, res->id.toString().c_str()); + } + + unsigned int really_read = file.read(res->data, res->size); + if (really_read != res->size) + warning("Read %d bytes from %s but expected %d", really_read, res->id.toString().c_str(), res->size); + + res->status = kResStatusAllocated; + return true; +} + Common::File *ResourceManager::getVolumeFile(const char *filename) { Common::List<Common::File *>::iterator it = _volumeFiles.begin(); Common::File *file; @@ -292,7 +300,10 @@ void ResourceManager::loadResource(Resource *res) { file->seek(res->file_offset, SEEK_SET); if (res->source->source_type == kSourceAudioVolume) { - loadFromAudioVolume(res, *file); + if (_sciVersion < SCI_VERSION_1_1) + loadFromAudioVolumeSCI1(res, *file); + else + loadFromAudioVolumeSCI11(res, *file); } else { int error = decompress(res, file); if (error) { @@ -436,8 +447,11 @@ void ResourceManager::scanNewSources() { else readResourceMapSCI1(source); break; + case kSourceExtAudioMap: + readAudioMapSCI1(source); + break; case kSourceIntMap: - readMap(source); + readAudioMapSCI11(source); break; default: break; @@ -460,6 +474,7 @@ ResourceManager::ResourceManager(int version, int maxMemory) { _LRU.clear(); _resMap.clear(); _sciVersion = version; + _audioMapSCI1 = NULL; addAppropriateSources(); @@ -607,15 +622,10 @@ void ResourceManager::printLRU() { debug("Total: %d entries, %d bytes (mgr says %d)", entries, mem, _memoryLRU); } -void ResourceManager::freeOldResources(int last_invulnerable) { - while (_maxMemory < _memoryLRU && (!last_invulnerable || !_LRU.empty())) { +void ResourceManager::freeOldResources() { + while (_maxMemory < _memoryLRU) { + assert(!_LRU.empty()); Resource *goner = *_LRU.reverse_begin(); - if (!goner) { - debug("Internal error: mgr->lru_last is NULL!"); - debug("LRU-mem= %d", _memoryLRU); - debug("lru_first = %p", (void *)*_LRU.begin()); - printLRU(); - } removeFromLRU(goner); goner->unalloc(); #ifdef SCI_VERBOSE_RESMGR @@ -659,6 +669,8 @@ Resource *ResourceManager::findResource(ResourceId id, bool lock) { // Unless an error occured, the resource is now either // locked or allocated, but never queued or freed. + freeOldResources(); + if (lock) { if (retval->status == kResStatusAllocated) { retval->status = kResStatusLocked; @@ -671,8 +683,6 @@ Resource *ResourceManager::findResource(ResourceId id, bool lock) { addToLRU(retval); } - freeOldResources(retval->status == kResStatusAllocated); - if (retval->data) return retval; else { @@ -695,7 +705,7 @@ void ResourceManager::unlockResource(Resource *res) { addToLRU(res); } - freeOldResources(0); + freeOldResources(); } int ResourceManager::detectMapVersion() { @@ -871,15 +881,7 @@ void ResourceManager::processPatch(ResourceSource *source, ResourceType restype, } // Prepare destination, if neccessary if (_resMap.contains(resId) == false) { - // FIXME: code duplication - switch (restype) { - case kResourceTypeSync: - newrsc = new ResourceSync; - break; - default: - newrsc = new Resource; - break; - } + newrsc = new Resource; _resMap.setVal(resId, newrsc); } else newrsc = _resMap.getVal(resId); @@ -1042,15 +1044,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) { resId = ResourceId((ResourceType)type, number); // adding new resource only if it does not exist if (_resMap.contains(resId) == false) { - switch (type) { - case kResourceTypeSync: - res = new ResourceSync; - break; - default: - res = new Resource; - break; - } - + res = new Resource; _resMap.setVal(resId, res); res->id = resId; res->source = getVolume(map, volume_nr); @@ -1064,11 +1058,7 @@ int ResourceManager::readResourceMapSCI1(ResourceSource *map) { void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size) { // Adding new resource only if it does not exist if (_resMap.contains(resId) == false) { - Resource *res; - if ((resId.type == kResourceTypeSync) || (resId.type == kResourceTypeSync36)) - res = new ResourceSync; - else - res = new Resource; + Resource *res = new Resource; _resMap.setVal(resId, res); res->id = resId; res->source = src; @@ -1077,6 +1067,22 @@ void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32 } } +void ResourceManager::removeAudioResource(ResourceId resId) { + // Remove resource, unless it was loaded from a patch + if (_resMap.contains(resId)) { + Resource *res = _resMap.getVal(resId); + + if (res->source->source_type == kSourceAudioVolume) { + if (res->lockers == 0) { + _resMap.erase(resId); + delete res; + } else { + warning("Failed to remove resource %s (still in use)", resId.toString().c_str()); + } + } + } +} + // Early SCI1.1 65535.MAP structure (uses RESOURCE.AUD): // ========= // 6-byte entries: @@ -1112,7 +1118,7 @@ void ResourceManager::addResource(ResourceId resId, ResourceSource *src, uint32 // w syncSize (iff seq has bit 7 set) // w syncAscSize (iff seq has bit 6 set) -int ResourceManager::readMap(ResourceSource *map) { +int ResourceManager::readAudioMapSCI11(ResourceSource *map) { bool isEarly = true; uint32 offset = 0; Resource *mapRes = findResource(ResourceId(kResourceTypeMap, map->volume_number), false); @@ -1197,6 +1203,103 @@ int ResourceManager::readMap(ResourceSource *map) { return 0; } +// AUDIOnnn.MAP contains 10-byte entries: +// w nEntry +// dw offset+volume (as in resource.map) +// dw size +// ending with 10 0xFFs + +int ResourceManager::readAudioMapSCI1(ResourceSource *map, bool unload) { + Common::File file; + + if (!file.open(map->location_name)) + return SCI_ERROR_RESMAP_NOT_FOUND; + + while (1) { + uint16 n = file.readUint16LE(); + uint32 offset = file.readUint32LE(); + uint32 size = file.readUint32LE(); + + if (file.ioFailed()) { + warning("Error while reading %s", map->location_name.c_str()); + return SCI_ERROR_RESMAP_NOT_FOUND; + } + + if (n == 0xffff) + break; + + byte volume_nr = offset >> 28; // most significant 4 bits + offset &= 0x0fffffff; // least significant 28 bits + + ResourceSource *src = getVolume(map, volume_nr); + + if (src) { + if (unload) + removeAudioResource(ResourceId(kResourceTypeAudio, n)); + else + addResource(ResourceId(kResourceTypeAudio, n), src, offset, size); + } else { + warning("Failed to find audio volume %i", volume_nr); + } + } + + return 0; +} + +void ResourceManager::setAudioLanguage(int language) { + if (_audioMapSCI1) { + if (_audioMapSCI1->volume_number == language) { + // This language is already loaded + return; + } + + // We already have a map loaded, so we unload it first + readAudioMapSCI1(_audioMapSCI1, true); + + // Remove all volumes that use this map from the source list + Common::List<ResourceSource *>::iterator it = _sources.begin(); + while (it != _sources.end()) { + ResourceSource *src = *it; + if (src->associated_map == _audioMapSCI1) { + it = _sources.erase(it); + delete src; + } else { + ++it; + } + } + + // Remove the map itself from the source list + _sources.remove(_audioMapSCI1); + delete _audioMapSCI1; + + _audioMapSCI1 = NULL; + } + + char filename[9]; + snprintf(filename, 9, "AUDIO%03d", language); + + Common::String fullname = Common::String(filename) + ".MAP"; + if (!Common::File::exists(fullname)) { + warning("No audio map found for language %i", language); + return; + } + + _audioMapSCI1 = addSource(NULL, kSourceExtAudioMap, fullname.c_str(), language); + + // Search for audio volumes for this language and add them to the source list + Common::ArchiveMemberList files; + SearchMan.listMatchingMembers(files, Common::String(filename) + ".0??"); + for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); ++x) { + const Common::String name = (*x)->getName(); + const char *dot = strrchr(name.c_str(), '.'); + int number = atoi(dot + 1); + + addSource(_audioMapSCI1, kSourceAudioVolume, name.c_str(), number); + } + + scanNewSources(); +} + int ResourceManager::readResourceInfo(Resource *res, Common::File *file, uint32&szPacked, ResourceCompression &compression) { // SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes @@ -1328,325 +1431,4 @@ int ResourceManager::decompress(Resource *res, Common::File *file) { return error; } -void ResourceSync::startSync(EngineState *s, reg_t obj) { - _syncTime = _syncCue = -1; - PUT_SEL32V(obj, syncCue, 0); - _ptr = (uint16 *)data; - //syncStarted = true; // not used -} - -void ResourceSync::nextSync(EngineState *s, reg_t obj) { - if (_ptr) { - _syncTime = (int16)READ_LE_UINT16(_ptr); - if (_syncTime == -1) { - stopSync(); - } else { - _syncCue = (int16)READ_LE_UINT16(_ptr + 1); - _ptr += 2; - } - PUT_SEL32V(obj, syncTime, _syncTime); - PUT_SEL32V(obj, syncCue, _syncCue); - } -} -//-------------------------------- -void ResourceSync::stopSync() { - _ptr = 0; - _syncCue = -1; - //syncStarted = false; // not used -} - - -AudioResource::AudioResource(ResourceManager *resMgr, int sciVersion) { - _resMgr = resMgr; - _sciVersion = sciVersion; - _audioRate = 11025; - _lang = 0; - _audioMapSCI1 = 0; - _audioMapSCI11 = 0; -} - -AudioResource::~AudioResource() { - if (_sciVersion < SCI_VERSION_1_1) { - if (_audioMapSCI1) { - delete[] _audioMapSCI1; - _audioMapSCI1 = 0; - } - } else { - if (_audioMapSCI11) - _resMgr->unlockResource(_audioMapSCI11); - } -} - -// Used in SCI1 games -void AudioResource::setAudioLang(int16 lang) { - if (lang != -1) { - _lang = lang; - - char filename[40]; - sprintf(filename, "AUDIO%03d.MAP", _lang); - - Common::File* audioMapFile = new Common::File(); - if (audioMapFile->open(filename)) { - // The audio map is freed in the destructor - _audioMapSCI1 = new byte[audioMapFile->size()]; - audioMapFile->read(_audioMapSCI1, audioMapFile->size()); - audioMapFile->close(); - delete audioMapFile; - } else { - _audioMapSCI1 = 0; - } - } -} - -int AudioResource::getAudioPosition() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) { - return g_system->getMixer()->getSoundElapsedTime(_audioHandle) * 6 / 100; // return elapsed time in ticks - } else { - return -1; // Sound finished - } -} - -bool AudioResource::findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &offset, uint32 &size) { - // AUDIO00X.MAP contains 10-byte entries: - // w nEntry - // dw offset+volume (as in resource.map) - // dw size - // ending with 10 0xFFs - uint16 n; - uint32 off; - - if (_audioMapSCI1 == 0) - return false; - - byte *ptr = _audioMapSCI1; - while ((n = READ_LE_UINT16(ptr)) != 0xFFFF) { - if (n == audioNumber) { - off = READ_LE_UINT32(ptr + 2); - size = READ_LE_UINT32(ptr + 6); - volume = off >> 28; - offset = off & 0x0FFFFFFF; - return true; - } - ptr += 10; - } - - return false; -} - -// FIXME: Move this to sound/adpcm.cpp? -// Note that the 16-bit version is also used in coktelvideo.cpp -static const uint16 tableDPCM16[128] = { - 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, - 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120, - 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0, - 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230, - 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280, - 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0, - 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, - 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, - 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0, - 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480, - 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, - 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, - 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 -}; - -static const byte tableDPCM8[8] = {0, 1, 2, 3, 6, 10, 15, 21}; - -static void deDPCM16(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) { - int16 *out = (int16 *) soundBuf; - - int32 s = 0; - for (uint32 i = 0; i < n; i++) { - byte b = audioStream.readByte(); - if (b & 0x80) - s -= tableDPCM16[b & 0x7f]; - else - s += tableDPCM16[b]; - - s = CLIP<int32>(s, -32768, 32767); - *out++ = TO_BE_16(s); - } -} - -static void deDPCM8Nibble(byte *soundBuf, int32 &s, byte b) { - if (b & 8) - s -= tableDPCM8[7 - (b & 7)]; - else - s += tableDPCM8[b & 7]; - s = CLIP<int32>(s, 0, 255); - *soundBuf = s; -} - -static void deDPCM8(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) { - int32 s = 0x80; - - for (uint i = 0; i < n; i++) { - byte b = audioStream.readByte(); - - deDPCM8Nibble(soundBuf++, s, b >> 4); - deDPCM8Nibble(soundBuf++, s, b & 0xf); - } -} - -// Sierra SOL audio file reader -// Check here for more info: http://wiki.multimedia.cx/index.php?title=Sierra_Audio -static bool readSOLHeader(Common::SeekableReadStream *audioStream, int headerSize, uint32 &size, uint16 &audioRate, byte &audioFlags) { - if (headerSize != 11 && headerSize != 12) { - warning("SOL audio header of size %i not supported", headerSize); - return false; - } - - audioStream->readUint32LE(); // skip "SOL" + 0 (4 bytes) - audioRate = audioStream->readUint16LE(); - audioFlags = audioStream->readByte(); - - size = audioStream->readUint32LE(); - return true; -} - -static byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 &size, byte audioFlags, byte &flags) { - byte *buffer; - - // Convert the SOL stream flags to our own format - flags = 0; - if (audioFlags & kSolFlag16Bit) - flags |= Audio::Mixer::FLAG_16BITS; - if (!(audioFlags & kSolFlagIsSigned)) - flags |= Audio::Mixer::FLAG_UNSIGNED; - - if (audioFlags & kSolFlagCompressed) { - buffer = (byte *)malloc(size * 2); - - if (audioFlags & kSolFlag16Bit) - deDPCM16(buffer, *audioStream, size); - else - deDPCM8(buffer, *audioStream, size); - - size *= 2; - } else { - // We assume that the sound data is raw PCM - buffer = (byte *)malloc(size); - audioStream->read(buffer, size); - } - - return buffer; -} - -Audio::AudioStream* AudioResource::getAudioStream(uint32 audioNumber, uint32 volume, int *sampleLen) { - Audio::AudioStream *audioStream = 0; - uint32 offset; - uint32 size; - bool found = false; - byte *data = 0; - char filename[40]; - byte flags = 0; - Sci::Resource* audioRes = NULL; - - // Try to load from resource manager - if (volume == 65535) - audioRes = _resMgr->findResource(ResourceId(kResourceTypeAudio, audioNumber), false); - else - audioRes = _resMgr->findResource(ResourceId(kResourceTypeAudio36, volume, audioNumber), false); - - if (audioRes) { - if (_sciVersion < SCI_VERSION_1_1) { - size = audioRes->size; - data = audioRes->data; - } else { - byte audioFlags; - - Common::MemoryReadStream *headerStream = - new Common::MemoryReadStream(audioRes->header, audioRes->headerSize, false); - - if (readSOLHeader(headerStream, audioRes->headerSize, size, _audioRate, audioFlags)) { - Common::MemoryReadStream *dataStream = - new Common::MemoryReadStream(audioRes->data, audioRes->size, false); - data = readSOLAudio(dataStream, size, audioFlags, flags); - delete dataStream; - } - delete headerStream; - } - - if (data) { - audioStream = Audio::makeLinearInputStream(data, size, _audioRate, - flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0); - } - } else { - // Load it from the audio file - if (_sciVersion < SCI_VERSION_1_1) { - byte sci1Volume; - found = findAudEntrySCI1(audioNumber, sci1Volume, offset, size); - sprintf(filename, "AUDIO%03d.%03d", _lang, sci1Volume); - flags |= Audio::Mixer::FLAG_UNSIGNED; - } - - if (found) { - #if 0 - // TODO: This tries to load directly from the KQ5CD audio file with MP3/OGG/FLAC - // compression. Once we got a tool to compress this file AND update the map file - // at the same time, we can use this code to play compressed audio. - if (_sciVersion < SCI_VERSION_1_1) { - uint32 start = offset * 1000 / _audioRate; - uint32 duration = size * 1000 / _audioRate; - - // Try to load compressed - audioStream = Audio::AudioStream::openStreamFile(filename, start, duration); - } - #endif - - if (!audioStream) { - // Compressed file load failed, try to load original raw data - Common::File* audioFile = new Common::File(); - if (audioFile->open(filename)) { - audioFile->seek(offset); - - if (_sciVersion < SCI_VERSION_1_1) { - data = (byte *)malloc(size); - audioFile->read(data, size); - } else { - byte type = audioFile->readByte() & 0x7f; - byte audioFlags; - - if (type != kResourceTypeAudio) { - warning("Resource type mismatch"); - delete audioFile; - return NULL; - } - - byte headerSize = audioFile->readByte(); - - if (readSOLHeader(audioFile, headerSize, size, _audioRate, audioFlags)) - data = readSOLAudio(audioFile, size, audioFlags, flags); - - if (!data) { - delete audioFile; - return NULL; - } - } - - audioFile->close(); - - if (data) { - audioStream = Audio::makeLinearInputStream(data, size, _audioRate, - flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0); - } - } - - delete audioFile; - } - } else { - warning("Failed to find audio entry (%i, %i, %i, %i, %i)", volume, (audioNumber >> 24) & 0xff, - (audioNumber >> 16) & 0xff, (audioNumber >> 8) & 0xff, audioNumber & 0xff); - } - } - - if (audioStream) { - *sampleLen = (flags & Audio::Mixer::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate; - return audioStream; - } - - return NULL; -} - } // End of namespace Sci diff --git a/engines/sci/resource.h b/engines/sci/resource.h index fc3f37f25c..77c92840ee 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -72,19 +72,14 @@ enum { enum ResSourceType { kSourceDirectory = 0, - kSourcePatch = 1, - kSourceVolume = 2, - kSourceExtMap = 3, - kSourceIntMap = 4, - kSourceAudioVolume = 5, - kSourceMask = 127 + kSourcePatch, + kSourceVolume, + kSourceExtMap, + kSourceIntMap, + kSourceAudioVolume, + kSourceExtAudioMap }; -#define RESSOURCE_ADDRESSING_BASIC 0 -#define RESSOURCE_ADDRESSING_EXTENDED 128 -#define RESSOURCE_ADDRESSING_MASK 128 - -#define RESOURCE_HASH(type, number) (uint32)((type<<16) | number) #define SCI0_RESMAP_ENTRIES_SIZE 6 #define SCI1_RESMAP_ENTRIES_SIZE 6 #define SCI11_RESMAP_ENTRIES_SIZE 5 @@ -136,7 +131,6 @@ struct ResourceSource { Common::String location_name; // FIXME: Replace by FSNode ? int volume_number; ResourceSource *associated_map; - ResourceSource *next; }; class ResourceManager; @@ -270,6 +264,8 @@ public: */ Common::List<ResourceId> *listResources(ResourceType type, int mapNumber = -1); + void setAudioLanguage(int language); + protected: int _maxMemory; //!< Config option: Maximum total byte number allocated Common::List<ResourceSource *> _sources; @@ -278,6 +274,7 @@ protected: Common::List<Resource *> _LRU; //!< Last Resource Used list ResourceMap _resMap; Common::List<Common::File *> _volumeFiles; //!< list of opened volume files + ResourceSource *_audioMapSCI1; //!< Currently loaded audio map for SCI1 /** * Add a path to the resource manager's list of sources. @@ -325,11 +322,13 @@ protected: void loadResource(Resource *res); bool loadPatch(Resource *res, Common::File &file); bool loadFromPatchFile(Resource *res); - bool loadFromAudioVolume(Resource *res, Common::File &file); - void freeOldResources(int last_invulnerable); + bool loadFromAudioVolumeSCI1(Resource *res, Common::File &file); + bool loadFromAudioVolumeSCI11(Resource *res, Common::File &file); + void freeOldResources(); int decompress(Resource *res, Common::File *file); int readResourceInfo(Resource *res, Common::File *file, uint32&szPacked, ResourceCompression &compression); void addResource(ResourceId resId, ResourceSource *src, uint32 offset, uint32 size = 0); + void removeAudioResource(ResourceId resId); /**--- Resource map decoding functions ---*/ int detectMapVersion(); @@ -337,21 +336,32 @@ protected: /** * Reads the SCI0 resource.map file from a local directory. + * @param map The map * @return 0 on success, an SCI_ERROR_* code otherwise */ int readResourceMapSCI0(ResourceSource *map); /** * Reads the SCI1 resource.map file from a local directory. + * @param map The map * @return 0 on success, an SCI_ERROR_* code otherwise */ int readResourceMapSCI1(ResourceSource *map); /** - * Reads SCI1.1 MAP resources + * Reads SCI1.1 audio map resources + * @param map The map * @return 0 on success, an SCI_ERROR_* code otherwise */ - int readMap(ResourceSource *map); + int readAudioMapSCI11(ResourceSource *map); + + /** + * Reads SCI1 audio map files + * @param map The map + * @param unload Unload the map instead of loading it + * @return 0 on success, an SCI_ERROR_* code otherwise + */ + int readAudioMapSCI1(ResourceSource *map, bool unload = false); /**--- Patch management functions ---*/ @@ -368,60 +378,6 @@ protected: int guessSciVersion(); }; -/** - * Used for lip and animation syncing in CD talkie games - */ -class ResourceSync : public Resource { -public: - ResourceSync() {} - ~ResourceSync() {} - - void startSync(EngineState *s, reg_t obj); - void nextSync(EngineState *s, reg_t obj); - void stopSync(); - -protected: - uint16 *_ptr; - int16 _syncTime, _syncCue; - //bool _syncStarted; // not used -}; - -/** - * Used for speech playback and digital music playback - * in CD talkie games - */ -class AudioResource { -public: - AudioResource(ResourceManager *resMgr, int sciVersion); - ~AudioResource(); - - void setAudioRate(uint16 audioRate) { _audioRate = audioRate; } - void setAudioLang(int16 lang); - - Audio::SoundHandle* getAudioHandle() { return &_audioHandle; } - int getAudioPosition(); - - Audio::AudioStream* getAudioStream(uint32 audioNumber, uint32 volume, int *sampleLen); - - void stop() { g_system->getMixer()->stopHandle(_audioHandle); } - void pause() { g_system->getMixer()->pauseHandle(_audioHandle, true); } - void resume() { g_system->getMixer()->pauseHandle(_audioHandle, false); } - -private: - Audio::SoundHandle _audioHandle; - uint16 _audioRate; - int16 _lang; - byte *_audioMapSCI1; - Resource *_audioMapSCI11; - ResourceManager *_resMgr; - int _sciVersion; - - bool findAudEntrySCI1(uint16 audioNumber, byte &volume, uint32 &offset, uint32 &size); - bool findAudEntrySCI11(uint32 audioNumber, uint32 volume, uint32 &offset, bool getSync = false, uint32 *size = NULL); - bool findAudEntrySCI11Late(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size); - bool findAudEntrySCI11Early(uint32 audioNumber, uint32 &offset, bool getSync, uint32 *size); -}; - } // End of namespace Sci #endif // SCI_SCICORE_RESOURCE_H diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index f58d729bf6..9b277b058f 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -158,7 +158,8 @@ Common::Error SciEngine::run() { if (flags & GF_SCI0_OLD || flags & GF_SCI0_OLDGFXFUNCS || - flags & GF_SCI0_OLDGETTIME) { + flags & GF_SCI0_OLDGETTIME || + flags & GF_SCI0_SCI1VOCAB) { error("This game entry is erroneous. It's marked as SCI1, but it has SCI0 flags set"); } } else if (version == SCI_VERSION_1_1 || version == SCI_VERSION_32) { @@ -170,7 +171,8 @@ Common::Error SciEngine::run() { if (flags & GF_SCI0_OLD || flags & GF_SCI0_OLDGFXFUNCS || - flags & GF_SCI0_OLDGETTIME) { + flags & GF_SCI0_OLDGETTIME || + flags & GF_SCI0_SCI1VOCAB) { error("This game entry is erroneous. It's marked as SCI1.1/SCI32, but it has SCI0 flags set"); } diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 91f491fe71..18b1b93a92 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -108,6 +108,11 @@ enum SciGameFlags { ** Older SCI versions had simpler code for GetTime() */ GF_SCI0_OLDGETTIME = (1 << 2), + + /* Applies to any game that requires the SCI1 kernel vocab + ** Some games (such as the King's Quest I demo) require the default kernel vocab table. + */ + GF_SCI0_SCI1VOCAB = (1 << 3), // ---------------------------------------------------------------------------- @@ -118,18 +123,18 @@ enum SciGameFlags { /* ** Used to distinguish SCI1 EGA games */ - GF_SCI1_EGA = (1 << 3), + GF_SCI1_EGA = (1 << 4), /* Applies to all SCI1 versions after 1.000.200 ** In late SCI1 versions, the argument of lofs[as] instructions ** is absolute rather than relative. */ - GF_SCI1_LOFSABSOLUTE = (1 << 4), + GF_SCI1_LOFSABSOLUTE = (1 << 5), /* Applies to all versions from 1.000.510 onwards ** kDoSound() is different than in earlier SCI1 versions. */ - GF_SCI1_NEWDOSOUND = (1 << 5) + GF_SCI1_NEWDOSOUND = (1 << 6) }; class SciEngine : public Engine { diff --git a/engines/sci/sfx/core.cpp b/engines/sci/sfx/core.cpp index e37007bf8e..9bf7730fc9 100644 --- a/engines/sci/sfx/core.cpp +++ b/engines/sci/sfx/core.cpp @@ -348,11 +348,13 @@ SfxState::SfxState() { _flags = 0; _song = NULL; _suspended = 0; - _soundSync = 0; - _audioResource = 0; + _syncResource = NULL; + _audioRate = 11025; } SfxState::~SfxState() { + if (_syncResource) + _resMgr->unlockResource(_syncResource); } @@ -526,7 +528,7 @@ void SfxState::updateSingleSong() { debugMessage += " none\n"; } - debugC(2, kDebugLevelSound, debugMessage.c_str()); + debugC(2, kDebugLevelSound, "%s", debugMessage.c_str()); _song = newsong; thawTime(); /* Recover song delay time */ @@ -641,8 +643,8 @@ void SfxState::sfx_init(ResourceManager *resmgr, int flags) { _songlib._lib = 0; _song = NULL; _flags = flags; - _soundSync = NULL; - _audioResource = NULL; + _syncResource = NULL; + _syncOffset = 0; player = NULL; @@ -676,6 +678,8 @@ void SfxState::sfx_init(ResourceManager *resmgr, int flags) { delete player; player = NULL; } + + _resMgr = resmgr; } void SfxState::sfx_exit() { @@ -689,12 +693,6 @@ void SfxState::sfx_exit() { g_system->getMixer()->stopAll(); _songlib.freeSounds(); - - // Delete audio resources for CD talkie games - if (_audioResource) { - delete _audioResource; - _audioResource = 0; - } } void SfxState::sfx_suspend(bool suspend) { @@ -1004,4 +1002,187 @@ void SfxState::sfx_all_stop() { update(); } +int SfxState::startAudio(uint16 module, uint32 number) { + int sampleLen; + Audio::AudioStream *audioStream = getAudioStream(number, module, &sampleLen); + + if (audioStream) { + g_system->getMixer()->playInputStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream); + return sampleLen; + } + + return 0; +} + +int SfxState::getAudioPosition() { + if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) + return g_system->getMixer()->getSoundElapsedTime(_audioHandle) * 6 / 100; // return elapsed time in ticks + else + return -1; // Sound finished +} + +enum SolFlags { + kSolFlagCompressed = 1 << 0, + kSolFlagUnknown = 1 << 1, + kSolFlag16Bit = 1 << 2, + kSolFlagIsSigned = 1 << 3 +}; + +// FIXME: Move this to sound/adpcm.cpp? +// Note that the 16-bit version is also used in coktelvideo.cpp +static const uint16 tableDPCM16[128] = { + 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, + 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120, + 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0, + 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230, + 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280, + 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0, + 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, + 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, + 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0, + 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480, + 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, + 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, + 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 +}; + +static const byte tableDPCM8[8] = {0, 1, 2, 3, 6, 10, 15, 21}; + +static void deDPCM16(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) { + int16 *out = (int16 *) soundBuf; + + int32 s = 0; + for (uint32 i = 0; i < n; i++) { + byte b = audioStream.readByte(); + if (b & 0x80) + s -= tableDPCM16[b & 0x7f]; + else + s += tableDPCM16[b]; + + s = CLIP<int32>(s, -32768, 32767); + *out++ = TO_BE_16(s); + } +} + +static void deDPCM8Nibble(byte *soundBuf, int32 &s, byte b) { + if (b & 8) + s -= tableDPCM8[7 - (b & 7)]; + else + s += tableDPCM8[b & 7]; + s = CLIP<int32>(s, 0, 255); + *soundBuf = s; +} + +static void deDPCM8(byte *soundBuf, Common::SeekableReadStream &audioStream, uint32 n) { + int32 s = 0x80; + + for (uint i = 0; i < n; i++) { + byte b = audioStream.readByte(); + + deDPCM8Nibble(soundBuf++, s, b >> 4); + deDPCM8Nibble(soundBuf++, s, b & 0xf); + } +} + +// Sierra SOL audio file reader +// Check here for more info: http://wiki.multimedia.cx/index.php?title=Sierra_Audio +static bool readSOLHeader(Common::SeekableReadStream *audioStream, int headerSize, uint32 &size, uint16 &audioRate, byte &audioFlags) { + if (headerSize != 11 && headerSize != 12) { + warning("SOL audio header of size %i not supported", headerSize); + return false; + } + + audioStream->readUint32LE(); // skip "SOL" + 0 (4 bytes) + audioRate = audioStream->readUint16LE(); + audioFlags = audioStream->readByte(); + + size = audioStream->readUint32LE(); + return true; +} + +static byte* readSOLAudio(Common::SeekableReadStream *audioStream, uint32 &size, byte audioFlags, byte &flags) { + byte *buffer; + + // Convert the SOL stream flags to our own format + flags = 0; + if (audioFlags & kSolFlag16Bit) + flags |= Audio::Mixer::FLAG_16BITS; + if (!(audioFlags & kSolFlagIsSigned)) + flags |= Audio::Mixer::FLAG_UNSIGNED; + + if (audioFlags & kSolFlagCompressed) { + buffer = (byte *)malloc(size * 2); + + if (audioFlags & kSolFlag16Bit) + deDPCM16(buffer, *audioStream, size); + else + deDPCM8(buffer, *audioStream, size); + + size *= 2; + } else { + // We assume that the sound data is raw PCM + buffer = (byte *)malloc(size); + audioStream->read(buffer, size); + } + + return buffer; +} + +Audio::AudioStream* SfxState::getAudioStream(uint32 number, uint32 volume, int *sampleLen) { + Audio::AudioStream *audioStream = 0; + uint32 size; + byte *data = 0; + byte flags = 0; + Sci::Resource* audioRes; + + if (volume == 65535) { + audioRes = _resMgr->findResource(ResourceId(kResourceTypeAudio, number), false); + if (!audioRes) { + warning("Failed to find audio entry %i", number); + return NULL; + } + } else { + audioRes = _resMgr->findResource(ResourceId(kResourceTypeAudio36, volume, number), false); + if (!audioRes) { + warning("Failed to find audio entry (%i, %i, %i, %i, %i)", volume, (number >> 24) & 0xff, + (number >> 16) & 0xff, (number >> 8) & 0xff, number & 0xff); + return NULL; + } + } + + byte audioFlags; + + if (audioRes->headerSize > 0) { + // SCI1.1 + Common::MemoryReadStream *headerStream = + new Common::MemoryReadStream(audioRes->header, audioRes->headerSize, false); + + if (readSOLHeader(headerStream, audioRes->headerSize, size, _audioRate, audioFlags)) { + Common::MemoryReadStream *dataStream = + new Common::MemoryReadStream(audioRes->data, audioRes->size, false); + data = readSOLAudio(dataStream, size, audioFlags, flags); + delete dataStream; + } + delete headerStream; + } else { + // SCI1 + size = audioRes->size; + data = (byte *)malloc(size); + assert(data); + memcpy(data, audioRes->data, size); + flags = Audio::Mixer::FLAG_UNSIGNED; + } + + if (data) { + audioStream = Audio::makeLinearInputStream(data, size, _audioRate, + flags | Audio::Mixer::FLAG_AUTOFREE, 0, 0); + if (audioStream) { + *sampleLen = (flags & Audio::Mixer::FLAG_16BITS ? size >> 1 : size) * 60 / _audioRate; + return audioStream; + } + } + + return NULL; +} + } // End of namespace Sci diff --git a/engines/sci/sfx/core.h b/engines/sci/sfx/core.h index 5db56bd864..e7eba85c99 100644 --- a/engines/sci/sfx/core.h +++ b/engines/sci/sfx/core.h @@ -50,8 +50,9 @@ public: // FIXME, make private SongLibrary _songlib; /**< Song library */ Song *_song; /**< Active song, or start of active song chain */ bool _suspended; /**< Whether we are suspended */ - ResourceSync *_soundSync; /**< Used by kDoSync for speech syncing in CD talkie games */ - AudioResource *_audioResource; /**< Used for audio resources in CD talkie games */ + Resource *_syncResource; /**< Used by kDoSync for speech syncing in CD talkie games */ + uint _syncOffset; + ResourceManager *_resMgr; public: SfxState(); @@ -164,6 +165,15 @@ public: Common::Error sfx_send_midi(SongHandle handle, int channel, int command, int arg1, int arg2); + // Functions for digital sound + void setAudioRate(uint16 rate) { _audioRate = rate; } + Audio::SoundHandle* getAudioHandle() { return &_audioHandle; } + int getAudioPosition(); + int startAudio(uint16 module, uint32 tuple); + void stopAudio() { g_system->getMixer()->stopHandle(_audioHandle); } + void pauseAudio() { g_system->getMixer()->pauseHandle(_audioHandle, true); } + void resumeAudio() { g_system->getMixer()->pauseHandle(_audioHandle, false); } + protected: void freezeTime(); void thawTime(); @@ -173,8 +183,12 @@ protected: void updateSingleSong(); void updateMultiSong(); void update(); -}; +private: + uint16 _audioRate; + Audio::SoundHandle _audioHandle; + Audio::AudioStream* getAudioStream(uint32 number, uint32 volume, int *sampleLen); +}; } // End of namespace Sci diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index cf90094112..88c258a2e6 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -1348,6 +1348,22 @@ void ScummEngine::processActors() { } } } + } else if (_game.heversion >= 90) { + for (int j = 0; j < numactors; ++j) { + for (int i = 0; i < numactors; ++i) { + int sc_actor1 = _sortedActors[j]->_layer; + int sc_actor2 = _sortedActors[i]->_layer; + if (sc_actor1 < sc_actor2) { + SWAP(_sortedActors[i], _sortedActors[j]); + } else if (sc_actor1 == sc_actor2) { + sc_actor1 = _sortedActors[j]->getPos().y; + sc_actor2 = _sortedActors[i]->getPos().y; + if (sc_actor1 < sc_actor2) { + SWAP(_sortedActors[i], _sortedActors[j]); + } + } + } + } } else { for (int j = 0; j < numactors; ++j) { for (int i = 0; i < numactors; ++i) { diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index 665782bf36..fe0904d632 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -420,8 +420,7 @@ void ScummEngine_v100he::o100_actorOps() { a->_needRedraw = true; break; case 59: - // HE games use reverse order of layering, so we adjust - a->_layer = -pop(); + a->_layer = pop(); a->_needRedraw = true; break; case 63: diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index bb209e78d1..64c63baa9d 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -770,8 +770,7 @@ void ScummEngine_v72he::o72_actorOps() { a->setTalkCondition(k); break; case 43: // HE 90+ - // HE games use reverse order of layering, so we adjust - a->_layer = -pop(); + a->_layer = pop(); a->_needRedraw = true; break; case 64: diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index caae659766..22487b43a3 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -727,7 +727,7 @@ void ScummEngine::resetScummVars() { // Value only used by the Macintosh version of Indiana Jones and the Last Crusade else if (_game.platform == Common::kPlatformMacintosh && _game.version == 3) VAR(VAR_VIDEOMODE) = 50; - // Value only used by the Amiga of Monkey Island 2 + // Value only used by the Amiga version of Monkey Island 2 else if (_game.platform == Common::kPlatformAmiga) VAR(VAR_VIDEOMODE) = 82; else if (_renderMode == Common::kRenderCGA) diff --git a/engines/sword1/music.cpp b/engines/sword1/music.cpp index 9f602aca2c..fb9068dde7 100644 --- a/engines/sword1/music.cpp +++ b/engines/sword1/music.cpp @@ -272,7 +272,7 @@ bool MusicHandle::playPSX(uint16 id, bool loop) { tableFile.close(); - if (size != 0xffffffff && size) { + if ((size != 0) && (size != 0xffffffff)) { _file.seek(offset, SEEK_SET); _audioSource = new Audio::VagStream(_file.readStream(size), loop); fadeUp(); diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp index 306d23db57..5577c66fc6 100644 --- a/engines/sword1/sound.cpp +++ b/engines/sword1/sound.cpp @@ -226,14 +226,14 @@ bool Sound::startSpeech(uint16 roomNo, uint16 localNo) { return false; } - uint16 numRooms = file.readUint16LE(); // Number of rooms + uint16 numRooms = file.readUint16LE(); // Read number of rooms referenced in this file file.seek(locIndex * 4 + 2); // 4 bytes per room, skip first 2 bytes uint16 numLines = file.readUint16LE(); uint16 roomOffset = file.readUint16LE(); - file.seek(2 + numRooms * 4 + roomOffset * 2); // The offset is in terms of uint16's, so multiply by 2. Skip the 0x112 byte header too. + file.seek(2 + numRooms * 4 + roomOffset * 2); // The offset is in terms of uint16's, so multiply by 2. Skip the room indexes too. locIndex = 0xFFFFFFFF; diff --git a/engines/tinsel/detection.cpp b/engines/tinsel/detection.cpp index 863848bee1..a3cd0bc7b7 100644 --- a/engines/tinsel/detection.cpp +++ b/engines/tinsel/detection.cpp @@ -297,15 +297,11 @@ static const TinselGameDescription gameDescriptions[] = { TINSEL_V1, }, - { // UK multilanguage PSX CD + { // Discworld PSX CD { "dw", "CD", { - {"french.txt", 0, "e7020d35f58d0d187052ac406d86cc87", 273918}, - {"german.txt", 0, "6e2c0f0655bc3cec5a6b3552164ec984", 263942}, - {"italian.txt", 0, "15f0703f85477d7fab4280bf938b61c1", 239830}, - {"spanish.txt", 0, "bda9bea9078d1483409082a3e180378a", 236702}, {"english.txt", 0, "7526cfc3a64e00f223795de476b4e2c9", 230326}, {NULL, 0, NULL, 0} }, diff --git a/engines/tinsel/palette.cpp b/engines/tinsel/palette.cpp index c544bddbb1..8df9e9a375 100644 --- a/engines/tinsel/palette.cpp +++ b/engines/tinsel/palette.cpp @@ -99,6 +99,7 @@ void psxPaletteMapper(PALQ *originalPal, uint8 *psxClut, byte *mapperTable) { bool colorFound = false; uint16 clutEntry = 0; + // Empty the table with color correspondences memset(mapperTable, 0, 16); for (int j = 1; j < 16; j++) { @@ -115,7 +116,7 @@ void psxPaletteMapper(PALQ *originalPal, uint8 *psxClut, byte *mapperTable) { uint16 psxEquivalent = TINSEL_PSX_RGB(TINSEL_GetRValue(pal->palRGB[i]) >> 3, TINSEL_GetGValue(pal->palRGB[i]) >> 3, TINSEL_GetBValue(pal->palRGB[i]) >> 3); if (psxEquivalent == clutEntry) { - mapperTable[j] = i + 1; + mapperTable[j] = i + 1; // Add entry in the table for the found color colorFound = true; } } diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp index 47602b5862..1a08fd2420 100644 --- a/engines/tinsel/tinsel.cpp +++ b/engines/tinsel/tinsel.cpp @@ -850,19 +850,8 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc) Common::File::addDefaultDirectory(_gameDataDir.getChild("dw2")); // Add subfolders needed for psx versions of Discworld 1 - if(TinselV1PSX) { - Common::File::addDefaultDirectory(_gameDataDir.getChild("MIDI")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("SAMPLES")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX").getChild("GFXAB")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX").getChild("GFXC")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX").getChild("GFXDG")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX").getChild("GFXHL")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX").getChild("GFXMO")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX").getChild("GFXP")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX").getChild("GFXRS")); - Common::File::addDefaultDirectory(_gameDataDir.getChild("GFX").getChild("GFXTW")); - } + if (TinselV1PSX) + SearchMan.addDirectory(_gameDataDir.getPath(), _gameDataDir, 0, 3, true); const GameSettings *g; diff --git a/engines/tucker/locations.cpp b/engines/tucker/locations.cpp index ec60086abf..9faa2024a6 100644 --- a/engines/tucker/locations.cpp +++ b/engines/tucker/locations.cpp @@ -650,21 +650,17 @@ void TuckerEngine::execData3PostUpdate_locationNum8() { if (_execData3Counter > 30) { _updateLocationYPosTable2[0] = 16; _updateLocationXPosTable2[0] = 264; - } } if (_updateLocationYPosTable2[0] > 0) { const int offset = _updateLocationYPosTable2[0] * 640 + _updateLocationXPosTable2[0]; - _locationBackgroundGfxBuf[offset] = 142; - _locationBackgroundGfxBuf[offset + 640 - 1] = 143; - _locationBackgroundGfxBuf[offset + 640] = 143; - _locationBackgroundGfxBuf[offset + 640 + 1] = 144; - _locationBackgroundGfxBuf[offset + 640 * 2 - 1] = 144; - _locationBackgroundGfxBuf[offset + 640 * 2] = 144; - _locationBackgroundGfxBuf[offset + 640 * 2 + 1] = 145; - _locationBackgroundGfxBuf[offset + 640 * 3 - 1] = 147; - _locationBackgroundGfxBuf[offset + 640 * 3] = 143; - _locationBackgroundGfxBuf[offset + 640 * 3 + 1] = 147; + static const int colorsTable[] = { 143, 143, 144, 144, 144, 145, 147, 143, 147 }; + _locationBackgroundGfxBuf[offset] = 142; + for (int j = 1; j <= 3; ++j) { + for (int i = -1; i <= 1; ++i) { + _locationBackgroundGfxBuf[offset + 640 * j + i] = colorsTable[(j - 1) * 3 + i + 1]; + } + } addDirtyRect(_updateLocationXPosTable2[0] - 1, _updateLocationYPosTable2[0], 3, 4); _updateLocationYPosTable2[0] += 2; if (_updateLocationYPosTable2[0] > 120) { diff --git a/engines/tucker/resource.cpp b/engines/tucker/resource.cpp index 1195fe4894..11c1c78133 100644 --- a/engines/tucker/resource.cpp +++ b/engines/tucker/resource.cpp @@ -218,6 +218,7 @@ void TuckerEngine::openCompressedSoundFile() { int version = _fCompressedSound.readUint16LE(); if (version == kCurrentCompressedSoundDataVersion) { _compressedSoundType = i; + debug(1, "Using compressed sound file '%s'", compressedSoundFilesTable[i].filename); return; } warning("Unhandled version %d for compressed sound file '%s'", version, compressedSoundFilesTable[i].filename); diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index d977813a31..11a535e54a 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -494,13 +494,9 @@ int TuckerEngine::handleSpecialObjectSelectionSequence() { AnimationSequencePlayer::AnimationSequencePlayer(OSystem *system, Audio::Mixer *mixer, Common::EventManager *event, int num) : _system(system), _mixer(mixer), _event(event), _seqNum(num) { memset(_animationPalette, 0, sizeof(_animationPalette)); - _soundSeqDataOffset = 0; _soundSeqDataCount = 0; _soundSeqDataIndex = 0; - _soundsList1Offset = 0; - _soundsList1Count = 0; - _soundsList2Offset = 0; - _soundsList2Count = 0; + _soundSeqData = 0; _offscreenBuffer = (uint8 *)malloc(kScreenWidth * kScreenHeight); _updateScreenWidth = 0; _updateScreenPicture = false; @@ -589,20 +585,9 @@ void AnimationSequencePlayer::syncTime() { } Audio::AudioStream *AnimationSequencePlayer::loadSoundFileAsStream(int index, AnimationSoundType type) { - const char *name = 0; - switch (type) { - case kAnimationSoundType8BitsRAW: - case kAnimationSoundType16BitsRAW: - name = _musicFileNamesTable[index]; - break; - case kAnimationSoundTypeWAV: - case kAnimationSoundTypeLoopingWAV: - name = _audioFileNamesTable[index]; - break; - } Audio::AudioStream *stream = 0; char fileName[64]; - snprintf(fileName, sizeof(fileName), "audio/%s", name); + snprintf(fileName, sizeof(fileName), "audio/%s", _audioFileNamesTable[index]); Common::File f; if (f.open(fileName)) { int size = 0, rate = 0; @@ -637,88 +622,53 @@ Audio::AudioStream *AnimationSequencePlayer::loadSoundFileAsStream(int index, An return stream; } -enum { - kSoundsList_Seq3_4, - kSoundsList_Seq9_10, - kSoundsList_Seq21_20, - kSoundsList_Seq13_14, - kSoundsList_Seq15_16, - kSoundsList_Seq27_28, - kSoundsList_Seq17_18, - kSoundsList_Seq19_20 -}; - void AnimationSequencePlayer::loadSounds(int num) { - static const int soundsList[][8] = { - { 1, 0, 14, 0, 10, 14, 58, 0 }, - { 1, 0, 14, 24, 5, 38, 60, 58 }, - { 1, 0, 14, 43, 9, 57, 48, 118 }, - { 6, 80, 14, 79, 4, 93, 25, 185 }, - { 7, 80, 13, 97, 9, 110, 43, 210 }, - { 10, 80, 11, 119, 0, 0, 11, 253 }, - { 8, 100, 0, 0, 0, 0, 0, 0 }, - { 0, 100, 4, 146, 0, 0, 7, 300 } - }; - int musicIndex = soundsList[num][0]; - int musicVolume = soundsList[num][1]; - _soundsList1Count = soundsList[num][2]; - _soundsList1Offset = soundsList[num][3]; - _soundsList2Count = soundsList[num][4]; - _soundsList2Offset = soundsList[num][5]; - _soundSeqDataCount = soundsList[num][6]; - _soundSeqDataOffset = soundsList[num][7]; - if (musicVolume != 0) { + if (_soundSeqDataList[num].musicVolume != 0) { Audio::AudioStream *s; - if ((s = loadSoundFileAsStream(musicIndex, kAnimationSoundType8BitsRAW)) != 0) { - _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, s, -1, scaleMixerVolume(musicVolume)); + if ((s = loadSoundFileAsStream(_soundSeqDataList[num].musicIndex, kAnimationSoundType8BitsRAW)) != 0) { + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, s, -1, scaleMixerVolume(_soundSeqDataList[num].musicVolume)); } } _soundSeqDataIndex = 0; + _soundSeqDataCount = _soundSeqDataList[num].soundSeqDataCount; + _soundSeqData = _soundSeqDataList[num].soundSeqData; } void AnimationSequencePlayer::updateSounds() { Audio::AudioStream *s = 0; - const SoundSequenceData *p = &_soundSeqData[_soundSeqDataOffset + _soundSeqDataIndex]; + const SoundSequenceData *p = &_soundSeqData[_soundSeqDataIndex]; while (_soundSeqDataIndex < _soundSeqDataCount && p->timestamp <= _frameCounter) { switch (p->opcode) { case 0: - if (p->index < _soundsList1Count) { - if ((s = loadSoundFileAsStream(_soundsList1Offset + p->index, kAnimationSoundTypeWAV)) != 0) { - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_soundsHandle[p->index], s, -1, scaleMixerVolume(p->volume)); - } + if ((s = loadSoundFileAsStream(p->num, kAnimationSoundTypeWAV)) != 0) { + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_soundsHandle[p->index], s, -1, scaleMixerVolume(p->volume)); } break; case 1: - if (p->index < _soundsList1Count) { - if ((s = loadSoundFileAsStream(_soundsList1Offset + p->index, kAnimationSoundTypeLoopingWAV)) != 0) { - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_soundsHandle[p->index], s, -1, scaleMixerVolume(p->volume)); - } + if ((s = loadSoundFileAsStream(p->num, kAnimationSoundTypeLoopingWAV)) != 0) { + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_soundsHandle[p->index], s, -1, scaleMixerVolume(p->volume)); } break; case 2: - if (p->index < _soundsList1Count) { - _mixer->stopHandle(_soundsHandle[p->index]); - } + _mixer->stopHandle(_soundsHandle[p->index]); break; case 3: _mixer->stopHandle(_musicHandle); break; case 4: _mixer->stopHandle(_musicHandle); - if ((s = loadSoundFileAsStream(p->index, kAnimationSoundType8BitsRAW)) != 0) { + if ((s = loadSoundFileAsStream(p->num, kAnimationSoundType8BitsRAW)) != 0) { _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, s, -1, scaleMixerVolume(p->volume)); } break; case 5: - if (p->index < _soundsList2Count) { - if ((s = loadSoundFileAsStream(_soundsList2Offset + p->index, kAnimationSoundTypeWAV)) != 0) { - _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, s, -1, scaleMixerVolume(p->volume)); - } + if ((s = loadSoundFileAsStream(p->num, kAnimationSoundTypeWAV)) != 0) { + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, s, -1, scaleMixerVolume(p->volume)); } break; case 6: _mixer->stopHandle(_musicHandle); - if ((s = loadSoundFileAsStream(p->index, kAnimationSoundType16BitsRAW)) != 0) { + if ((s = loadSoundFileAsStream(p->num, kAnimationSoundType16BitsRAW)) != 0) { _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, s, -1, scaleMixerVolume(p->volume)); } break; @@ -796,8 +746,7 @@ uint8 *AnimationSequencePlayer::loadPicture(const char *fileName) { } void AnimationSequencePlayer::getRGBPalette(int index) { - byte rgbPalette[3 * 256]; - memcpy(rgbPalette, _flicPlayer[index].getPalette(), 3 * 256); + const byte *rgbPalette = _flicPlayer[index].getPalette(); for (int i = 0; i < 256; i++) { _animationPalette[i * 4 + 0] = rgbPalette[i * 3 + 0]; _animationPalette[i * 4 + 1] = rgbPalette[i * 3 + 1]; diff --git a/engines/tucker/staticres.cpp b/engines/tucker/staticres.cpp index 62472e2704..b663fb38da 100644 --- a/engines/tucker/staticres.cpp +++ b/engines/tucker/staticres.cpp @@ -246,138 +246,181 @@ const uint8 TuckerEngine::_charWidthCharset2[58] = { 0x13, 0x12, 0x10, 0x11, 0x13, 0x14, 0x14, 0x10, 0x13, 0x10, }; -const SoundSequenceData AnimationSequencePlayer::_soundSeqData[] = { - { 16, 3, 1, 100 }, { 18, 5, 1, 100 }, { 26, 9, 5, 100 }, { 74, 9, 0, 100 }, - { 118, 10, 0, 100 }, { 139, 9, 0, 100 }, { 140, 10, 2, 100 }, { 144, 5, 2, 100 }, - { 146, 3, 2, 100 }, { 147, 9, 2, 100 }, { 148, 2, 1, 100 }, { 156, 0, 1, 50 }, - { 158, 4, 5, 100 }, { 188, 4, 5, 100 }, { 212, 2, 2, 100 }, { 223, 1, 0, 100 }, - { 230, 1, 2, 100 }, { 234, 1, 0, 100 }, { 251, 1, 0, 100 }, { 265, 11, 6, 80 }, - { 293, 5, 1, 80 }, { 295, 12, 6, 80 }, { 343, 13, 6, 110 }, { 373, 14, 6, 80 }, - { 429, 5, 2, 100 }, { 431, 15, 6, 80 }, { 456, 2, 1, 100 }, { 457, 1, 5, 100 }, - { 463, 0, 5, 100 }, { 482, 2, 2, 100 }, { 483, 8, 1, 100 }, { 494, 8, 5, 100 }, - { 507, 7, 5, 100 }, { 511, 7, 5, 100 }, { 522, 13, 1, 100 }, { 547, 6, 5, 100 }, - { 548, 11, 0, 100 }, { 556, 12, 0, 100 }, { 557, 2, 5, 100 }, { 599, 7, 1, 100 }, - { 639, 7, 2, 100 }, { 641, 12, 0, 100 }, { 642, 7, 5, 100 }, { 718, 14, 2, 100 }, - { 719, 1, 2, 100 }, { 720, 2, 2, 100 }, { 721, 3, 2, 100 }, { 722, 4, 2, 100 }, - { 723, 5, 2, 100 }, { 724, 6, 2, 100 }, { 725, 7, 2, 100 }, { 726, 8, 2, 100 }, - { 727, 9, 2, 100 }, { 728, 10, 2, 100 }, { 729, 11, 2, 100 }, { 730, 12, 2, 100 }, - { 731, 0, 2, 100 }, { 732, 13, 2, 100 }, - // count 2,58 - // offset 3,58 - { 2, 0, 3, 100 }, { 3, 2, 0, 100 }, { 3, 5, 1, 20 }, { 6, 25, 6, 80 }, - { 22, 1, 5, 100 }, { 37, 29, 6, 80 }, { 59, 30, 6, 80 }, { 69, 26, 6, 80 }, - { 124, 27, 6, 80 }, { 163, 28, 6, 80 }, { 197, 31, 6, 80 }, { 224, 32, 6, 80 }, - { 306, 33, 6, 80 }, { 350, 34, 6, 80 }, { 388, 8, 0, 100 }, { 389, 6, 1, 100 }, - { 390, 9, 1, 100 }, { 395, 10, 0, 100 }, { 398, 3, 0, 100 }, { 408, 3, 0, 100 }, - { 413, 4, 0, 100 }, { 418, 3, 0, 100 }, { 426, 6, 2, 100 }, { 427, 9, 2, 100 }, - { 430, 35, 6, 80 }, { 472, 36, 6, 80 }, { 514, 9, 1, 100 }, { 515, 7, 0, 100 }, - { 516, 6, 1, 100 }, { 517, 4, 0, 100 }, { 520, 11, 0, 100 }, { 523, 3, 0, 100 }, - { 531, 7, 2, 100 }, { 532, 9, 2, 100 }, { 533, 6, 2, 100 }, { 534, 3, 0, 100 }, - { 535, 37, 6, 80 }, { 553, 38, 6, 80 }, { 569, 39, 6, 80 }, { 588, 40, 6, 80 }, - { 662, 41, 6, 80 }, { 777, 42, 6, 80 }, { 978, 1, 0, 100 }, { 1008, 12, 0, 100 }, - { 1011, 4, 5, 100 }, { 1022, 52, 6, 80 }, { 1039, 3, 5, 100 }, { 1045, 3, 5, 100 }, - { 1051, 3, 5, 100 }, { 1057, 3, 5, 100 }, { 1063, 3, 5, 100 }, { 1066, 3, 5, 40 }, - { 1074, 43, 6, 80 }, { 1256, 44, 6, 80 }, { 1322, 45, 6, 80 }, { 1373, 46, 6, 80 }, - { 1419, 47, 6, 80 }, { 1792, 13, 0, 100 }, { 1793, 0, 5, 100 }, { 1895, 51, 6, 80 }, - // count 3,60 - // offset 4,118 - { 2, 0, 3, 100 }, { 4, 3, 1, 40 }, { 5, 7, 1, 20 }, { 7, 3, 5, 100 }, - { 62, 3, 2, 100 }, { 63, 48, 6, 80 }, { 198, 7, 2, 100 }, { 202, 5, 1, 100 }, - { 203, 16, 6, 80 }, { 211, 1, 5, 100 }, { 216, 0, 1, 40 }, { 217, 5, 2, 100 }, - { 218, 6, 1, 100 }, { 224, 2, 5, 100 }, { 229, 17, 6, 80 }, { 273, 6, 2, 100 }, - { 274, 4, 1, 100 }, { 275, 4, 5, 100 }, { 335, 1, 1, 100 }, { 336, 13, 0, 100 }, - { 339, 11, 0, 100 }, { 358, 0, 5, 100 }, { 364, 24, 4, 100 }, { 397, 7, 5, 100 }, - { 399, 6, 5, 100 }, { 433, 5, 5, 100 }, { 451, 13, 0, 100 }, { 459, 1, 2, 100 }, - { 508, 4, 2, 100 }, { 509, 1, 1, 100 }, { 521, 11, 0, 100 }, { 530, 8, 0, 100 }, - { 537, 9, 0, 100 }, { 557, 8, 5, 100 }, { 578, 5, 5, 100 }, { 602, 13, 0, 100 }, - { 609, 1, 2, 100 }, { 626, 12, 0, 100 }, { 628, 10, 0, 100 }, { 670, 6, 5, 100 }, - { 690, 10, 0, 100 }, { 692, 3, 5, 100 }, { 705, 11, 0, 100 }, { 710, 2, 5, 100 }, - { 714, 9, 0, 100 }, { 720, 9, 2, 100 }, { 721, 7, 5, 100 }, { 725, 0, 5, 100 }, - // count 4,48 - // offset 5,166 - { 3, 8, 0, 100 }, { 43, 11, 0, 100 }, { 68, 5, 1, 100 }, { 100, 5, 2, 100 }, - { 104, 6, 0, 100 }, { 139, 7, 0, 100 }, { 192, 3, 0, 100 }, { 199, 4, 0, 100 }, - { 207, 4, 0, 100 }, { 208, 2, 0, 100 }, { 254, 0, 0, 100 }, { 260, 0, 0, 100 }, - { 266, 0, 0, 100 }, { 272, 0, 0, 100 }, { 276, 0, 0, 100 }, { 282, 1, 0, 100 }, - { 303, 10, 0, 100 }, { 319, 12, 0, 100 }, { 355, 9, 0, 100 }, - // count 5,19 - // offset 6,185 - { 3, 0, 1, 100 }, { 34, 0, 2, 100 }, { 57, 0, 5, 100 }, { 77, 0, 5, 100 }, - { 84, 9, 0, 100 }, { 100, 9, 0, 100 }, { 140, 3, 5, 100 }, { 157, 2, 5, 100 }, - { 158, 1, 0, 100 }, { 204, 1, 5, 100 }, { 220, 2, 1, 100 }, { 235, 7, 0, 100 }, - { 236, 2, 2, 100 }, { 248, 12, 0, 100 }, { 251, 13, 0, 100 }, { 265, 11, 0, 100 }, - { 276, 11, 0, 100 }, { 310, 5, 0, 100 }, { 335, 6, 0, 100 }, { 370, 4, 0, 100 }, - { 373, 8, 0, 100 }, { 378, 8, 0, 100 }, { 434, 10, 0, 100 }, { 453, 3, 0, 100 }, - { 484, 3, 2, 100 }, - // count 6,25 - // offset 7,210 - { 3, 4, 5, 100 }, { 10, 5, 5, 100 }, { 22, 6, 5, 100 }, { 32, 7, 5, 100 }, - { 39, 6, 5, 100 }, { 48, 7, 5, 100 }, { 57, 6, 5, 100 }, { 65, 3, 0, 50 }, - { 102, 4, 0, 50 }, { 151, 2, 5, 50 }, { 205, 3, 5, 100 }, { 218, 0, 5, 100 }, - { 227, 0, 5, 100 }, { 236, 0, 5, 100 }, { 245, 0, 5, 100 }, { 254, 0, 5, 100 }, - { 263, 0, 5, 100 }, { 272, 0, 5, 100 }, { 291, 1, 1, 40 }, { 309, 8, 5, 100 }, - { 360, 8, 5, 100 }, { 384, 2, 1, 60 }, { 398, 10, 0, 100 }, { 440, 2, 2, 100 }, - { 441, 1, 2, 100 }, { 452, 11, 0, 100 }, { 466, 1, 5, 100 }, { 470, 8, 0, 100 }, - { 503, 6, 0, 100 }, { 519, 7, 0, 100 }, { 536, 8, 0, 100 }, { 538, 4, 5, 100 }, - { 549, 5, 5, 100 }, { 558, 4, 5, 100 }, { 568, 5, 5, 100 }, { 578, 4, 5, 100 }, - { 586, 5, 5, 100 }, { 593, 4, 5, 100 }, { 600, 5, 5, 100 }, { 606, 4, 5, 100 }, - { 613, 5, 5, 100 }, { 620, 9, 0, 100 }, { 630, 12, 0, 100 }, - // count 7,43 - // offset 8,253 - { 17, 2, 0, 100 }, { 57, 8, 0, 100 }, { 62, 10, 0, 100 }, { 67, 9, 0, 100 }, - { 74, 3, 1, 100 }, { 87, 3, 2, 100 }, { 85, 0, 0, 100 }, { 138, 5, 0, 100 }, - { 196, 7, 0, 100 }, { 222, 6, 0, 100 }, { 228, 1, 0, 100 }, - // count 8,11 - // offset 9,264 - { 20, 4, 0, 100 }, { 132, 0, 0, 100 }, { 145, 0, 2, 100 }, { 171, 1, 0, 100 }, - { 315, 2, 0, 50 }, { 334, 3, 0, 100 }, { 602, 5, 0, 50 }, { 631, 5, 0, 50 }, - { 660, 5, 0, 50 }, { 767, 5, 0, 50 }, { 795, 5, 0, 50 }, { 824, 5, 0, 50 }, - // count 9,12 - // offset 10,276 - { 4, 8, 1, 100 }, { 5, 6, 0, 100 }, { 47, 8, 2, 100 }, { 125, 8, 1, 100 }, - { 126, 6, 0, 100 }, { 156, 8, 2, 100 }, { 168, 2, 0, 100 }, { 174, 2, 0, 100 }, - { 180, 2, 0, 100 }, { 186, 2, 0, 100 }, { 192, 2, 0, 100 }, { 267, 2, 0, 100 }, - { 273, 2, 0, 100 }, { 279, 2, 0, 100 }, { 285, 2, 0, 100 }, { 291, 2, 0, 100 }, - { 297, 2, 0, 100 }, { 302, 0, 0, 100 }, { 417, 1, 0, 100 }, { 472, 5, 0, 100 }, - { 600, 5, 0, 100 }, { 623, 3, 0, 100 }, { 643, 9, 0, 100 }, { 781, 4, 0, 80 }, - // count 10,24 - // offset 11,300 - { 2, 0, 3, 100 }, { 3, 0, 1, 100 }, { 33, 0, 2, 100 }, { 33, 1, 0, 100 }, - { 53, 2, 1, 100 }, { 78, 2, 2, 100 }, { 80, 0, 4, 100 } - // count 11,7 +static const SoundSequenceData _soundDataSeq3_4[] = { + { 16, 3, 33, 100, 1 }, { 18, 5, 34, 100, 1 }, { 26, 9, 16, 100, 5 }, { 74, 9, 35, 100, 0 }, + { 118, 10, 36, 100, 0 }, { 139, 9, 35, 100, 0 }, { 140, 10, 0, 100, 2 }, { 144, 5, 0, 100, 2 }, + { 146, 3, 0, 100, 2 }, { 147, 9, 0, 100, 2 }, { 148, 2, 30, 100, 1 }, { 156, 0, 103, 50, 1 }, + { 158, 4, 31, 100, 5 }, { 188, 4, 31, 100, 5 }, { 212, 2, 0, 100, 2 }, { 223, 1, 20, 100, 0 }, + { 230, 1, 0, 100, 2 }, { 234, 1, 20, 100, 0 }, { 251, 1, 20, 100, 0 }, { 265, 11, 69, 80, 6 }, + { 293, 5, 34, 80, 1 }, { 295, 12, 76, 80, 6 }, { 343, 13, 87, 110, 6 }, { 373, 14, 97, 80, 6 }, + { 429, 5, 0, 100, 2 }, { 431, 15, 100, 80, 6 }, { 456, 2, 30, 100, 1 }, { 457, 1, 19, 100, 5 }, + { 463, 0, 18, 100, 5 }, { 482, 2, 0, 100, 2 }, { 483, 8, 40, 100, 1 }, { 494, 8, 37, 100, 5 }, + { 507, 7, 17, 100, 5 }, { 511, 7, 17, 100, 5 }, { 522, 13, 21, 100, 1 }, { 547, 6, 49, 100, 5 }, + { 548, 11, 48, 100, 0 }, { 556, 12, 38, 100, 0 }, { 557, 2, 23, 100, 5 }, { 599, 7, 39, 100, 1 }, + { 639, 7, 0, 100, 2 }, { 641, 12, 38, 100, 0 }, { 642, 7, 17, 100, 5 }, { 718, 14, 0, 100, 2 }, + { 719, 1, 0, 100, 2 }, { 720, 2, 0, 100, 2 }, { 721, 3, 0, 100, 2 }, { 722, 4, 0, 100, 2 }, + { 723, 5, 0, 100, 2 }, { 724, 6, 0, 100, 2 }, { 725, 7, 0, 100, 2 }, { 726, 8, 0, 100, 2 }, + { 727, 9, 0, 100, 2 }, { 728, 10, 0, 100, 2 }, { 729, 11, 0, 100, 2 }, { 730, 12, 0, 100, 2 }, + { 731, 0, 0, 100, 2 }, { 732, 13, 0, 100, 2 }, }; -const char *AnimationSequencePlayer::_musicFileNamesTable[] = { +static const SoundSequenceData _soundDataSeq9_10[] = { + { 2, 0, 0, 100, 3 }, { 3, 2, 32, 100, 0 }, { 3, 5, 54, 20, 1 }, { 6, 25, 71, 80, 6 }, + { 22, 1, 18, 100, 5 }, { 37, 29, 75, 80, 6 }, { 59, 30, 77, 80, 6 }, { 69, 26, 72, 80, 6 }, + { 124, 27, 73, 80, 6 }, { 163, 28, 74, 80, 6 }, { 197, 31, 78, 80, 6 }, { 224, 32, 79, 80, 6 }, + { 306, 33, 80, 80, 6 }, { 350, 34, 81, 80, 6 }, { 388, 8, 57, 100, 0 }, { 389, 6, 55, 100, 1 }, + { 390, 9, 58, 100, 1 }, { 395, 10, 59, 100, 0 }, { 398, 3, 52, 100, 0 }, { 408, 3, 52, 100, 0 }, + { 413, 4, 53, 100, 0 }, { 418, 3, 52, 100, 0 }, { 426, 6, 0, 100, 2 }, { 427, 9, 0, 100, 2 }, + { 430, 35, 82, 80, 6 }, { 472, 36, 83, 80, 6 }, { 514, 9, 58, 100, 1 }, { 515, 7, 56, 100, 0 }, + { 516, 6, 55, 100, 1 }, { 517, 4, 53, 100, 0 }, { 520, 11, 60, 100, 0 }, { 523, 3, 52, 100, 0 }, + { 531, 7, 0, 100, 2 }, { 532, 9, 0, 100, 2 }, { 533, 6, 0, 100, 2 }, { 534, 3, 52, 100, 0 }, + { 535, 37, 84, 80, 6 }, { 553, 38, 85, 80, 6 }, { 569, 39, 86, 80, 6 }, { 588, 40, 88, 80, 6 }, + { 662, 41, 89, 80, 6 }, { 777, 42, 90, 80, 6 }, { 978, 1, 22, 100, 0 }, { 1008, 12, 61, 100, 0 }, + { 1011, 4, 15, 100, 5 }, { 1022, 52, 99, 80, 6 }, { 1039, 3, 63, 100, 5 }, { 1045, 3, 63, 100, 5 }, + { 1051, 3, 63, 100, 5 }, { 1057, 3, 63, 100, 5 }, { 1063, 3, 63, 100, 5 }, { 1066, 3, 63, 40, 5 }, + { 1074, 43, 91, 80, 6 }, { 1256, 44, 92, 80, 6 }, { 1322, 45, 93, 80, 6 }, { 1373, 46, 94, 80, 6 }, + { 1419, 47, 95, 80, 6 }, { 1792, 13, 62, 100, 0 }, { 1793, 0, 50, 100, 5 }, { 1895, 51, 98, 80, 6 }, +}; + +static const SoundSequenceData _soundDataSeq21_20[] = { + { 2, 0, 0, 100, 3 }, { 4, 3, 34, 40, 1 }, { 5, 7, 54, 20, 1 }, { 7, 3, 51, 100, 5 }, + { 62, 3, 0, 100, 2 }, { 63, 48, 96, 80, 6 }, { 198, 7, 0, 100, 2 }, { 202, 5, 46, 100, 1 }, + { 203, 16, 101, 80, 6 }, { 211, 1, 41, 100, 5 }, { 216, 0, 103, 40, 1 }, { 217, 5, 0, 100, 2 }, + { 218, 6, 47, 100, 1 }, { 224, 2, 43, 100, 5 }, { 229, 17, 102, 80, 6 }, { 273, 6, 0, 100, 2 }, + { 274, 4, 40, 100, 1 }, { 275, 4, 44, 100, 5 }, { 335, 1, 21, 100, 1 }, { 336, 13, 42, 100, 0 }, + { 339, 11, 28, 100, 0 }, { 358, 0, 25, 100, 5 }, { 364, 24, 70, 100, 4 }, { 397, 7, 49, 100, 5 }, + { 399, 6, 48, 100, 5 }, { 433, 5, 45, 100, 5 }, { 451, 13, 42, 100, 0 }, { 459, 1, 0, 100, 2 }, + { 508, 4, 0, 100, 2 }, { 509, 1, 21, 100, 1 }, { 521, 11, 28, 100, 0 }, { 530, 8, 118, 100, 0 }, + { 537, 9, 26, 100, 0 }, { 557, 8, 106, 100, 5 }, { 578, 5, 45, 100, 5 }, { 602, 13, 42, 100, 0 }, + { 609, 1, 0, 100, 2 }, { 626, 12, 29, 100, 0 }, { 628, 10, 27, 100, 0 }, { 670, 6, 48, 100, 5 }, + { 690, 10, 27, 100, 0 }, { 692, 3, 51, 100, 5 }, { 705, 11, 28, 100, 0 }, { 710, 2, 43, 100, 5 }, + { 714, 9, 26, 100, 0 }, { 720, 9, 0, 100, 2 }, { 721, 7, 49, 100, 5 }, { 725, 0, 25, 100, 5 }, +}; + +static const SoundSequenceData _soundDataSeq13_14[] = { + { 3, 0, 128, 100, 1 }, { 34, 0, 0, 100, 2 }, { 57, 0, 123, 100, 5 }, { 77, 0, 123, 100, 5 }, + { 84, 9, 24, 100, 0 }, { 100, 9, 24, 100, 0 }, { 140, 3, 19, 100, 5 }, { 157, 2, 109, 100, 5 }, + { 158, 1, 129, 100, 0 }, { 204, 1, 114, 100, 5 }, { 220, 2, 107, 100, 1 }, { 235, 7, 113, 100, 0 }, + { 236, 2, 0, 100, 2 }, { 248, 12, 118, 100, 0 }, { 251, 13, 119, 100, 0 }, { 265, 11, 117, 100, 0 }, + { 276, 11, 117, 100, 0 }, { 310, 5, 110, 100, 0 }, { 335, 6, 112, 100, 0 }, { 370, 4, 124, 100, 0 }, + { 373, 8, 127, 100, 0 }, { 378, 8, 127, 100, 0 }, { 434, 10, 120, 100, 0 }, { 453, 3, 108, 100, 0 }, + { 484, 3, 0, 100, 2 }, +}; + +static const SoundSequenceData _soundDataSeq15_16[] = { + { 3, 4, 3, 100, 5 }, { 10, 5, 4, 100, 5 }, { 22, 6, 64, 100, 5 }, { 32, 7, 65, 100, 5 }, + { 39, 6, 64, 100, 5 }, { 48, 7, 65, 100, 5 }, { 57, 6, 64, 100, 5 }, { 65, 3, 67, 50, 0 }, + { 102, 4, 68, 50, 0 }, { 151, 2, 12, 50, 5 }, { 205, 3, 5, 100, 5 }, { 218, 0, 63, 100, 5 }, + { 227, 0, 63, 100, 5 }, { 236, 0, 63, 100, 5 }, { 245, 0, 63, 100, 5 }, { 254, 0, 63, 100, 5 }, + { 263, 0, 63, 100, 5 }, { 272, 0, 63, 100, 5 }, { 291, 1, 54, 40, 1 }, { 309, 8, 6, 100, 5 }, + { 360, 8, 6, 100, 5 }, { 384, 2, 55, 60, 1 }, { 398, 10, 66, 100, 0 }, { 440, 2, 0, 100, 2 }, + { 441, 1, 0, 100, 2 }, { 452, 11, 62, 100, 0 }, { 466, 1, 2, 100, 5 }, { 470, 8, 9, 100, 0 }, + { 503, 6, 7, 100, 0 }, { 519, 7, 8, 100, 0 }, { 536, 8, 9, 100, 0 }, { 538, 4, 3, 100, 5 }, + { 549, 5, 4, 100, 5 }, { 558, 4, 3, 100, 5 }, { 568, 5, 4, 100, 5 }, { 578, 4, 3, 100, 5 }, + { 586, 5, 4, 100, 5 }, { 593, 4, 3, 100, 5 }, { 600, 5, 4, 100, 5 }, { 606, 4, 3, 100, 5 }, + { 613, 5, 4, 100, 5 }, { 620, 9, 10, 100, 0 }, { 630, 12, 11, 100, 0 }, +}; + +static const SoundSequenceData _soundDataSeq27_28[] = { + { 17, 2, 111, 100, 0 }, { 57, 8, 105, 100, 0 }, { 62, 10, 126, 100, 0 }, { 67, 9, 110, 100, 0 }, + { 74, 3, 115, 100, 1 }, { 87, 3, 0, 100, 2 }, { 85, 0, 121, 100, 0 }, { 138, 5, 116, 100, 0 }, + { 196, 7, 125, 100, 0 }, { 222, 6, 122, 100, 0 }, { 228, 1, 129, 100, 0 }, +}; + +static const SoundSequenceData _soundDataSeq19_20[] = { + { 2, 0, 0, 100, 3 }, { 3, 0, 115, 100, 1 }, { 33, 0, 0, 100, 2 }, { 33, 1, 13, 100, 0 }, + { 53, 2, 14, 100, 1 }, { 78, 2, 0, 100, 2 }, { 80, 0, 0, 100, 4 }, +}; + +const SoundSequenceDataList AnimationSequencePlayer::_soundSeqDataList[] = { + { 0, 0, 14, 10, 58, _soundDataSeq3_4 }, + { 0, 0, 14, 5, 60, _soundDataSeq9_10 }, + { 0, 0, 14, 9, 48, _soundDataSeq21_20 }, + { 1, 80, 14, 4, 25, _soundDataSeq13_14 }, + { 1, 80, 13, 9, 43, _soundDataSeq15_16 }, + { 1, 80, 11, 0, 11, _soundDataSeq27_28 }, + { 104, 100, 0, 0, 0, 0 }, + { 0, 100, 4, 0, 7, _soundDataSeq19_20 } +}; + +const char *AnimationSequencePlayer::_audioFileNamesTable[] = { "demomenu.raw", - "introdub.raw", - "introdua.raw", - "demorola.raw", - "democha1.raw", - "icrmusic.raw", - "demorolc.raw", - "demorolc.raw", - "merilogo.raw", - "democha2.raw", "demorolc.raw", + "fx101.wav", + "fx102.wav", + "fx103.wav", + "fx104.wav", + "fx105.wav", + "fx107.wav", + "fx108.wav", + "fx109.wav", + "fx110.wav", + "fx111.wav", + "fx112.wav", + "fx113.wav", + "fx114.wav", + "fx116.wav", + "fx117.wav", + "fx32.wav", + "fx33.wav", + "fx34.wav", + "fx35.wav", + "fx36.wav", + "fx37.wav", + "fx38.wav", + "fx39.wav", + "fx40.wav", + "fx42.wav", + "fx43.wav", + "fx44.wav", + "fx45.wav", + "fx47.wav", + "fx48.wav", + "fx49.wav", + "fx50.wav", + "fx52.wav", + "fx53.wav", + "fx55.wav", + "fx56.wav", + "fx57.wav", + "fx58.wav", + "fx59.wav", + "fx60.wav", + "fx61.wav", + "fx62.wav", + "fx63.wav", + "fx64.wav", + "fx66.wav", + "fx67.wav", + "fx68.wav", + "fx69.wav", + "fx70.wav", + "fx71.wav", + "fx72.wav", + "fx73.wav", + "fx74.wav", + "fx75.wav", + "fx76.wav", + "fx77.wav", + "fx78.wav", + "fx79.wav", + "fx80.wav", + "fx81.wav", + "fx83.wav", + "fx86.wav", + "fx91.wav", + "fx92.wav", + "fx93.wav", + "fx97.wav", + "fx98.wav", "int1.raw", - "int2.raw", - "int3.raw", - "int4.raw", - "int5.raw", - "int6.raw", - "int7.raw", - "int8.raw", - "int9.raw", - "int10.raw", - "int11.raw", - "int12.raw", - "int13.raw", "int14.raw", "int15.raw", "int16.raw", "int17.raw", "int18.raw", "int19.raw", + "int2.raw", "int20.raw", "int21.raw", "int22.raw", @@ -388,6 +431,7 @@ const char *AnimationSequencePlayer::_musicFileNamesTable[] = { "int27.raw", "int28.raw", "int29.raw", + "int3.raw", "int30.raw", "int31.raw", "int32.raw", @@ -397,177 +441,39 @@ const char *AnimationSequencePlayer::_musicFileNamesTable[] = { "int36.raw", "int37.raw", "int38.raw", - "int39.raw", - "int40.raw", + "int4.raw", "int41.raw", - "int42.raw" -}; - -const char *AnimationSequencePlayer::_audioFileNamesTable[] = { - "introdua.wav", - "fx35.wav", - "fx47.wav", - "fx50.wav", - "fx51.wav", - "fx52.wav", - "fx54.wav", - "fx58.wav", - "fx59.wav", - "fx53.wav", - "fx55.wav", - "fx68.wav", - "fx57.wav", - "fx36.wav", - // offset 2,14 - "fx33.wav", - "fx34.wav", - "fx38.wav", - "fx39.wav", - "fx48.wav", - "fx49.wav", - "fx69.wav", - "fx32.wav", - "fx56.wav", - "fx117.wav", - // offset 3,24 - "introdua.wav", - "fx37.wav", - "fx49.wav", - "fx72.wav", - "fx73.wav", - "fx74.wav", - "fx75.wav", - "fx76.wav", - "fx77.wav", - "fx78.wav", - "fx79.wav", - "fx80.wav", - "fx81.wav", - "fx83.wav", - // offset 4,38 - "fx70.wav", - "fx33.wav", - "rdfx12.wav", - "fx86.wav", - "fx116.wav", - // offset 5,43 + "int42.raw", + "int5.raw", + "int6.raw", + "int7.raw", "introdua.wav", - "fx36.wav", - "fx46.wav", - "fx52.wav", - "fx59.wav", - "fx66.wav", - "fx67.wav", - "fx74.wav", - "rdfx26.wav", - "fx42.wav", - "fx43.wav", - "fx44.wav", - "fx45.wav", - "fx61.wav", - // offset 6,57 - "fx40.wav", - "fx60.wav", - "fx62.wav", - "fx71.wav", - "fx63.wav", - "fx64.wav", - "fx68.wav", - "fx69.wav", - "rdfx12.wav", - // offset 7,66 + "merilogo.raw", "rdfx1.wav", - "rdfx2.wav", - "rdfx4.wav", - "rdfx5.wav", - "rdfx6.wav", - "rdfx7.wav", - "rdfx10.wav", - "rdfx11.wav", "rdfx12.wav", - "rdfx19.wav", - "rdfx29.wav", - "rdfx32.wav", - "rdfx35.wav", - // offset 8,79 - "rdfx8.wav", - "rdfx9.wav", "rdfx13.wav", "rdfx14.wav", - "rdfx33.wav", + "rdfx15.wav", "rdfx16.wav", + "rdfx17.wav", "rdfx18.wav", "rdfx20.wav", - "rdfx38.wav", - "fx39.wav", - "rdfx28.wav", + "rdfx21.wav", + "rdfx22.wav", + "rdfx24.wav", "rdfx25.wav", "rdfx26.wav", "rdfx27.wav", - // offset 9,93 - "rdfx31.wav", - "rdfx21.wav", - "rdfx15.wav", - "fx34.wav", - // offset 10,97 - "fx96.wav", - "fx74.wav", - "fx75.wav", - "fx97.wav", - "fx98.wav", - "fx106.wav", - "fx107.wav", - "fx108.wav", - "fx109.wav", - "fx110.wav", - "fx93.wav", - "fx83.wav", - "fx111.wav", - // offset 11,110 - "fx86.wav", - "fx101.wav", - "fx112.wav", - "fx104.wav", - "fx102.wav", - "fx103.wav", - "fx91.wav", - "fx92.wav", - "fx105.wav", - // offset 12,119 + "rdfx28.wav", "rdfx3.wav", - "rdfx9.wav", - "rdfx17.wav", - "rdfx22.wav", - "rdfx23.wav", - "rdfx24.wav", "rdfx30.wav", + "rdfx31.wav", + "rdfx33.wav", "rdfx36.wav", - "rdfx1.wav", - "rdfx16.wav", "rdfx37.wav", - // offset 13,130 - "fx82.wav", - "fx80.wav", - "fx89.wav", - "fx90.wav", - "fx83.wav", - "fx84.wav", - // offset 14,136 - "rdfx2.wav", - "fx85.wav", - "fx86.wav", - "fx87.wav", - "fx88.wav", - "fx99.wav", - "fx98.wav", - "fx97.wav", - "fx96.wav", - "fx100.wav", - // offset 15,146 - "rdfx22.wav", - "fx113.wav", - "fx114.wav", - "fx115.wav" + "rdfx38.wav", + "rdfx8.wav", + "rdfx9.wav", }; } // namespace Tucker diff --git a/engines/tucker/tucker.cpp b/engines/tucker/tucker.cpp index cedd9ec723..692335d5ef 100644 --- a/engines/tucker/tucker.cpp +++ b/engines/tucker/tucker.cpp @@ -304,7 +304,7 @@ void TuckerEngine::restart() { _currentGfxBackgroundCounter = 0; _currentGfxBackground = 0; _fadePaletteCounter = 0; - memset(&_currentPalette, 0, sizeof(_currentPalette)); + memset(_currentPalette, 0, sizeof(_currentPalette)); _fullRedrawCounter = 0; _dirtyRectsPrevCount = _dirtyRectsCount = 0; @@ -3395,7 +3395,6 @@ void TuckerEngine::setSelectedObjectKey() { _selectedObject.locationObject_toY2 = _locationObjectsTable[_selectedCharacterNum].toY2; _selectedObject.locationObject_toWalkX2 = _locationObjectsTable[_selectedCharacterNum].toWalkX2; _selectedObject.locationObject_toWalkY2 = _locationObjectsTable[_selectedCharacterNum].toWalkY2; - } } } else { diff --git a/engines/tucker/tucker.h b/engines/tucker/tucker.h index 966900c923..6afccdc4da 100644 --- a/engines/tucker/tucker.h +++ b/engines/tucker/tucker.h @@ -848,11 +848,32 @@ enum AnimationSoundType { kAnimationSoundTypeLoopingWAV }; +enum { + kSoundsList_Seq3_4, + kSoundsList_Seq9_10, + kSoundsList_Seq21_20, + kSoundsList_Seq13_14, + kSoundsList_Seq15_16, + kSoundsList_Seq27_28, + kSoundsList_Seq17_18, + kSoundsList_Seq19_20 +}; + struct SoundSequenceData { int timestamp; int index; - int opcode; + int num; int volume; + int opcode; +}; + +struct SoundSequenceDataList { + int musicIndex; + int musicVolume; + int soundList1Count; + int soundList2Count; + int soundSeqDataCount; + const SoundSequenceData *soundSeqData; }; class AnimationSequencePlayer { @@ -919,13 +940,9 @@ private: int _updateFuncIndex; ::Graphics::FlicDecoder _flicPlayer[2]; uint8 _animationPalette[256 * 4]; - int _soundsList1Offset; - int _soundsList1Count; - int _soundsList2Offset; - int _soundsList2Count; - int _soundSeqDataOffset; int _soundSeqDataCount; int _soundSeqDataIndex; + const SoundSequenceData *_soundSeqData; uint8 *_offscreenBuffer; int _updateScreenWidth; int _updateScreenPicture; @@ -938,8 +955,7 @@ private: Audio::SoundHandle _sfxHandle; Audio::SoundHandle _musicHandle; - static const SoundSequenceData _soundSeqData[]; - static const char *_musicFileNamesTable[]; + static const SoundSequenceDataList _soundSeqDataList[]; static const char *_audioFileNamesTable[]; }; |