aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/animator_hof.cpp8
-rw-r--r--engines/kyra/animator_mr.cpp6
-rw-r--r--engines/kyra/debugger.cpp1
-rw-r--r--engines/kyra/detection.cpp103
-rw-r--r--engines/kyra/gui_hof.cpp4
-rw-r--r--engines/kyra/gui_lok.cpp2
-rw-r--r--engines/kyra/items_lok.cpp8
-rw-r--r--engines/kyra/kyra_hof.cpp35
-rw-r--r--engines/kyra/kyra_hof.h7
-rw-r--r--engines/kyra/kyra_lok.cpp1
-rw-r--r--engines/kyra/kyra_lok.h14
-rw-r--r--engines/kyra/kyra_mr.cpp9
-rw-r--r--engines/kyra/kyra_mr.h5
-rw-r--r--engines/kyra/kyra_v1.cpp5
-rw-r--r--engines/kyra/kyra_v1.h18
-rw-r--r--engines/kyra/kyra_v2.cpp22
-rw-r--r--engines/kyra/kyra_v2.h5
-rw-r--r--engines/kyra/resource.cpp817
-rw-r--r--engines/kyra/resource.h20
-rw-r--r--engines/kyra/scene_lok.cpp12
-rw-r--r--engines/kyra/scene_v2.cpp5
-rw-r--r--engines/kyra/script_hof.cpp4
-rw-r--r--engines/kyra/script_lok.cpp65
-rw-r--r--engines/kyra/script_v1.cpp4
-rw-r--r--engines/kyra/sequences_hof.cpp208
-rw-r--r--engines/kyra/sound.cpp42
-rw-r--r--engines/kyra/sound.h13
-rw-r--r--engines/kyra/sound_lok.cpp9
-rw-r--r--engines/kyra/sound_towns.cpp7
-rw-r--r--engines/kyra/staticres.cpp58
-rw-r--r--engines/kyra/text.cpp2
-rw-r--r--engines/kyra/text_hof.cpp3
-rw-r--r--engines/kyra/text_lok.cpp6
-rw-r--r--engines/kyra/text_mr.cpp15
-rw-r--r--engines/kyra/vqa.cpp8
35 files changed, 1296 insertions, 255 deletions
diff --git a/engines/kyra/animator_hof.cpp b/engines/kyra/animator_hof.cpp
index 1192145530..c5d44d10af 100644
--- a/engines/kyra/animator_hof.cpp
+++ b/engines/kyra/animator_hof.cpp
@@ -127,12 +127,8 @@ void KyraEngine_HoF::updateItemAnimations() {
return;
const ItemAnimData_v2 *s = &_itemAnimData[_nextAnimItem];
- ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem];
-
- if (++_nextAnimItem == 14) {
- _nextAnimItem = 0;
- return;
- }
+ ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem];
+ _nextAnimItem = ++_nextAnimItem % _itemAnimDataSize;
uint32 ctime = _system->getMillis();
if (ctime < a->nextFrame)
diff --git a/engines/kyra/animator_mr.cpp b/engines/kyra/animator_mr.cpp
index f04ca0345d..9702499fe7 100644
--- a/engines/kyra/animator_mr.cpp
+++ b/engines/kyra/animator_mr.cpp
@@ -205,11 +205,7 @@ void KyraEngine_MR::updateItemAnimations() {
const ItemAnimData_v2 *s = &_itemAnimData[_nextAnimItem];
ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem];
-
- if (++_nextAnimItem == 11) {
- _nextAnimItem = 0;
- return;
- }
+ _nextAnimItem = ++_nextAnimItem % 10;
uint32 ctime = _system->getMillis();
if (ctime < a->nextFrame)
diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp
index 0d170dbf05..7ae5414d82 100644
--- a/engines/kyra/debugger.cpp
+++ b/engines/kyra/debugger.cpp
@@ -192,6 +192,7 @@ bool Debugger::cmd_setTimerCountdown(int argc, const char **argv) {
Debugger_LoK::Debugger_LoK(KyraEngine_LoK *vm)
: Debugger(vm), _vm(vm) {
+ DCmd_Register("enter", WRAP_METHOD(Debugger_LoK, cmd_enterRoom));
DCmd_Register("rooms", WRAP_METHOD(Debugger_LoK, cmd_listRooms));
DCmd_Register("give", WRAP_METHOD(Debugger_LoK, cmd_giveItem));
DCmd_Register("birthstones", WRAP_METHOD(Debugger_LoK, cmd_listBirthstones));
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 3c4c87e12b..a3ca2f829e 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -41,22 +41,25 @@ struct KYRAGameDescription {
namespace {
-#define FLAGS(x, y, z, a, b, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, id }
-
-#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, Kyra::GI_KYRA1)
-#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, Kyra::GI_KYRA1)
-#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, Kyra::GI_KYRA1)
-#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, Kyra::GI_KYRA1)
-#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, Kyra::GI_KYRA1)
-#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, Kyra::GI_KYRA1)
-
-#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, Kyra::GI_KYRA2)
-#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, Kyra::GI_KYRA2)
-#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, Kyra::GI_KYRA2)
-#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, Kyra::GI_KYRA2)
-#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, Kyra::GI_KYRA2)
-
-#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, Kyra::GI_KYRA3)
+#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id }
+
+#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1)
+#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1)
+#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, Kyra::GI_KYRA1)
+#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, false, Kyra::GI_KYRA1)
+#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, false, Kyra::GI_KYRA1)
+#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA1)
+
+#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2)
+#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA2)
+#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_KYRA2)
+#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, Kyra::GI_KYRA2)
+#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA2)
+#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2)
+#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_KYRA2)
+
+#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3)
+#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3)
const KYRAGameDescription adGameDescs[] = {
{
@@ -296,6 +299,66 @@ const KYRAGameDescription adGameDescs[] = {
KYRA1_DEMO_FLAGS
},
+ { // Floppy version
+ {
+ "kyra2",
+ 0,
+ AD_ENTRY1("WESTWOOD.001", "3f52dda68c4f7696c8309038be9f4151"),
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA2_FLOPPY_CMP_FLAGS
+ },
+
+ { // Floppy version
+ {
+ "kyra2",
+ 0,
+ AD_ENTRY1("WESTWOOD.001", "d787b9559afddfe058b84c0b3a787224"),
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA2_FLOPPY_CMP_FLAGS
+ },
+
+ { // // Floppy version extracted
+ {
+ "kyra2",
+ "Extracted",
+ AD_ENTRY1("FATE.PAK", "1ba18be685ad8e5a0ab5d46a0ce4d345"),
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA2_FLOPPY_FLAGS
+ },
+
+ { // Floppy version extracted
+ {
+ "kyra2",
+ "Extracted",
+ AD_ENTRY1("FATE.PAK", "262fb69dd8e52e596c7aefc6456f7c1b"),
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA2_FLOPPY_FLAGS
+ },
+
+ { // Floppy version extracted
+ {
+ "kyra2",
+ "Extracted",
+ AD_ENTRY1("FATE.PAK", "f7de11506b4c8fdf64bc763206c3e4e7"),
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ KYRA2_FLOPPY_FLAGS
+ },
+
{ // CD version
{
"kyra2",
@@ -417,7 +480,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_FLAGS
+ KYRA3_CD_INS_FLAGS
},
{
{
@@ -432,7 +495,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_FLAGS
+ KYRA3_CD_INS_FLAGS
},
{
{
@@ -447,7 +510,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::kPlatformPC,
Common::ADGF_DROPLANGUAGE
},
- KYRA3_CD_FLAGS
+ KYRA3_CD_INS_FLAGS
},
// installed version
@@ -497,7 +560,7 @@ const KYRAGameDescription adGameDescs[] = {
KYRA3_CD_FLAGS
},
- { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0) }
+ { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) }
};
const PlainGameDescriptor gameList[] = {
diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp
index 10f7f657a3..555934cb7f 100644
--- a/engines/kyra/gui_hof.cpp
+++ b/engines/kyra/gui_hof.cpp
@@ -455,12 +455,12 @@ void KyraEngine_HoF::showBookPage() {
char filename[16];
sprintf(filename, "PAGE%.01X.", _bookCurPage);
- strcat(filename, _languageExtension[_lang]);
+ strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT");
uint8 *leftPage = _res->fileData(filename, 0);
int leftPageY = _bookPageYOffset[_bookCurPage];
sprintf(filename, "PAGE%.01X.", _bookCurPage+1);
- strcat(filename, _languageExtension[_lang]);
+ strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT");
uint8 *rightPage = (_bookCurPage != _bookMaxPage) ? _res->fileData(filename, 0) : 0;
int rightPageY = _bookPageYOffset[_bookCurPage+1];
diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp
index 2b823b1ae7..6fa30c9e9a 100644
--- a/engines/kyra/gui_lok.cpp
+++ b/engines/kyra/gui_lok.cpp
@@ -337,6 +337,8 @@ void GUI_LoK::setGUILabels() {
} else if (_vm->gameFlags().lang == Common::ES_ESP) {
offsetOn = offsetMainMenu = offsetOptions = offset = -4;
menuLabelGarbageOffset = 72;
+ } else if (_vm->gameFlags().lang == Common::IT_ITA) {
+ offsetOn = offsetMainMenu = offsetOptions = offset = 32;
} else if (_vm->gameFlags().lang == Common::DE_DEU) {
offset = offsetMainMenu = offsetOn = offsetOptions = 24;
} else if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) {
diff --git a/engines/kyra/items_lok.cpp b/engines/kyra/items_lok.cpp
index e86be25707..8eb62c20c2 100644
--- a/engines/kyra/items_lok.cpp
+++ b/engines/kyra/items_lok.cpp
@@ -176,7 +176,7 @@ void KyraEngine_LoK::placeItemInGenericMapScene(int item, int index) {
}
void KyraEngine_LoK::setHandItem(uint16 item) {
- debugC(9, kDebugLevelMain, "KyraEngine_LoK::setHandItem(%d)", item);
+ debugC(9, kDebugLevelMain, "KyraEngine_LoK::setHandItem(%u)", item);
_screen->hideMouse();
setMouseItem(item);
_itemInHand = item;
@@ -191,9 +191,9 @@ void KyraEngine_LoK::removeHandItem() {
_screen->showMouse();
}
-void KyraEngine_LoK::setMouseItem(int item) {
- debugC(9, kDebugLevelMain, "KyraEngine_LoK::setMouseItem(%d)", item);
- if (item == -1)
+void KyraEngine_LoK::setMouseItem(uint16 item) {
+ debugC(9, kDebugLevelMain, "KyraEngine_LoK::setMouseItem(%u)", item);
+ if (item == 0xFFFF)
_screen->setMouseCursor(1, 1, _shapes[6]);
else
_screen->setMouseCursor(8, 15, _shapes[216+item]);
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 0bc5162e94..9c5548c1f7 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -177,6 +177,39 @@ KyraEngine_HoF::~KyraEngine_HoF() {
_timOpcodes.clear();
}
+void KyraEngine_HoF::pauseEngineIntern(bool pause) {
+ KyraEngine_v2::pauseEngineIntern(pause);
+
+ if (!pause) {
+ uint32 pausedTime = _system->getMillis() - _pauseStart;
+ _pauseStart = 0;
+
+ // sequence player
+ //
+ // Timers in KyraEngine_HoF::seq_cmpFadeFrame() and KyraEngine_HoF::seq_animatedSubFrame()
+ // have been left out for now. I think we don't need them here.
+
+ _seqStartTime += pausedTime;
+ _seqSubFrameStartTime += pausedTime;
+ _seqEndTime += pausedTime;
+ _seqSubFrameEndTimeInternal += pausedTime;
+ _seqWsaChatTimeout += pausedTime;
+ _seqWsaChatFrameTimeout += pausedTime;
+
+ for (int x = 0; x < 10; x++) {
+ if (_activeText[x].duration != -1)
+ _activeText[x].startTime += pausedTime;
+ }
+
+ for (int x = 0; x < 8; x++) {
+ if (_activeWSA[x].flags != -1)
+ _activeWSA[x].nextFrame += pausedTime;
+ }
+
+ // TODO: item animation, idle animation, tim player, etc
+ }
+}
+
int KyraEngine_HoF::init() {
_screen = new Screen_HoF(this, _system);
assert(_screen);
@@ -254,6 +287,8 @@ int KyraEngine_HoF::go() {
if (_menuChoice != 4) {
// load just the pak files needed for ingame
_res->loadPakFile(StaticResource::staticDataFilename());
+ if (_flags.useInstallerPackage)
+ _res->loadPakFile("WESTWOOD.001");
if (_flags.platform == Common::kPlatformPC && _flags.isTalkie)
_res->loadFileList("FILEDATA.FDT");
else
diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h
index fe4b6390b7..866dd55d16 100644
--- a/engines/kyra/kyra_hof.h
+++ b/engines/kyra/kyra_hof.h
@@ -182,6 +182,8 @@ public:
KyraEngine_HoF(OSystem *system, const GameFlags &flags);
~KyraEngine_HoF();
+ void pauseEngineIntern(bool pause);
+
Screen *screen() { return _screen; }
Screen_v2 *screen_v2() const { return _screen; }
GUI_v2 *gui_v2() const { return _gui; }
@@ -856,7 +858,12 @@ protected:
uint32 _seqFrameDelay;
uint32 _seqStartTime;
+ uint32 _seqSubFrameStartTime;
uint32 _seqEndTime;
+ uint32 _seqSubFrameEndTimeInternal;
+ uint32 _seqWsaChatTimeout;
+ uint32 _seqWsaChatFrameTimeout;
+
int _seqFrameCounter;
int _seqScrollTextCounter;
int _seqWsaCurrentFrame;
diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp
index 0668cc7202..c852f6e3ee 100644
--- a/engines/kyra/kyra_lok.cpp
+++ b/engines/kyra/kyra_lok.cpp
@@ -91,6 +91,7 @@ KyraEngine_LoK::KyraEngine_LoK(OSystem *system, const GameFlags &flags)
memset(_panPagesTable, 0, sizeof(_panPagesTable));
memset(_sceneAnimTable, 0, sizeof(_sceneAnimTable));
_currHeadShape = 0;
+ _speechPlayTime = 0;
memset(&_itemBkgBackUp, 0, sizeof(_itemBkgBackUp));
}
diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h
index 5e244e4925..cb3062847e 100644
--- a/engines/kyra/kyra_lok.h
+++ b/engines/kyra/kyra_lok.h
@@ -113,6 +113,10 @@ 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.
+
Screen *screen() { return _screen; }
Animator_LoK *animator() { return _animator; }
virtual Movie *createWSAMovie();
@@ -205,8 +209,11 @@ public:
void snd_playWanderScoreViaMap(int command, int restart);
virtual void snd_playVoiceFile(int id);
void snd_voiceWaitForFinish(bool ingame = true);
+ uint32 snd_getVoicePlayTime();
protected:
+ int32 _speechPlayTime;
+
void saveGame(const char *fileName, const char *saveName);
void loadGame(const char *fileName);
@@ -284,7 +291,7 @@ protected:
// -> mouse item
void setHandItem(uint16 item);
void removeHandItem();
- void setMouseItem(int item);
+ void setMouseItem(uint16 item);
// -> graphics effects
void wipeDownMouseItem(int xpos, int ypos);
@@ -628,9 +635,6 @@ protected:
int _cdaTrackTableSize;
const AudioDataStruct * _soundData;
- static const int8 _charXPosTable[];
- static const int8 _charYPosTable[];
-
// positions of the inventory
static const uint16 _itemPosX[];
static const uint8 _itemPosY[];
@@ -791,9 +795,9 @@ protected:
int o1_pauseMusicSeconds(EMCState *script);
int o1_resetMaskRegion(EMCState *script);
int o1_setPaletteChangeFlag(EMCState *script);
- int o1_dummy(EMCState *script);
int o1_vocUnload(EMCState *script);
int o1_vocLoad(EMCState *script);
+ int o1_dummy(EMCState *script);
};
} // end of namespace Kyra
diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp
index c0c04cb370..c842e318ec 100644
--- a/engines/kyra/kyra_mr.cpp
+++ b/engines/kyra/kyra_mr.cpp
@@ -370,7 +370,10 @@ void KyraEngine_MR::playVQA(const char *name) {
snprintf(filename, sizeof(filename), "%s%d.VQA", name, size);
if (vqa.open(filename)) {
- _soundDigital->stopAllSounds();
+ for (int i = 0; i < 4; ++i) {
+ if (i != _musicSoundChannel)
+ _soundDigital->stopSound(i);
+ }
_screen->hideMouse();
memcpy(_screen->getPalette(1), _screen->getPalette(0), 768);
@@ -402,14 +405,12 @@ void KyraEngine_MR::playMenuAudioFile() {
if (_soundDigital->isPlaying(_musicSoundChannel))
return;
- _musicSoundChannel = _soundDigital->playSound(_menuAudioFile, 0xFF, Audio::Mixer::kMusicSoundType);
+ _musicSoundChannel = _soundDigital->playSound(_menuAudioFile, 0xFF, Audio::Mixer::kMusicSoundType, 255, true);
}
void KyraEngine_MR::snd_playWanderScoreViaMap(int track, int force) {
debugC(9, kDebugLevelMain, "KyraEngine_MR::snd_playWanderScoreViaMap(%d, %d)", track, force);
- // XXX byte_3C87C compare
-
if (_musicSoundChannel != -1 && !_soundDigital->isPlaying(_musicSoundChannel))
force = 1;
else if (_musicSoundChannel == -1)
diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h
index 4ec02c7849..5af138373c 100644
--- a/engines/kyra/kyra_mr.h
+++ b/engines/kyra/kyra_mr.h
@@ -50,6 +50,11 @@ 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.
+
Screen *screen() { return _screen; }
Screen_v2 *screen_v2() const { return _screen; }
GUI_v2 *gui_v2() const { return _gui; }
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index a3d18f7713..1cc1d728bf 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -87,6 +87,11 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags)
return _debugger;
}
+void KyraEngine_v1::pauseEngineIntern(bool pause) {
+ Engine::pauseEngineIntern(pause);
+ _timer->pause(pause);
+}
+
int KyraEngine_v1::init() {
registerDefaultSettings();
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index 81a6254c7f..4f38ceca98 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -46,11 +46,12 @@ struct GameFlags {
Common::Language lang;
Common::Platform platform;
- bool isDemo : 1;
- bool useAltShapeHeader : 1; // alternative shape header (uses 2 bytes more, those are unused though)
- bool isTalkie : 1;
- bool useHiResOverlay : 1;
- bool useDigSound : 1;
+ bool isDemo : 1;
+ bool useAltShapeHeader : 1; // alternative shape header (uses 2 bytes more, those are unused though)
+ bool isTalkie : 1;
+ bool useHiResOverlay : 1;
+ bool useDigSound : 1;
+ bool useInstallerPackage : 1;
byte gameID;
};
@@ -109,6 +110,8 @@ public:
::GUI::Debugger *getDebugger();
+ virtual void pauseEngineIntern(bool pause);
+
bool quit() const { return _quitFlag; }
uint8 game() const { return _flags.gameID; }
@@ -263,6 +266,11 @@ protected:
static const int8 _addXPosTable[];
static const int8 _addYPosTable[];
+ // Character
+
+ static const int8 _charAddXPosTable[];
+ static const int8 _charAddYPosTable[];
+
// save/load
int _gameToLoad;
diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp
index 7b720259cc..12da338843 100644
--- a/engines/kyra/kyra_v2.cpp
+++ b/engines/kyra/kyra_v2.cpp
@@ -68,6 +68,8 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags, const Engi
memset(&_mainCharacter, 0, sizeof(_mainCharacter));
memset(&_mainCharacter.inventory, -1, sizeof(_mainCharacter.inventory));
+
+ _pauseStart = 0;
}
KyraEngine_v2::~KyraEngine_v2() {
@@ -93,6 +95,22 @@ KyraEngine_v2::~KyraEngine_v2() {
delete[] _screenBuffer;
}
+void KyraEngine_v2::pauseEngineIntern(bool pause) {
+ KyraEngine_v1::pauseEngineIntern(pause);
+
+ if (!pause) {
+ uint32 pausedTime = _system->getMillis() - _pauseStart;
+
+ for (int i = 0; i < ARRAYSIZE(_sceneSpecialScriptsTimer); ++i) {
+ if (_sceneSpecialScriptsTimer[i])
+ _sceneSpecialScriptsTimer[i] += pausedTime;
+ }
+
+ } else {
+ _pauseStart = _system->getMillis();
+ }
+}
+
void KyraEngine_v2::delay(uint32 amount, bool updateGame, bool isMainLoop) {
debugC(9, kDebugLevelMain, "KyraEngine_v2::delay(%u, %d, %d)", amount, updateGame, isMainLoop);
@@ -326,8 +344,8 @@ int KyraEngine_v2::updateCharPos(int *table, int force) {
debugC(9, kDebugLevelMain, "KyraEngine_v2::updateCharPos(%p, %d)", (const void*)table, force);
if (_updateCharPosNextUpdate > _system->getMillis() && !force)
return 0;
- _mainCharacter.x1 += _updateCharPosXTable[_mainCharacter.facing];
- _mainCharacter.y1 += _updateCharPosYTable[_mainCharacter.facing];
+ _mainCharacter.x1 += _charAddXPosTable[_mainCharacter.facing];
+ _mainCharacter.y1 += _charAddYPosTable[_mainCharacter.facing];
updateCharAnimFrame(0, table);
_updateCharPosNextUpdate = _system->getMillis() + getCharacterWalkspeed() * _tickLength;
return 1;
diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h
index 2f6d8a6185..24f7aad614 100644
--- a/engines/kyra/kyra_v2.h
+++ b/engines/kyra/kyra_v2.h
@@ -75,6 +75,8 @@ public:
KyraEngine_v2(OSystem *system, const GameFlags &flags, const EngineDesc &desc);
~KyraEngine_v2();
+ virtual void pauseEngineIntern(bool pause);
+
virtual Screen_v2 *screen_v2() const = 0;
virtual GUI *gui_v2() const = 0;
@@ -85,6 +87,7 @@ protected:
EngineDesc _desc;
// run
+ uint32 _pauseStart;
bool _runFlag;
bool _showOutro;
@@ -355,8 +358,6 @@ protected:
void updateCharPosWithUpdate();
uint32 _updateCharPosNextUpdate;
- static const int8 _updateCharPosXTable[];
- static const int8 _updateCharPosYTable[];
virtual int getCharacterWalkspeed() const = 0;
virtual void updateCharAnimFrame(int num, int *table) = 0;
diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp
index 9d34c669a1..6b38a0f907 100644
--- a/engines/kyra/resource.cpp
+++ b/engines/kyra/resource.cpp
@@ -30,10 +30,10 @@
#include "common/fs.h"
#include "common/func.h"
-#include "gui/message.h"
-
#include "kyra/resource.h"
+#define INS_CACHE_THRESHOLD 300000 // all files with file size greater than this will be cached
+
namespace Kyra {
Resource::Resource(KyraEngine_v1 *vm) : _loaders(), _map(), _vm(vm) {
@@ -55,8 +55,7 @@ bool Resource::reset() {
if (!loadPakFile(StaticResource::staticDataFilename()) || !StaticResource::checkKyraDat()) {
Common::String errorMessage = "You're missing the '" + StaticResource::staticDataFilename() + "' file or it got corrupted, (re)get it from the ScummVM website";
- ::GUI::MessageDialog errorMsg(errorMessage);
- errorMsg.runModal();
+ _vm->GUIErrorMessage(errorMessage);
error(errorMessage.c_str());
}
@@ -69,17 +68,31 @@ bool Resource::reset() {
if (_vm->gameFlags().isTalkie)
loadPakFile("CHAPTER1.VRM");
} else if (_vm->game() == GI_KYRA2) {
+ if (_vm->gameFlags().useInstallerPackage)
+ loadPakFile("WESTWOOD.001");
+
// mouse pointer, fonts, etc. required for initializing
if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
loadPakFile("GENERAL.PAK");
} else {
+ if (_vm->gameFlags().isTalkie) {
+ // Add default file directories
+ Common::File::addDefaultDirectory(ConfMan.get("path") + "hof_cd");
+ Common::File::addDefaultDirectory(ConfMan.get("path") + "HOF_CD");
+ }
+
loadPakFile("INTROGEN.PAK");
loadPakFile("OTHER.PAK");
}
return true;
} else if (_vm->game() == GI_KYRA3) {
- loadPakFile("WESTWOOD.001");
+ if (_vm->gameFlags().useInstallerPackage)
+ loadPakFile("WESTWOOD.001");
+ // Add default file directories
+ Common::File::addDefaultDirectory(ConfMan.get("path") + "malcolm");
+ Common::File::addDefaultDirectory(ConfMan.get("path") + "MALCOLM");
+
loadFileList("FILEDATA.FDT");
return true;
@@ -210,7 +223,7 @@ bool Resource::loadFileList(const Common::String &filedata) {
buffer[12] = 0;
f.seek(offset + 16, SEEK_SET);
- Common::String filename = (char*)buffer;
+ Common::String filename = Common::String((char*)buffer);
filename.toUppercase();
if (filename.hasSuffix(".PAK")) {
@@ -569,7 +582,7 @@ Common::SeekableReadStream *ResLoaderPak::loadFileFromArchive(const Common::Stri
return stream;
}
-class ResLoaderIns : public ResArchiveLoader {
+class ResLoaderInsKyra : public ResArchiveLoader {
public:
bool checkFilename(Common::String filename) const;
bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
@@ -577,16 +590,790 @@ public:
Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const;
ResFileEntry::kType getType() const {
- return ResFileEntry::kIns;
+ return ResFileEntry::kInsKyra;
+ }
+};
+
+bool ResLoaderInsKyra::checkFilename(Common::String filename) const {
+ return false;
+}
+
+bool ResLoaderInsKyra::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+ return true;
+}
+
+bool ResLoaderInsKyra::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const {
+ return true;
+}
+
+Common::SeekableReadStream *ResLoaderInsKyra::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const {
+ return 0;
+}
+
+class FileExpanderSource {
+public:
+ FileExpanderSource(const uint8 *data) : _dataPtr(data), _bitsLeft(8), _key(0), _index(0) {}
+ ~FileExpanderSource() {}
+
+ void advSrcRefresh();
+ void advSrcBitsBy1();
+ void advSrcBitsByIndex(uint8 newIndex);
+
+ uint8 getKeyLower() { return _key & 0xff; }
+ void setIndex(uint8 index) { _index = index; }
+ uint16 getKeyMasked(uint8 newIndex);
+ uint16 keyMaskedAlign(uint16 val);
+
+ void copyBytes(uint8 *& dst);
+
+private:
+ const uint8 *_dataPtr;
+ uint16 _key;
+ int8 _bitsLeft;
+ uint8 _index;
+};
+
+void FileExpanderSource::advSrcBitsBy1() {
+ _key >>= 1;
+ if (!--_bitsLeft) {
+ _key = ((*_dataPtr++) << 8 ) | (_key & 0xff);
+ _bitsLeft = 8;
+ }
+}
+
+void FileExpanderSource::advSrcBitsByIndex(uint8 newIndex) {
+ _index = newIndex;
+ _bitsLeft -= _index;
+ if (_bitsLeft <= 0) {
+ _key >>= (_index + _bitsLeft);
+ _index = -_bitsLeft;
+ _bitsLeft = 8 - _index;
+ _key = (*_dataPtr++ << 8) | (_key & 0xff);
+ }
+ _key >>= _index;
+}
+
+uint16 FileExpanderSource::getKeyMasked(uint8 newIndex) {
+ static const uint8 mskTable[] = { 0x0F, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
+ _index = newIndex;
+ uint16 res = 0;
+
+ if (_index > 8) {
+ newIndex = _index - 8;
+ res = (_key & 0xff) & mskTable[8];
+ advSrcBitsByIndex(8);
+ _index = newIndex;
+ res |= (((_key & 0xff) & mskTable[_index]) << 8);
+ advSrcBitsByIndex(_index);
+ } else {
+ res = (_key & 0xff) & mskTable[_index];
+ advSrcBitsByIndex(_index);
}
+
+ return res;
+}
+
+void FileExpanderSource::copyBytes(uint8 *& dst) {
+ advSrcBitsByIndex(_bitsLeft);
+ uint16 r = (READ_LE_UINT16(_dataPtr) ^ _key) + 1;
+ _dataPtr += 2;
+
+ if (r)
+ error("decompression failure");
+
+ memcpy(dst, _dataPtr, _key);
+ _dataPtr += _key;
+ dst += _key;
+}
+
+uint16 FileExpanderSource::keyMaskedAlign(uint16 val) {
+ val -= 0x101;
+ _index = (val & 0xff) >> 2;
+ int16 b = ((_bitsLeft << 8) | _index) - 1;
+ _bitsLeft = b >> 8;
+ _index = b & 0xff;
+ return (((val & 3) + 4) << _index) + 0x101 + getKeyMasked(_index);
+}
+
+void FileExpanderSource::advSrcRefresh() {
+ _key = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+ _bitsLeft = 8;
+}
+
+class FileExpander {
+public:
+ FileExpander();
+ ~FileExpander();
+
+ bool process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 insize);
+
+private:
+ void generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt);
+ uint8 calcCmdAndIndex(const uint8 *tbl, int16 &para);
+
+ FileExpanderSource *_src;
+ uint8 *_tables[9];
+ uint16 *_tables16[3];
};
-bool ResLoaderIns::checkFilename(Common::String filename) const {
+FileExpander::FileExpander() : _src(0) {
+ _tables[0] = new uint8[3914];
+ assert(_tables[0]);
+
+ _tables[1] = _tables[0] + 320;
+ _tables[2] = _tables[0] + 352;
+ _tables[3] = _tables[0] + 864;
+ _tables[4] = _tables[0] + 2016;
+ _tables[5] = _tables[0] + 2528;
+ _tables[6] = _tables[0] + 2656;
+ _tables[7] = _tables[0] + 2736;
+ _tables[8] = _tables[0] + 2756;
+
+ _tables16[0] = (uint16 *)(_tables[0] + 3268);
+ _tables16[1] = (uint16 *)(_tables[0] + 3302);
+ _tables16[2] = (uint16 *)(_tables[0] + 3338);
+}
+
+FileExpander::~FileExpander() {
+ delete _src;
+ delete[] _tables[0];
+}
+
+bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32 compressedSize) {
+ static const uint8 indexTable[] = {
+ 0x10, 0x11, 0x12, 0x00, 0x08, 0x07, 0x09, 0x06, 0x0A,
+ 0x05, 0x0B, 0x04, 0x0C, 0x03, 0x0D, 0x02, 0x0E, 0x01, 0x0F
+ };
+
+ memset(_tables[0], 0, 3914);
+
+ uint8 *d = dst;
+ uint16 tableSize0 = 0;
+ uint16 tableSize1 = 0;
+ bool needrefresh = true;
+ bool postprocess = false;
+
+ _src = new FileExpanderSource(src);
+
+ while (d < dst + outsize) {
+
+ if (needrefresh) {
+ needrefresh = false;
+ _src->advSrcRefresh();
+ }
+
+ _src->advSrcBitsBy1();
+
+ int mode = _src->getKeyMasked(2) - 1;
+ if (mode == 1) {
+ tableSize0 = _src->getKeyMasked(5) + 257;
+ tableSize1 = _src->getKeyMasked(5) + 1;
+ memset(_tables[7], 0, 19);
+
+ const uint8 *itbl = indexTable;
+ int numbytes = _src->getKeyMasked(4) + 4;
+
+ while (numbytes--)
+ _tables[7][*itbl++] = _src->getKeyMasked(3);
+
+ generateTables(7, 8, 255, 19);
+
+ int cnt = tableSize0 + tableSize1;
+ uint8 *tmp = _tables[0];
+
+ while (cnt) {
+ uint16 cmd = _src->getKeyLower();
+ cmd = READ_LE_UINT16(&_tables[8][cmd << 1]);
+ _src->advSrcBitsByIndex(_tables[7][cmd]);
+
+ if (cmd < 16) {
+ *tmp++ = cmd;
+ cnt--;
+ } else {
+ uint8 tmpI = 0;
+ if (cmd == 16) {
+ cmd = _src->getKeyMasked(2) + 3;
+ tmpI = *(tmp - 1);
+ } else if (cmd == 17) {
+ cmd = _src->getKeyMasked(3) + 3;
+ } else {
+ cmd = _src->getKeyMasked(7) + 11;
+ }
+ _src->setIndex(tmpI);
+ memset(tmp, tmpI, cmd);
+ tmp += cmd;
+
+ cnt -= cmd;
+ if (cnt < 0)
+ error("decompression failure");
+ }
+ }
+
+ memcpy(_tables[1], _tables[0] + tableSize0, tableSize1);
+ generateTables(0, 2, 3, tableSize0);
+ generateTables(1, 4, 5, tableSize1);
+ postprocess = true;
+ } else if (mode < 0) {
+ _src->copyBytes(d);
+ postprocess = false;
+ needrefresh = true;
+ } else if (mode == 0){
+ uint8 *d2 = _tables[0];
+ memset(d2, 8, 144);
+ memset(d2 + 144, 9, 112);
+ memset(d2 + 256, 7, 24);
+ memset(d2 + 280, 8, 8);
+ d2 = _tables[1];
+ memset(d2, 5, 32);
+ tableSize0 = 288;
+ tableSize1 = 32;
+
+ generateTables(0, 2, 3, tableSize0);
+ generateTables(1, 4, 5, tableSize1);
+ postprocess = true;
+ } else {
+ error("decompression failure");
+ }
+
+ if (!postprocess)
+ continue;
+
+ int16 cmd = 0;
+
+ do {
+ cmd = ((int16*) _tables[2])[_src->getKeyLower()];
+ _src->advSrcBitsByIndex(cmd < 0 ? calcCmdAndIndex(_tables[3], cmd) : _tables[0][cmd]);
+
+ if (cmd == 0x11d) {
+ cmd = 0x200;
+ } else if (cmd > 0x108) {
+ cmd = _src->keyMaskedAlign(cmd);
+ }
+
+ if (!(cmd >> 8)) {
+ *d++ = cmd & 0xff;
+ } else if (cmd != 0x100) {
+ cmd -= 0xfe;
+ int16 offset = ((int16*) _tables[4])[_src->getKeyLower()];
+ _src->advSrcBitsByIndex(offset < 0 ? calcCmdAndIndex(_tables[5], offset) : _tables[1][offset]);
+ if ((offset & 0xff) >= 4) {
+ uint8 newIndex = ((offset & 0xff) >> 1) - 1;
+ offset = (((offset & 1) + 2) << newIndex) + _src->getKeyMasked(newIndex);
+ }
+
+ uint8 *s2 = d - 1 - offset;
+ if (s2 >= dst) {
+ while (cmd--)
+ *d++ = *s2++;
+ } else {
+ uint32 pos = dst - s2;
+ s2 += (d - dst);
+
+ if (pos < (uint32) cmd) {
+ cmd -= pos;
+ while (pos--)
+ *d++ = *s2++;
+ s2 = dst;
+ }
+ while (cmd--)
+ *d++ = *s2++;
+ }
+ }
+ } while (cmd != 0x100);
+ }
+
+ delete _src;
+ _src = 0;
+
+ return true;
+}
+
+void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex2, int cnt) {
+ const uint8 *tbl1 = _tables[srcIndex];
+ const uint8 *tbl2 = _tables[dstIndex];
+ const uint8 *tbl3 = dstIndex2 == 0xff ? 0 : _tables[dstIndex2];
+
+ if (!cnt)
+ return;
+
+ const uint8 *s = tbl1;
+ memset(_tables16[0], 0, 32);
+
+ for (int i = 0; i < cnt; i++)
+ _tables16[0][(*s++)]++;
+
+ _tables16[1][1] = 0;
+
+ for (uint16 i = 1, r = 0; i < 16; i++) {
+ r = (r + _tables16[0][i]) << 1;
+ _tables16[1][i + 1] = r;
+ }
+
+ if (_tables16[1][16]) {
+ uint16 r = 0;
+ for (uint16 i = 1; i < 16; i++)
+ r += _tables16[0][i];
+ if (r > 1)
+ error("decompression failure");
+ }
+
+ s = tbl1;
+ uint16 *d = _tables16[2];
+ for (int i = 0; i < cnt; i++) {
+ uint16 t = *s++;
+ if (t) {
+ _tables16[1][t]++;
+ t = _tables16[1][t] - 1;
+ }
+ *d++ = t;
+ }
+
+ s = tbl1;
+ d = _tables16[2];
+ for (int i = 0; i < cnt; i++) {
+ int8 t = ((int8)(*s++)) - 1;
+ if (t > 0) {
+ uint16 v1 = *d;
+ uint16 v2 = 0;
+
+ do {
+ v2 = (v2 << 1) | (v1 & 1);
+ v1 >>= 1;
+ } while (--t && v1);
+
+ t++;
+ uint8 c1 = (v1 & 1);
+ while (t--) {
+ uint8 c2 = v2 >> 15;
+ v2 = (v2 << 1) | c1;
+ c1 = c2;
+ };
+
+ *d++ = v2;
+ } else {
+ d++;
+ }
+ }
+
+ memset((void*) tbl2, 0, 512);
+
+ cnt--;
+ s = tbl1 + cnt;
+ d = &_tables16[2][cnt];
+ uint16 * bt = (uint16*) tbl3;
+ uint16 inc = 0;
+ uint16 cnt2 = 0;
+
+ do {
+ uint8 t = *s--;
+ uint16 *s2 = (uint16*) tbl2;
+
+ if (t && t < 9) {
+ inc = 1 << t;
+ uint16 o = *d;
+
+ do {
+ s2[o] = cnt;
+ o += inc;
+ } while (!(o & 0xf00));
+
+ } else if (t > 8) {
+ if (!bt)
+ error("decompression failure");
+
+ t -= 8;
+ uint8 shiftCnt = 1;
+ uint8 v = (*d) >> 8;
+ s2 = &((uint16*) tbl2)[*d & 0xff];
+
+ do {
+ if (!*s2) {
+ *s2 = (uint16)(~cnt2);
+ *(uint32*)&bt[cnt2] = 0;
+ cnt2 += 2;
+ }
+
+ s2 = &bt[(uint16)(~*s2)];
+ if (v & shiftCnt)
+ s2++;
+
+ shiftCnt <<= 1;
+ } while (--t);
+ *s2 = cnt;
+ }
+ d--;
+ } while (--cnt >= 0);
+}
+
+uint8 FileExpander::calcCmdAndIndex(const uint8 *tbl, int16 &para) {
+ const uint16 *t = (const uint16*)tbl;
+ _src->advSrcBitsByIndex(8);
+ uint8 newIndex = 0;
+ uint16 v = _src->getKeyLower();
+
+ do {
+ newIndex++;
+ para = t[((~para) & 0xfffe) | (v & 1)];
+ v >>= 1;
+ } while (para < 0);
+
+ return newIndex;
+}
+
+class FileCache {
+public:
+ FileCache() : _size(0) {}
+ ~FileCache() {}
+
+ void add(ResFileEntry entry, const uint8 *data);
+ bool getData(ResFileEntry entry, uint8 *dst);
+ void flush();
+
+private:
+ struct FileCacheEntry {
+ ResFileEntry entry;
+ const uint8 *data;
+ };
+
+ Common::List<FileCacheEntry> _cachedFileList;
+ uint32 _size;
+};
+
+void FileCache::add(ResFileEntry entry, const uint8 *data) {
+ FileCacheEntry fileCacheEntry;
+ fileCacheEntry.entry.compressedSize = entry.compressedSize;
+ fileCacheEntry.entry.mounted = entry.mounted;
+ fileCacheEntry.entry.offset = entry.offset;
+ fileCacheEntry.entry.parent = entry.parent;
+ fileCacheEntry.entry.preload = entry.preload;
+ fileCacheEntry.entry.prot = entry.prot;
+ fileCacheEntry.entry.size = entry.size;
+ fileCacheEntry.entry.type = entry.type;
+ fileCacheEntry.entry.fileIndex = entry.fileIndex;
+ uint8 *dst = new uint8[entry.size];
+ assert(dst);
+ memcpy(dst, data, entry.size);
+ fileCacheEntry.data = dst;
+ _cachedFileList.push_back(fileCacheEntry);
+ _size += entry.size;
+}
+
+bool FileCache::getData(ResFileEntry entry, uint8 *dst) {
+ for (Common::List<FileCacheEntry>::const_iterator c = _cachedFileList.begin(); c != _cachedFileList.end(); ++c) {
+ if (c->entry.offset == entry.offset && c->entry.compressedSize == entry.compressedSize &&
+ c->entry.fileIndex == entry.fileIndex && c->entry.size == entry.size) {
+ memcpy(dst, c->data, c->entry.size);
+ return true;
+ }
+ }
+ return false;
+}
+
+void FileCache::flush() {
+ debug(1, "total amount of cache memory used: %d", _size);
+ for (Common::List<FileCacheEntry>::const_iterator c = _cachedFileList.begin(); c != _cachedFileList.end(); ++c)
+ delete[] c->data;
+ _cachedFileList.clear();
+ _size = 0;
+}
+
+class ResLoaderInsHof : public ResArchiveLoader {
+public:
+ ResLoaderInsHof() {}
+ ~ResLoaderInsHof() { _fileCache.flush(); }
+
+ bool checkFilename(Common::String filename) const;
+ bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+ bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const;
+ Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const;
+
+ ResFileEntry::kType getType() const {
+ return ResFileEntry::kInsHof;
+ }
+private:
+ mutable FileCache _fileCache;
+};
+
+bool ResLoaderInsHof::checkFilename(Common::String filename) const {
+ filename.toUppercase();
+ if (!filename.hasSuffix(".001"))
+ return false;
+ filename.insertChar('2', filename.size() - 1);
+ filename.deleteLastChar();
+ if (!Common::File::exists(filename))
+ return false;
+ return true;
+}
+
+bool ResLoaderInsHof::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+ uint8 fileId = stream.readByte();
+ uint32 size = stream.readUint32LE();
+
+ if (size < stream.size() + 1)
+ return false;
+
+ return (fileId == 1);
+}
+
+bool ResLoaderInsHof::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const {
+ Common::File tmpFile;
+
+ uint32 pos = 0;
+ uint32 bytesleft = 0;
+ bool startFile = true;
+
+ Common::String filenameBase(filename.c_str(), 10);
+ Common::String filenameTemp;
+ char filenameExt[4];
+
+ while (filenameBase.lastChar() != '.')
+ filenameBase.deleteLastChar();
+
+ InsHofArchive newArchive;
+
+ Common::List<InsHofArchive> archives;
+
+ for (int8 currentFile = 1; currentFile; currentFile++) {
+ sprintf(filenameExt, "%03d", currentFile);
+ filenameTemp = filenameBase + Common::String(filenameExt);
+
+ if (!tmpFile.open(filenameTemp)) {
+ debug(3, "couldn't open file '%s'\n", filenameTemp.c_str());
+ break;
+ }
+
+ tmpFile.seek(pos);
+ uint8 fileId = tmpFile.readByte();
+ pos++;
+
+ uint32 size = tmpFile.size() - 1;
+ if (startFile) {
+ size -= 4;
+ if (fileId == currentFile) {
+ size -= 6;
+ pos += 6;
+ tmpFile.seek(6, SEEK_CUR);
+ } else {
+ size = size + 1 - pos;
+ }
+ newArchive.filename = filenameBase;
+ bytesleft = newArchive.totalSize = tmpFile.readUint32LE();
+ pos += 4;
+ newArchive.firstFile = currentFile;
+ newArchive.startOffset = pos;
+ startFile = false;
+ }
+
+ uint32 cs = MIN(size, bytesleft);
+ bytesleft -= cs;
+
+ tmpFile.close();
+
+ pos += cs;
+ if (cs == size) {
+ if (!bytesleft) {
+ newArchive.lastFile = currentFile;
+ newArchive.endOffset = --pos;
+ archives.push_back(newArchive);
+ currentFile = -1;
+ } else {
+ pos = 0;
+ }
+ } else {
+ startFile = true;
+ bytesleft = size - cs;
+ newArchive.lastFile = currentFile--;
+ newArchive.endOffset = --pos;
+ archives.push_back(newArchive);
+ }
+ }
+
+ ResFileEntry newEntry;
+ pos = 0;
+
+ const uint32 kExecSize = 0x0bba;
+ const uint32 kHeaderSize = 30;
+ const uint32 kHeaderSize2 = 46;
+
+ for (Common::List<InsHofArchive>::iterator a = archives.begin(); a != archives.end(); ++a) {
+ startFile = true;
+ for (uint32 i = a->firstFile; i != (a->lastFile + 1); i++) {
+ sprintf(filenameExt, "%03d", i);
+ filenameTemp = a->filename + Common::String(filenameExt);
+
+ if (!tmpFile.open(filenameTemp)) {
+ debug(3, "couldn't open file '%s'\n", filenameTemp.c_str());
+ break;
+ }
+
+ uint32 size = (i == a->lastFile) ? a->endOffset : tmpFile.size();
+
+ if (startFile) {
+ startFile = false;
+ pos = a->startOffset + kExecSize;
+ if (pos > size) {
+ pos -= size;
+ tmpFile.close();
+ continue;
+ }
+ } else {
+ pos ++;
+ }
+
+ while (pos < size) {
+ uint8 hdr[43];
+ uint32 m = 0;
+ tmpFile.seek(pos);
+
+ if (pos + 42 > size) {
+ m = size - pos;
+ uint32 b = 42 - m;
+
+ if (m >= 4) {
+ uint32 id = tmpFile.readUint32LE();
+ if (id == 0x06054B50) {
+ startFile = true;
+ break;
+ } else {
+ tmpFile.seek(pos);
+ }
+ }
+
+ sprintf(filenameExt, "%03d", i + 1);
+ filenameTemp = a->filename + Common::String(filenameExt);
+
+ Common::File tmpFile2;
+ tmpFile2.open(filenameTemp);
+ tmpFile.read(hdr, m);
+ tmpFile2.read(hdr + m, b);
+ tmpFile2.close();
+
+ } else {
+ tmpFile.read(hdr, 42);
+ }
+
+ uint32 id = READ_LE_UINT32(hdr);
+
+ if (id == 0x04034B50) {
+ if (hdr[8] != 8)
+ error("compression type not implemented");
+ newEntry.compressedSize = READ_LE_UINT32(hdr + 18);
+ newEntry.size = READ_LE_UINT32(hdr + 22);
+
+ uint16 filestrlen = READ_LE_UINT16(hdr + 26);
+ *(hdr + 30 + filestrlen) = 0;
+ pos += (kHeaderSize + filestrlen - m);
+
+ newEntry.parent = filename;
+ newEntry.offset = pos;
+ newEntry.type = ResFileEntry::kAutoDetect;
+ newEntry.mounted = false;
+ newEntry.preload = false;
+ newEntry.prot = false;
+ newEntry.fileIndex = i;
+ files.push_back(File(Common::String((const char *)(hdr + 30)), newEntry));
+
+ pos += newEntry.compressedSize;
+ if (pos > size) {
+ pos -= size;
+ break;
+ }
+ } else {
+ uint32 filestrlen = READ_LE_UINT32(hdr + 28);
+ pos += (kHeaderSize2 + filestrlen - m);
+ }
+ }
+ tmpFile.close();
+ }
+ }
+
+ archives.clear();
+
+ return true;
+}
+
+Common::SeekableReadStream *ResLoaderInsHof::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const {
+ if (archive) {
+ delete archive;
+ archive = 0;
+ }
+
+ uint8 *outbuffer = (uint8 *)malloc(entry.size);
+ assert(outbuffer);
+
+ if (!_fileCache.getData(entry, outbuffer)) {
+ Common::File tmpFile;
+ char filename[13];
+ sprintf(filename, "WESTWOOD.%03d", entry.fileIndex);
+
+ if (!tmpFile.open(filename)) {
+ free(outbuffer);
+ return 0;
+ }
+
+ tmpFile.seek(entry.offset);
+
+ uint8 *inbuffer = new uint8[entry.compressedSize];
+ assert(inbuffer);
+
+ if ((entry.offset + entry.compressedSize) > tmpFile.size()) {
+ // this is for files that are split between two archive files
+ uint32 a = tmpFile.size() - entry.offset;
+ uint32 b = entry.compressedSize - a;
+
+ tmpFile.read(inbuffer, a);
+ tmpFile.close();
+
+ filename[strlen(filename) - 1]++;
+
+ if (!tmpFile.open(filename))
+ return 0;
+ tmpFile.seek(1);
+ tmpFile.read(inbuffer + a, b);
+ } else {
+ tmpFile.read(inbuffer, entry.compressedSize);
+ }
+
+ tmpFile.close();
+
+ FileExpander().process(outbuffer, inbuffer, entry.size, entry.compressedSize);
+ delete[] inbuffer;
+
+ if (entry.size > INS_CACHE_THRESHOLD)
+ _fileCache.add(entry, outbuffer);
+ }
+
+ Common::MemoryReadStream *stream = new Common::MemoryReadStream(outbuffer, entry.size, true);
+ assert(stream);
+
+ return stream;
+}
+
+class ResLoaderInsMalcolm : public ResArchiveLoader {
+public:
+ bool checkFilename(Common::String filename) const;
+ bool isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const;
+ bool loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const;
+ Common::SeekableReadStream *loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const;
+
+ ResFileEntry::kType getType() const {
+ return ResFileEntry::kInsMal;
+ }
+};
+
+bool ResLoaderInsMalcolm::checkFilename(Common::String filename) const {
filename.toUppercase();
- return (filename.hasSuffix(".001"));
+ if (!filename.hasSuffix(".001"))
+ return false;
+ filename.insertChar('2', filename.size() - 1);
+ filename.deleteLastChar();
+ if (Common::File::exists(filename))
+ return false;
+ return true;
}
-bool ResLoaderIns::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
+bool ResLoaderInsMalcolm::isLoadable(const Common::String &filename, Common::SeekableReadStream &stream) const {
stream.seek(3);
uint32 size = stream.readUint32LE();
@@ -600,7 +1387,7 @@ bool ResLoaderIns::isLoadable(const Common::String &filename, Common::SeekableRe
return (buffer[0] == 0x0D && buffer[1] == 0x0A);
}
-bool ResLoaderIns::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const {
+bool ResLoaderInsMalcolm::loadFile(const Common::String &filename, Common::SeekableReadStream &stream, FileList &files) const {
Common::List<Common::String> filenames;
// thanks to eriktorbjorn for this code (a bit modified though)
@@ -645,7 +1432,7 @@ bool ResLoaderIns::loadFile(const Common::String &filename, Common::SeekableRead
return true;
}
-Common::SeekableReadStream *ResLoaderIns::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const {
+Common::SeekableReadStream *ResLoaderInsMalcolm::loadFileFromArchive(const Common::String &file, Common::SeekableReadStream *archive, const ResFileEntry entry) const {
assert(archive);
archive->seek(entry.offset, SEEK_SET);
@@ -738,7 +1525,9 @@ Common::SeekableReadStream *ResLoaderTlk::loadFileFromArchive(const Common::Stri
void Resource::initializeLoaders() {
_loaders.push_back(LoaderList::value_type(new ResLoaderPak()));
- _loaders.push_back(LoaderList::value_type(new ResLoaderIns()));
+ _loaders.push_back(LoaderList::value_type(new ResLoaderInsKyra()));
+ _loaders.push_back(LoaderList::value_type(new ResLoaderInsHof()));
+ _loaders.push_back(LoaderList::value_type(new ResLoaderInsMalcolm()));
_loaders.push_back(LoaderList::value_type(new ResLoaderTlk()));
}
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h
index a8de21b5ca..90405690a4 100644
--- a/engines/kyra/resource.h
+++ b/engines/kyra/resource.h
@@ -41,6 +41,15 @@
namespace Kyra {
+struct InsHofArchive {
+ Common::String filename;
+ uint32 firstFile;
+ uint32 startOffset;
+ uint32 lastFile;
+ uint32 endOffset;
+ uint32 totalSize;
+};
+
struct ResFileEntry {
Common::String parent;
uint32 size;
@@ -52,12 +61,17 @@ struct ResFileEntry {
enum kType {
kRaw = 0,
kPak = 1,
- kIns = 2,
- kTlk = 3,
+ kInsKyra = 2,
+ kInsHof = 3,
+ kInsMal = 4,
+ kTlk = 5,
kAutoDetect
};
kType type;
uint32 offset;
+
+ int fileIndex;
+ uint32 compressedSize;
};
typedef Common::HashMap<Common::String, ResFileEntry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ResFileMap;
@@ -271,7 +285,7 @@ public:
bool prefetchId(int id);
void unloadId(int id);
private:
- void outputError();
+ void outputError(const Common::String &error);
KyraEngine_v1 *_vm;
diff --git a/engines/kyra/scene_lok.cpp b/engines/kyra/scene_lok.cpp
index 085332b525..e4ae67f751 100644
--- a/engines/kyra/scene_lok.cpp
+++ b/engines/kyra/scene_lok.cpp
@@ -295,13 +295,13 @@ int KyraEngine_LoK::setCharacterPosition(int character, int *facingTable) {
debugC(9, kDebugLevelMain, "KyraEngine_LoK::setCharacterPosition(%d, %p)", character, (const void *)facingTable);
if (character == 0) {
- _currentCharacter->x1 += _charXPosTable[_currentCharacter->facing];
- _currentCharacter->y1 += _charYPosTable[_currentCharacter->facing];
+ _currentCharacter->x1 += _charAddXPosTable[_currentCharacter->facing];
+ _currentCharacter->y1 += _charAddYPosTable[_currentCharacter->facing];
setCharacterPositionHelper(0, facingTable);
return 1;
} else {
- _characterList[character].x1 += _charXPosTable[_characterList[character].facing];
- _characterList[character].y1 += _charYPosTable[_characterList[character].facing];
+ _characterList[character].x1 += _charAddXPosTable[_characterList[character].facing];
+ _characterList[character].y1 += _charAddYPosTable[_characterList[character].facing];
if (_characterList[character].sceneId == _currentCharacter->sceneId)
setCharacterPositionHelper(character, 0);
}
@@ -1009,8 +1009,8 @@ int KyraEngine_LoK::changeScene(int facing) {
return 0;
}
- int xpos = _charXPosTable[facing] + _currentCharacter->x1;
- int ypos = _charYPosTable[facing] + _currentCharacter->y1;
+ int xpos = _charAddXPosTable[facing] + _currentCharacter->x1;
+ int ypos = _charAddYPosTable[facing] + _currentCharacter->y1;
if (xpos >= 12 && xpos <= 308) {
if (!lineIsPassable(xpos, ypos))
diff --git a/engines/kyra/scene_v2.cpp b/engines/kyra/scene_v2.cpp
index 7072cfc9a5..3bf81bfb39 100644
--- a/engines/kyra/scene_v2.cpp
+++ b/engines/kyra/scene_v2.cpp
@@ -98,7 +98,7 @@ int KyraEngine_v2::findWay(int x, int y, int toX, int toY, int *moveTable, int m
temp = pathfinderInitPositionIndexTable(temp, x, y);
pathfinderFinializePath(moveTable, temp, x, y, moveTableSize);
usePostProcess = false;
- }
+ }
return usePostProcess ? size : getMoveTableSize(moveTable);
}
@@ -106,13 +106,14 @@ bool KyraEngine_v2::directLinePassable(int x, int y, int toX, int toY) {
debugC(9, kDebugLevelMain, "KyraEngine_v2::directLinePassable(%d, %d, %d, %d)", x, y, toX, toY);
Screen *scr = screen();
- while (x != toX && y != toY) {
+ while (x != toX || y != toY) {
int facing = getFacingFromPointToPoint(x, y, toX, toY);
x += _addXPosTable[facing];
y += _addYPosTable[facing];
if (!scr->getShapeFlag1(x, y))
return false;
}
+
return true;
}
diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp
index d2b6b08183..91fbfb3e49 100644
--- a/engines/kyra/script_hof.cpp
+++ b/engines/kyra/script_hof.cpp
@@ -760,7 +760,7 @@ int KyraEngine_HoF::o2_showItemString(EMCState *script) {
int KyraEngine_HoF::o2_isAnySoundPlaying(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_isAnySoundPlaying(%p) ()", (const void *)script);
- return _sound->voiceIsPlaying();
+ return _sound->voiceIsPlaying() ? 1 : 0;
}
int KyraEngine_HoF::o2_setDrawNoShapeFlag(EMCState *script) {
@@ -800,7 +800,7 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) {
_screen->fadeToBlack(0x14);
sprintf(filename, "LETTER%.1d.", letter);
- strcat(filename, _languageExtension[_lang]);
+ strcat(filename, (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _lang) ? _languageExtension[_lang] : "TXT");
uint8 *letterBuffer = _res->fileData(filename, 0);
if (letterBuffer) {
diff --git a/engines/kyra/script_lok.cpp b/engines/kyra/script_lok.cpp
index 670c7282e3..efa0f8e48f 100644
--- a/engines/kyra/script_lok.cpp
+++ b/engines/kyra/script_lok.cpp
@@ -35,6 +35,7 @@
#include "kyra/animator_lok.h"
#include "kyra/text.h"
#include "kyra/timer.h"
+#include "kyra/sound.h"
namespace Kyra {
int KyraEngine_LoK::o1_magicInMouseItem(EMCState *script) {
@@ -320,9 +321,20 @@ int KyraEngine_LoK::o1_setBrandonStatusBit(EMCState *script) {
}
int KyraEngine_LoK::o1_delaySecs(EMCState *script) {
- debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_delaySecs(%p) (%d)", (const void *)script, stackPos(0));
- if (stackPos(0) > 0 && !_skipFlag)
- delay(stackPos(0)*1000, true);
+ if (_flags.isTalkie && speechEnabled()) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_voiceDelay(%p) (%d)", (const void *)script, stackPos(0));
+ if (stackPos(0) == 0) {
+ snd_voiceWaitForFinish(true);
+ } else if (stackPos(0) < 0) {
+ uint32 time = ABS(stackPos(0)) * _tickLength;
+ delay(time, true);
+ }
+ } else {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_delaySecs(%p) (%d)", (const void *)script, stackPos(0));
+ if (stackPos(0) >= 0 && !_skipFlag)
+ delay(stackPos(0)*1000, true);
+ }
+
_skipFlag = false;
return 0;
}
@@ -700,7 +712,10 @@ int KyraEngine_LoK::o1_displayWSAFrameOnHidPage(EMCState *script) {
}
int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) {
- debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSASequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6));
+ if (_flags.isTalkie)
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSASequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ else
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_displayWSASequentialFrames(%p) (%d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6));
int startFrame = stackPos(0);
int endFrame = stackPos(1);
int xpos = stackPos(2);
@@ -708,6 +723,40 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) {
int waitTime = stackPos(4);
int wsaIndex = stackPos(5);
int maxTime = stackPos(6);
+
+ if (_flags.isTalkie) {
+ int specialTime = stackPos(7);
+ if (specialTime) {
+ uint32 voiceTime = snd_getVoicePlayTime();
+ if (voiceTime) {
+ int displayFrames = ABS(endFrame-startFrame)+1;
+ displayFrames *= maxTime;
+ assert(displayFrames != 0);
+
+ bool voiceSync = false;
+
+ if (specialTime < 0) {
+ voiceSync = true;
+ specialTime = ABS(specialTime);
+ }
+
+ voiceTime *= specialTime;
+ voiceTime /= 100;
+
+ if (voiceSync) {
+ uint32 voicePlayedTime = _sound->voicePlayedTime(_speechFile.c_str());
+ if (voicePlayedTime >= voiceTime)
+ voiceTime = 0;
+ else
+ voiceTime -= voicePlayedTime;
+ }
+
+ waitTime = voiceTime / displayFrames;
+ waitTime /= _tickLength;
+ }
+ }
+ }
+
if (maxTime - 1 <= 0)
maxTime = 1;
@@ -734,7 +783,8 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) {
while (endFrame >= frame) {
uint32 continueTime = waitTime * _tickLength + _system->getMillis();
_movieObjects[wsaIndex]->displayFrame(frame);
- _animator->_updateScreen = true;
+ if (waitTime)
+ _animator->_updateScreen = true;
while (_system->getMillis() < continueTime) {
_sprites->updateSceneAnims();
_animator->updateAllObjectShapes();
@@ -751,7 +801,8 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) {
while (endFrame <= frame) {
uint32 continueTime = waitTime * _tickLength + _system->getMillis();
_movieObjects[wsaIndex]->displayFrame(frame);
- _animator->_updateScreen = true;
+ if (waitTime)
+ _animator->_updateScreen = true;
while (_system->getMillis() < continueTime) {
_sprites->updateSceneAnims();
_animator->updateAllObjectShapes();
@@ -1691,7 +1742,7 @@ int KyraEngine_LoK::o1_pauseMusicSeconds(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_pauseMusicSeconds(%p) ()", (const void *)script);
// if music disabled
// return
- o1_delaySecs(script);
+ delay(stackPos(0)*1000, true);
return 0;
}
diff --git a/engines/kyra/script_v1.cpp b/engines/kyra/script_v1.cpp
index 7881605b9e..f74c7e3560 100644
--- a/engines/kyra/script_v1.cpp
+++ b/engines/kyra/script_v1.cpp
@@ -96,9 +96,9 @@ int KyraEngine_v1::o1_playWanderScoreViaMap(EMCState *script) {
return 0;
}
-int KyraEngine_v1::o1_fillRect(EMCState *script) {
+int KyraEngine_v1::o1_fillRect(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_fillRect(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
- screen()->fillRect(stackPos(1), stackPos(2), stackPos(1)+stackPos(3), stackPos(2)+stackPos(4), stackPos(5), stackPos(0));
+ screen()->fillRect(stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(0));
return 0;
}
diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index 3e9f6030ac..0751fc15db 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -231,7 +231,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
_seqFrameDelay = cseq.frameDelay;
_seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength;
while (!((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) {
- uint32 starttime = _system->getMillis();
+ _seqSubFrameStartTime = _system->getMillis();
seq_processWSAs();
if (cb)
(this->*cb)(0, 0, 0, 0);
@@ -246,8 +246,8 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
if (now >= _seqEndTime && !_seqSubframePlaying)
break;
- uint32 tdiff = _seqEndTime - starttime;
- int32 dly = _tickLength - (now - starttime);
+ uint32 tdiff = _seqEndTime - _seqSubFrameStartTime;
+ int32 dly = _tickLength - (now - _seqSubFrameStartTime);
if (dly > 0)
delay(MIN<uint32>(dly, tdiff));
}
@@ -263,7 +263,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
_seqEndTime = _system->getMillis() + dl;
while (!((skipFlag() && allowSkip) || _quitFlag || (_abortIntroFlag && allowSkip) || _menuChoice)) {
- uint32 starttime = _system->getMillis();
+ _seqSubFrameStartTime = _system->getMillis();
seq_processWSAs();
_screen->copyPage(2, 0);
@@ -275,8 +275,8 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
break;
}
- uint32 tdiff = _seqEndTime - starttime;
- int32 dly = _tickLength - (now - starttime);
+ uint32 tdiff = _seqEndTime - _seqSubFrameStartTime;
+ int32 dly = _tickLength - (now - _seqSubFrameStartTime);
if (dly > 0)
delay(MIN<uint32>(dly, tdiff));
}
@@ -289,13 +289,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
_sound->voiceStop();
}
- if (_flags.isDemo && !_flags.isTalkie) {
- if (seqNum == kSequenceDemoFisher) {
- _abortIntroFlag = false;
- resetSkipFlag();
- seqNum = kSequenceDemoVirgin;
- }
- } else {
+ if (!_flags.isDemo || _flags.isTalkie) {
if ((seqNum != kSequenceTitle && seqNum < kSequenceZanfaun &&
(_abortIntroFlag || skipFlag())) || seqNum == kSequenceZanfaun) {
_abortIntroFlag = false;
@@ -319,8 +313,13 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
}
}
+ if (_flags.isDemo && !_flags.isTalkie) {
+ _eventList.clear();
+ _screen->fadeToBlack();
+ }
+
if (!_menuChoice)
- delay(1000);
+ delay(1200);
_screen->setCurPage(oldPage);
_screen->showMouse();
@@ -375,13 +374,14 @@ int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm
uint8 *tmpPal = &(_screen->getPalette(3)[0x101]);
memset(tmpPal, 0, 256);
- uint32 endtime = 0, now = 0;
+ _seqSubFrameEndTimeInternal = 0;
+ uint32 now = 0;
switch (_seqFrameCounter) {
case 0:
_seqSubframePlaying = true;
_sound->playTrack(4);
- endtime = _system->getMillis() + 60 * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + 60 * _tickLength;
_seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0) + 3, 255) & 0xff;
memset(_seqTextColorMap, _seqTextColor[1], 16);
@@ -390,8 +390,8 @@ int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm
_screen->setTextColorMap(_seqTextColorMap);
now = _system->getMillis();
- if (endtime > now)
- delay(endtime - now);
+ if (_seqSubFrameEndTimeInternal > now)
+ delay(_seqSubFrameEndTimeInternal - now);
break;
case 1:
@@ -830,7 +830,7 @@ int KyraEngine_HoF::seq_introHand3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
}
int KyraEngine_HoF::seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
- uint32 endtime = 0;
+ _seqSubFrameEndTimeInternal = 0;
int chatX = 0;
int chatY = 0;
int chatW = 0;
@@ -851,12 +851,12 @@ int KyraEngine_HoF::seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm
_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
_screen->setTextColorMap(_seqTextColorMap);
- endtime = _system->getMillis() + 480 * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
seq_printCreditsString(81, 240, 70, _seqTextColorMap, 252);
seq_printCreditsString(82, 240, 90, _seqTextColorMap, _seqTextColor[0]);
_screen->copyPage(2, 12);
- delay(endtime - _system->getMillis());
seq_playTalkText(_flags.isTalkie ? 28 : 24);
+ delay(_seqSubFrameEndTimeInternal - _system->getMillis());
_seqTextColor[0] = 1;
if (_flags.isTalkie) {
@@ -914,7 +914,7 @@ int KyraEngine_HoF::seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm
}
int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
- uint32 endtime = 0;
+ _seqSubFrameEndTimeInternal = 0;
int chatX = 0;
int chatY = 0;
int chatW = 0;
@@ -925,7 +925,7 @@ int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
switch (frm) {
case -2:
seq_sequenceCommand(9);
- endtime = _system->getMillis() + 480 * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
seq_printCreditsString(34, 240, _flags.isTalkie ? 60 : 40, _seqTextColorMap, 252);
seq_printCreditsString(35, 240, _flags.isTalkie ? 70 : 50, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(36, 240, _flags.isTalkie ? 90 : 70, _seqTextColorMap, 252);
@@ -934,7 +934,7 @@ int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
seq_printCreditsString(39, 240, _flags.isTalkie ? 130 : 120, _seqTextColorMap, _seqTextColor[0]);
if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
seq_printCreditsString(103, 240, 130, _seqTextColorMap, _seqTextColor[0]);
- delay(endtime - _system->getMillis());
+ delay(_seqSubFrameEndTimeInternal - _system->getMillis());
_seqEndTime = 0;
break;
@@ -998,7 +998,7 @@ int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
}
int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
- uint32 endtime = 0;
+ _seqSubFrameEndTimeInternal = 0;
int chatX = 0;
int chatY = 0;
int chatW = 0;
@@ -1007,7 +1007,7 @@ int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
switch (frm) {
case -2:
seq_sequenceCommand(9);
- endtime = _system->getMillis() + 480 * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
seq_printCreditsString(40, 240, _flags.isTalkie ? 55 : 40, _seqTextColorMap, 252);
seq_printCreditsString(41, 240, _flags.isTalkie ? 65 : 50, _seqTextColorMap, _seqTextColor[0]);
@@ -1016,7 +1016,7 @@ int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
seq_printCreditsString(44, 240, _flags.isTalkie ? 105 : 90, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(93, 240, _flags.isTalkie ? 125 : 110, _seqTextColorMap, 252);
seq_printCreditsString(94, 240, _flags.isTalkie ? 135 : 120, _seqTextColorMap, _seqTextColor[0]);
- delay(endtime - _system->getMillis());
+ delay(_seqSubFrameEndTimeInternal - _system->getMillis());
_seqEndTime = 0;
break;
@@ -1075,7 +1075,7 @@ int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
}
int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
- uint32 endtime = 0;
+ _seqSubFrameEndTimeInternal = 0;
int chatX = 0;
int chatY = 0;
int chatW = 0;
@@ -1089,7 +1089,7 @@ int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm)
_screen->copyPage(2, 0);
_screen->updateScreen();
seq_sequenceCommand(9);
- endtime = _system->getMillis() + 480 * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
seq_printCreditsString(49, 240, 20, _seqTextColorMap, 252);
seq_printCreditsString(50, 240, 30, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(51, 240, 40, _seqTextColorMap, _seqTextColor[0]);
@@ -1106,7 +1106,7 @@ int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm)
seq_printCreditsString(63, 240, 150, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(64, 240, 160, _seqTextColorMap, _seqTextColor[0]);
- delay(endtime - _system->getMillis());
+ delay(_seqSubFrameEndTimeInternal - _system->getMillis());
_seqEndTime = 0;
break;
@@ -1157,7 +1157,7 @@ int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm)
}
int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
- uint32 endtime = 0;
+ _seqSubFrameEndTimeInternal = 0;
int chatX = 0;
int chatY = 0;
int chatW = 0;
@@ -1169,7 +1169,7 @@ int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm)
_screen->copyPage(2, 0);
_screen->updateScreen();
seq_sequenceCommand(9);
- endtime = _system->getMillis() + 480 * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
seq_printCreditsString(45, 240, 40, _seqTextColorMap, 252);
seq_printCreditsString(46, 240, 50, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(47, 240, 60, _seqTextColorMap, _seqTextColor[0]);
@@ -1182,7 +1182,7 @@ int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm)
seq_printCreditsString(69, 240, 150, _seqTextColorMap, _seqTextColor[0]);
if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
seq_printCreditsString(104, 240, 160, _seqTextColorMap, _seqTextColor[0]);
- delay(endtime - _system->getMillis());
+ delay(_seqSubFrameEndTimeInternal - _system->getMillis());
_seqEndTime = 0;
break;
@@ -1227,7 +1227,7 @@ int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm)
}
int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
- uint32 endtime = 0;
+ _seqSubFrameEndTimeInternal = 0;
int chatX = 0;
int chatY = 0;
int chatW = 0;
@@ -1240,7 +1240,7 @@ int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm)
switch (frm) {
case -2:
seq_sequenceCommand(9);
- endtime = _system->getMillis() + 480 * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
seq_printCreditsString(70, 240, 20, _seqTextColorMap, 252);
seq_printCreditsString(71, 240, 30, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(72, 240, 40, _seqTextColorMap, _seqTextColor[0]);
@@ -1255,7 +1255,7 @@ int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm)
seq_printCreditsString(90, 240, 130, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(91, 240, 140, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(92, 240, 150, _seqTextColorMap, _seqTextColor[0]);
- delay(endtime - _system->getMillis());
+ delay(_seqSubFrameEndTimeInternal - _system->getMillis());
_seqEndTime = 0;
break;
@@ -1327,7 +1327,7 @@ int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm)
}
int KyraEngine_HoF::seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
- uint32 endtime = 0;
+ _seqSubFrameEndTimeInternal = 0;
int chatX = 0;
int chatY = 0;
int chatW = 0;
@@ -1339,7 +1339,7 @@ int KyraEngine_HoF::seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm
_screen->copyPage(2, 0);
_screen->updateScreen();
seq_sequenceCommand(9);
- endtime = _system->getMillis() + 480 * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
seq_printCreditsString(76, 240, 40, _seqTextColorMap, 252);
seq_printCreditsString(77, 240, 50, _seqTextColorMap, 252);
seq_printCreditsString(78, 240, 60, _seqTextColorMap, _seqTextColor[0]);
@@ -1349,7 +1349,7 @@ int KyraEngine_HoF::seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm
seq_printCreditsString(85, 240, 110, _seqTextColorMap, _seqTextColor[0]);
seq_printCreditsString(99, 240, 130, _seqTextColorMap, 252);
seq_printCreditsString(100, 240, 140, _seqTextColorMap, _seqTextColor[0]);
- delay(endtime - _system->getMillis());
+ delay(_seqSubFrameEndTimeInternal - _system->getMillis());
_seqEndTime = 0;
break;
@@ -1811,7 +1811,7 @@ uint32 KyraEngine_HoF::seq_activeTextsTimeLeft() {
}
void KyraEngine_HoF::seq_processWSAs() {
- for (int i = 0; i < 8; i++) {
+ for (int i = 0; i < 8; i++) {
if (_activeWSA[i].flags != -1) {
if (seq_processNextSubFrame(i))
seq_resetActiveWSA(i);
@@ -2334,13 +2334,16 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i
int dur = int(strlen(_sequenceStrings[strIndex])) * (_flags.isTalkie ? 7 : 15);
int entry = textEnabled() ? seq_setTextEntry(strIndex, x, y, dur, width) : strIndex;
_activeText[entry].textcolor = textColor;
- uint32 chatTimeout = _system->getMillis() + dur * _tickLength;
+ _seqWsaChatTimeout = _system->getMillis() + dur * _tickLength;
int curframe = firstframe;
- if (vocIndex && speechEnabled())
+ if (vocIndex && speechEnabled()) {
+ while (_sound->voiceIsPlaying() && !skipFlag())
+ delay(4);
seq_playTalkText(vocIndex);
+ }
- while (_system->getMillis() < chatTimeout && !(_abortIntroFlag || skipFlag())) {
+ while (_system->getMillis() < _seqWsaChatTimeout && !(_abortIntroFlag || skipFlag())) {
if (lastframe < 0) {
int t = ABS(lastframe);
if (t < curframe)
@@ -2350,7 +2353,7 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i
if (ABS(lastframe) < curframe)
curframe = firstframe;
- uint32 frameTimeout = _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength;
+ _seqWsaChatFrameTimeout = _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength;
if (wsa) {
wsa->setDrawPage(2);
wsa->setX(wsaXpos);
@@ -2363,8 +2366,8 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i
seq_processText();
uint32 tm = _system->getMillis();
- if (frameTimeout > tm && chatTimeout > tm)
- delay(MIN(frameTimeout - tm, chatTimeout - tm));
+ if (_seqWsaChatFrameTimeout > tm && _seqWsaChatTimeout > tm)
+ delay(MIN(_seqWsaChatFrameTimeout - tm, _seqWsaChatTimeout - tm));
if (speechEnabled() && !textEnabled() && !snd_voiceIsPlaying())
break;
@@ -2377,11 +2380,8 @@ void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, i
if (_abortIntroFlag || skipFlag())
_sound->voiceStop();
- if (lastframe < 0) {
- int t = ABS(lastframe);
- if (t < curframe)
- curframe = t;
- }
+ if (ABS(lastframe) < curframe)
+ curframe = ABS(lastframe);
if (curframe == firstframe)
curframe++;
@@ -2395,27 +2395,46 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
if (!data)
return;
- static const char mark[] = { 5, 13, 0};
+ static const char mark[] = { 5, 13, 0 };
_screen->clearPage(tempPage1);
_screen->clearPage(tempPage2);
_screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, 0, tempPage1);
- uint8 *tmp = new uint8[397];
- memset(tmp, 0, 397);
- uint8 **tmpStringTable = new uint8*[35];
+ struct ScrollTextData {
+ int16 x;
+ int16 y;
+ uint8 *text;
+ byte unk1;
+ byte height;
+ byte adjust;
+
+ ScrollTextData() {
+ x = 0; // 0 11
+ y = 0; // 2 13
+ text = 0; // 4 15
+ unk1 = 0; // 8 19
+ height = 0; // 9 20
+ adjust = 0; // 10 21
+ }
+ };
+
+ ScrollTextData *textData = new ScrollTextData[36];
uint8 *ptr = data;
- int strTblIndex = 0;
bool loop = true;
int cnt = 0;
while (loop) {
- uint32 endTime = _system->getMillis() + speed * _tickLength;
+ _seqSubFrameEndTimeInternal = _system->getMillis() + speed * _tickLength;
while (cnt < 35 && *ptr) {
- int m = cnt * 11;
- uint16 cH = cnt ? READ_LE_UINT16(&tmp[m + 2]) + tmp[m + 9] + (tmp[m + 9] >> 3) : d->h;
+ uint16 cH;
+
+ if (cnt)
+ cH = textData[cnt].y + textData[cnt].height + (textData[cnt].height >> 3);
+ else
+ cH = d->h;
char *str = (char*)ptr;
@@ -2423,12 +2442,15 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
if (!ptr)
ptr = (uint8*)strchr(str, 0);
- tmp[m + 19] = *ptr;
+ textData[cnt + 1].unk1 = *ptr;
*ptr = 0;
- if (tmp[m + 19])
+ if (textData[cnt + 1].unk1)
ptr++;
- tmp[m + 21] = (*str == 3 || *str == 4) ? tmp[m + 21] = *str++ : 0;
+ if (*str == 3 || *str == 4)
+ textData[cnt + 1].adjust = *str++;
+ else
+ textData[cnt + 1].adjust = 0;
_screen->setFont(fid1);
@@ -2439,18 +2461,25 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
str++;
}
- tmp[m + 20] = _screen->getFontHeight();
+ textData[cnt + 1].height = _screen->getFontHeight();
- WRITE_LE_UINT16(&tmp[m + 11], (tmp[m + 21] == 3) ? 157 - _screen->getTextWidth(str) :
- ((tmp[m + 21] == 4) ? 161 : (((d->w << 3) - _screen->getTextWidth(str)) >> 1) + 1));
+ switch (textData[cnt + 1].adjust) {
+ case 3:
+ textData[cnt + 1].x = 157 - _screen->getTextWidth(str);
+ break;
+ case 4:
+ textData[cnt + 1].x = 161;
+ break;
+ default:
+ textData[cnt + 1].x = (((d->w << 3) - _screen->getTextWidth(str)) >> 1) + 1;
+ break;
+ }
- if (tmp[m + 8] == 5)
- cH -= (tmp[m + 9] + (tmp[m + 9] >> 3));
+ if (textData[cnt].unk1 == 5)
+ cH -= (textData[cnt].height + (textData[cnt].height >> 3));
- WRITE_LE_UINT16(&tmp[m + 13], cH);
- WRITE_LE_UINT32(&tmp[m + 15], strTblIndex);
- tmpStringTable[strTblIndex] = (uint8*) str;
- strTblIndex = (strTblIndex + 1) % 35;
+ textData[cnt + 1].y = cH;
+ textData[cnt + 1].text = (uint8*) str;
cnt++;
}
@@ -2460,11 +2489,10 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
bool palCycle = 0;
while (cnt2 < cnt) {
- int m = cnt2 * 11;
- const char *str = (const char*)tmpStringTable[READ_LE_UINT32(&tmp[m + 15])];
+ const char *str = (const char*)textData[cnt2 + 1].text;
const char *str2 = str;
- uint16 cW = READ_LE_UINT16(&tmp[m + 11]) - 10;
- uint16 cH = READ_LE_UINT16(&tmp[m + 13]);
+ int16 cW = textData[cnt2 + 1].x - 10;
+ int16 cH = textData[cnt2 + 1].y;
int x = (d->sx << 3) + cW;
int y = d->sy + cH;
int col1 = 255;
@@ -2472,7 +2500,7 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
if (cH < d->h) {
_screen->setCurPage(tempPage2);
_screen->setFont(fid1);
- if (tmp[m + 20] != _screen->getFontHeight())
+ if (textData[cnt2 + 1].height != _screen->getFontHeight())
_screen->setFont(fid2);
if (specialData) {
@@ -2503,18 +2531,18 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
_screen->setCurPage(0);
}
- WRITE_LE_UINT16(&tmp[m + 13], READ_LE_UINT16(&tmp[m + 13]) - step);
+ textData[cnt2 + 1].y -= step;
cnt2++;
}
_screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage2, 0);
_screen->updateScreen();
- if ((int16)READ_LE_UINT16(&tmp[13]) < -10) {
- tmpStringTable[tmp[15]] += strlen((char*)tmpStringTable[tmp[15]]);
- tmpStringTable[tmp[15]][0] = tmp[19];
+ if (textData[1].y < -10) {
+ textData[1].text += strlen((char*)textData[1].text);
+ textData[1].text[0] = textData[1].unk1;
cnt--;
- memcpy(&tmp[11], &tmp[22], cnt * 11);
+ memcpy(&textData[1], &textData[2], cnt * sizeof(ScrollTextData));
}
if (palCycle) {
@@ -2524,9 +2552,9 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
_screen->setScreenPalette(_screen->_currentPalette);
}
- delayUntil(endTime);
+ delayUntil(_seqSubFrameEndTimeInternal);
- if ((cnt < 36) && ((d->sy + d->h) > (READ_LE_UINT16(&tmp[cnt * 11 + 2]) + tmp[cnt * 11 + 9])) && !skipFlag()) {
+ if ((cnt < 36) && ((d->sy + d->h) > (textData[cnt].y + textData[cnt].height)) && !skipFlag()) {
resetSkipFlag();
delay(_tickLength * 500);
cnt = 0;
@@ -2542,8 +2570,7 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
_abortIntroFlag= false;
resetSkipFlag();
- delete[] tmp;
- delete[] tmpStringTable;
+ delete[] textData;
}
void KyraEngine_HoF::seq_scrollPage() {
@@ -2594,20 +2621,20 @@ void KyraEngine_HoF::seq_showStarcraftLogo() {
_screen->copyPage(2, 0);
_screen->fadeFromBlack();
for (int i = 1; i < endframe; i++) {
- uint32 endTime = _system->getMillis() + 50;
+ _seqEndTime = _system->getMillis() + 50;
if (skipFlag())
break;
ci->displayFrame(i, 0);
_screen->copyPage(2, 0);
_screen->updateScreen();
- delay(endTime - _system->getMillis());
+ delay(_seqEndTime - _system->getMillis());
}
if(!skipFlag()) {
- uint32 endTime = _system->getMillis() + 50;
+ _seqEndTime = _system->getMillis() + 50;
ci->displayFrame(0, 0);
_screen->copyPage(2, 0);
_screen->updateScreen();
- delay(endTime - _system->getMillis());
+ delay(_seqEndTime - _system->getMillis());
}
_screen->fadeToBlack();
_screen->showMouse();
@@ -2624,6 +2651,8 @@ void KyraEngine_HoF::seq_init() {
_res->unloadAllPakFiles();
_res->loadPakFile(StaticResource::staticDataFilename());
+ if (_flags.useInstallerPackage)
+ _res->loadPakFile("WESTWOOD.001");
_res->loadFileList(_sequencePakList, _sequencePakListSize);
int numShp = -1;
@@ -2783,3 +2812,4 @@ void KyraEngine_HoF::seq_makeBookAppear() {
} // end of namespace Kyra
+
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index a8566a7309..8f9077705e 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -66,17 +66,14 @@ bool Sound::voiceFileIsPresent(const char *file) {
return false;
}
-bool Sound::voicePlay(const char *file, bool isSfx) {
- uint32 fileSize = 0;
- byte *fileData = 0;
- bool found = false;
+int32 Sound::voicePlay(const char *file, bool isSfx) {
char filenamebuffer[25];
int h = 0;
while (_mixer->isSoundHandleActive(_soundChannels[h].channelHandle) && h < kNumChannelHandles)
h++;
if (h >= kNumChannelHandles)
- return false;
+ return 0;
Audio::AudioStream *audioStream = 0;
@@ -88,29 +85,29 @@ bool Sound::voicePlay(const char *file, bool isSfx) {
if (!stream)
continue;
audioStream = _supportedCodes[i].streamFunc(stream, true, 0, 0, 1);
- found = true;
break;
}
- if (!found) {
+ if (!audioStream) {
strcpy(filenamebuffer, file);
strcat(filenamebuffer, ".VOC");
- fileData = _vm->resource()->fileData(filenamebuffer, &fileSize);
+ uint32 fileSize = 0;
+ byte *fileData = _vm->resource()->fileData(filenamebuffer, &fileSize);
if (!fileData)
- return false;
+ return 0;
Common::MemoryReadStream vocStream(fileData, fileSize);
audioStream = Audio::makeVOCStream(vocStream);
+
+ delete[] fileData;
+ fileSize = 0;
}
_soundChannels[h].file = file;
_mixer->playInputStream(isSfx ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType, &_soundChannels[h].channelHandle, audioStream);
- delete[] fileData;
- fileSize = 0;
-
- return true;
+ return audioStream->getTotalPlayTime();
}
void Sound::voiceStop(const char *file) {
@@ -143,6 +140,18 @@ bool Sound::voiceIsPlaying(const char *file) {
return res;
}
+uint32 Sound::voicePlayedTime(const char *file) {
+ if (!file)
+ return 0;
+
+ for (int i = 0; i < kNumChannelHandles; ++i) {
+ if (_soundChannels[i].file == file)
+ return _mixer->getSoundElapsedTime(_soundChannels[i].channelHandle);
+ }
+
+ return 0;
+}
+
#pragma mark -
SoundMidiPC::SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *driver) : Sound(vm, mixer) {
@@ -529,12 +538,15 @@ void KyraEngine_v1::snd_playWanderScoreViaMap(int command, int restart) {
void KyraEngine_v1::snd_stopVoice() {
debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine_v1::snd_stopVoice()");
- _sound->voiceStop(_speechFile.empty() ? 0 : _speechFile.c_str());
+ if (!_speechFile.empty()) {
+ _sound->voiceStop(_speechFile.c_str());
+ _speechFile.clear();
+ }
}
bool KyraEngine_v1::snd_voiceIsPlaying() {
debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine_v1::snd_voiceIsPlaying()");
- return _sound->voiceIsPlaying(_speechFile.empty() ? 0 : _speechFile.c_str());
+ return _speechFile.empty() ? false : _sound->voiceIsPlaying(_speechFile.c_str());
}
// static res
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index 595619c7e9..2427a6cdde 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -174,9 +174,9 @@ public:
*
* @param file file to be played
* @param isSfx marks file as sfx instead of voice
- * @return channel the voice file is played on
+ * @return playtime of the voice file (-1 marks unknown playtime)
*/
- virtual bool voicePlay(const char *file, bool isSfx = false);
+ virtual int32 voicePlay(const char *file, bool isSfx = false);
/**
* Checks if a voice is being played.
@@ -186,6 +186,13 @@ public:
bool voiceIsPlaying(const char *file = 0);
/**
+ * Checks how long a voice has been playing
+ *
+ * @return time in milliseconds
+ */
+ uint32 voicePlayedTime(const char *file);
+
+ /**
* Stops playback of the current voice.
*/
void voiceStop(const char *file = 0);
@@ -449,7 +456,7 @@ public:
void haltTrack();
void beginFadeOut();
- bool voicePlay(const char *file, bool isSfx = false);
+ int32 voicePlay(const char *file, bool isSfx = false);
void playSoundEffect(uint8) {}
private:
diff --git a/engines/kyra/sound_lok.cpp b/engines/kyra/sound_lok.cpp
index 728013cdaa..8a1d16a6b1 100644
--- a/engines/kyra/sound_lok.cpp
+++ b/engines/kyra/sound_lok.cpp
@@ -67,7 +67,7 @@ void KyraEngine_LoK::snd_playVoiceFile(int id) {
assert(id >= 0 && id < 9999);
sprintf(vocFile, "%03d", id);
_speechFile = vocFile;
- _sound->voicePlay(vocFile);
+ _speechPlayTime = _sound->voicePlay(vocFile);
}
void KyraEngine_LoK::snd_voiceWaitForFinish(bool ingame) {
@@ -80,4 +80,11 @@ void KyraEngine_LoK::snd_voiceWaitForFinish(bool ingame) {
}
}
+uint32 KyraEngine_LoK::snd_getVoicePlayTime() {
+ debugC(9, kDebugLevelMain | kDebugLevelSound, "KyraEngine_LoK::snd_getVoicePlayTime()");
+ if (!snd_voiceIsPlaying())
+ return 0;
+ return (_speechPlayTime != -1 ? _speechPlayTime : 0);
+}
+
} // end of namespace Kyra
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 513f523194..4265533507 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -1301,6 +1301,7 @@ bool SoundTowns::loadInstruments() {
void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0);
+ Common::StackLock lock(_mutex);
if (!_parser) {
_parser = new MidiParser_EuD(_driver->queue());
@@ -1431,7 +1432,7 @@ void SoundTowns_v2::haltTrack() {
//_driver->reset();
}
-bool SoundTowns_v2::voicePlay(const char *file, bool) {
+int32 SoundTowns_v2::voicePlay(const char *file, bool) {
static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 };
int h = 0;
@@ -1439,7 +1440,7 @@ bool SoundTowns_v2::voicePlay(const char *file, bool) {
while (_mixer->isSoundHandleActive(_soundChannels[h].channelHandle) && h < kNumChannelHandles)
h++;
if (h >= kNumChannelHandles)
- return false;
+ return 0;
}
char filename [13];
@@ -1496,7 +1497,7 @@ bool SoundTowns_v2::voicePlay(const char *file, bool) {
_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_soundChannels[h].channelHandle, _currentSFX);
delete[] data;
- return true;
+ return 1;
}
void SoundTowns_v2::beginFadeOut() {
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 7ba19e9966..302b92ab07 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -40,11 +40,9 @@
#include "kyra/gui_hof.h"
#include "kyra/gui_mr.h"
-#include "gui/message.h"
-
namespace Kyra {
-#define RESFILE_VERSION 27
+#define RESFILE_VERSION 28
bool StaticResource::checkKyraDat() {
Common::File kyraDat;
@@ -293,18 +291,20 @@ bool StaticResource::init() {
error("unknown game ID");
}
+ char errorBuffer[100];
int tempSize = 0;
uint8 *temp = getFile("INDEX", tempSize);
if (!temp) {
- warning("No matching INDEX file found ('%s')", getFilename("INDEX"));
- outputError();
+ snprintf(errorBuffer, sizeof(errorBuffer), "is missing an '%s' entry", getFilename("INDEX"));
+ outputError(errorBuffer);
return false;
}
if (tempSize != 3*4) {
delete[] temp;
- warning("'%s' has illegal filesize %d", getFilename("INDEX"), tempSize);
- outputError();
+
+ snprintf(errorBuffer, sizeof(errorBuffer), "has incorrect header size for entry '%s'", getFilename("INDEX"));
+ outputError(errorBuffer);
return false;
}
@@ -316,28 +316,25 @@ bool StaticResource::init() {
temp = 0;
if (version != RESFILE_VERSION) {
- warning("Invalid KYRA.DAT file version (%u, required %d)", version, RESFILE_VERSION);
- outputError();
+ snprintf(errorBuffer, sizeof(errorBuffer), "has invalid version %d required, you got %d", RESFILE_VERSION, version);
+ outputError(errorBuffer);
return false;
}
if (gameID != _vm->game()) {
- warning("Invalid game id (%u)", gameID);
- outputError();
+ outputError("does not include support for your game");
return false;
}
uint32 gameFeatures = createFeatures(_vm->gameFlags());
if ((featuresValue & GAME_FLAGS) != gameFeatures) {
- warning("Your data file has a different game flags (0x%.08X has the data and your version has 0x%.08X)", (featuresValue & GAME_FLAGS), gameFeatures);
- outputError();
+ outputError("does not include support for your game version");
return false;
}
// load all tables for now
if (!prefetchId(-1)) {
- warning("Couldn't load all needed resources from 'KYRA.DAT'");
- outputError();
+ outputError("is lacking entries for your game version");
return false;
}
return true;
@@ -347,11 +344,10 @@ void StaticResource::deinit() {
unloadId(-1);
}
-void StaticResource::outputError() {
- Common::String errorMessage = "Your '" + StaticResource::staticDataFilename() + "' file is outdated, reget it from the ScummVM website";
- ::GUI::MessageDialog errorMsg(errorMessage);
- errorMsg.runModal();
- error(errorMessage.c_str());
+void StaticResource::outputError(const Common::String &error) {
+ Common::String errorMessage = "Your '" + StaticResource::staticDataFilename() + "' file " + error + ", reget a correct version from the ScummVM website";
+ _vm->GUIErrorMessage(errorMessage);
+ ::error(errorMessage.c_str());
}
const char * const*StaticResource::loadStrings(int id, int &strings) {
@@ -1281,7 +1277,7 @@ void KyraEngine_HoF::initStaticResource() {
&KyraEngine_HoF::seq_introLibrary2, &KyraEngine_HoF::seq_introLibrary2,
&KyraEngine_HoF::seq_introMarco, &KyraEngine_HoF::seq_introHand1a,
&KyraEngine_HoF::seq_introHand1b, &KyraEngine_HoF::seq_introHand1c,
- &KyraEngine_HoF::seq_introHand2, &KyraEngine_HoF::seq_introHand3, 0
+ &KyraEngine_HoF::seq_introHand2, &KyraEngine_HoF::seq_introHand3, 0
};
static const SeqProc hofDemoSequenceCallbacks[] = {
@@ -1363,11 +1359,11 @@ const int8 KyraEngine_v1::_addYPosTable[] = {
0, -2, -2, -2, 0, 2, 2, 2
};
-const int8 KyraEngine_LoK::_charXPosTable[] = {
+const int8 KyraEngine_v1::_charAddXPosTable[] = {
0, 4, 4, 4, 0, -4, -4, -4
};
-const int8 KyraEngine_LoK::_charYPosTable[] = {
+const int8 KyraEngine_v1::_charAddYPosTable[] = {
-2, -2, 0, 2, 2, 2, 0, -2
};
@@ -1534,14 +1530,6 @@ const int KyraEngine_LoK::_dosTrackMapSize = ARRAYSIZE(KyraEngine_LoK::_dosTrack
// kyra engine v2 static data
-const int8 KyraEngine_v2::_updateCharPosXTable[] = {
- 0, 4, 4, 4, 0, -4, -4, -4
-};
-
-const int8 KyraEngine_v2::_updateCharPosYTable[] = {
- -2, -2, 0, 2, 2, 2, 0, -2
-};
-
const int GUI_v2::_sliderBarsPosition[] = {
0x92, 0x1F, 0x92, 0x30, 0x92, 0x41, 0x92, 0x52
};
@@ -1554,16 +1542,16 @@ const char *KyraEngine_HoF::_languageExtension[] = {
"ENG",
"FRE",
"GER",/*,
- "ITA", Italian and Spanish was never included
+ "ITA", Italian and Spanish were never included
"SPA"*/
- "JPN"
+ "JPN",
};
const char *KyraEngine_HoF::_scriptLangExt[] = {
"EMC",
"FMC",
"GMC",/*,
- "IMC", Italian and Spanish was never included
+ "IMC", Italian and Spanish were never included
"SMC"*/
"JMC"
};
@@ -1956,7 +1944,7 @@ const char *KyraEngine_MR::_languageExtension[] = {
"TRE",
"TRF",
"TRG"/*,
- "TRI", Italian and Spanish was never included
+ "TRI", Italian and Spanish were never included
"TRS"*/
};
diff --git a/engines/kyra/text.cpp b/engines/kyra/text.cpp
index 931c5fe1c9..f8eb10a85e 100644
--- a/engines/kyra/text.cpp
+++ b/engines/kyra/text.cpp
@@ -210,7 +210,7 @@ void TextDisplayer::printTalkTextMessage(const char *text, int x, int y, uint8 c
calcWidestLineBounds(x1, x2, w, x);
_talkCoords.x = x1;
_talkCoords.w = w + 2;
- _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkCoords.y, _talkCoords.w, _talkMessageH, srcPage, dstPage);
+ _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkCoords.y, _talkCoords.w, _talkMessageH, srcPage, dstPage, Screen::CR_NO_P_CHECK);
int curPage = _screen->_curPage;
_screen->_curPage = srcPage;
for (int i = 0; i < lineCount; ++i) {
diff --git a/engines/kyra/text_hof.cpp b/engines/kyra/text_hof.cpp
index 0d40827390..dd587c5112 100644
--- a/engines/kyra/text_hof.cpp
+++ b/engines/kyra/text_hof.cpp
@@ -107,8 +107,7 @@ char *TextDisplayer_HoF::preprocessString(const char *str) {
int textWidth = _screen->getTextWidth(p);
_screen->_charWidth = 0;
- // longer text strings for German versions
- int maxTextWidth = (_vm->language() == 2 ? 240 : 176);
+ int maxTextWidth = (_vm->language() == 0) ? 176 : 240;
if (textWidth > maxTextWidth) {
if (textWidth > (maxTextWidth*2)) {
diff --git a/engines/kyra/text_lok.cpp b/engines/kyra/text_lok.cpp
index ccca079e32..f6b0407a75 100644
--- a/engines/kyra/text_lok.cpp
+++ b/engines/kyra/text_lok.cpp
@@ -62,10 +62,8 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const
if (chatDuration != -1)
chatDuration *= _tickLength;
- if (vocFile != -1) {
- snd_voiceWaitForFinish();
+ if (vocFile != -1)
snd_playVoiceFile(vocFile);
- }
_timer->disable(14);
_timer->disable(18);
@@ -269,6 +267,8 @@ void KyraEngine_LoK::characterSays(int vocFile, const char *chatStr, int8 charNu
if (_currentCharacter->sceneId == 210)
return;
+ snd_voiceWaitForFinish(true);
+
convoInitialized = initCharacterChat(charNum);
chatPartnerNum = getChatPartnerNum();
diff --git a/engines/kyra/text_mr.cpp b/engines/kyra/text_mr.cpp
index 13b37fa77a..16c56da099 100644
--- a/engines/kyra/text_mr.cpp
+++ b/engines/kyra/text_mr.cpp
@@ -55,25 +55,26 @@ char *TextDisplayer_MR::preprocessString(const char *str) {
int count = 0, offs = 0;
if (textWidth > (3*maxTextWidth)) {
count = getCharLength(p, textWidth/4);
- offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count);
+ offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
p += count + offs;
- }
-
+ // No update of textWidth here
+ }
+
if (textWidth > (2*maxTextWidth)) {
count = getCharLength(p, textWidth/3);
- offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count);
+ offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
p += count + offs;
textWidth = _screen->getTextWidth(p);
}
count = getCharLength(p, textWidth/2);
- offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count);
+ offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
p += count + offs;
textWidth = _screen->getTextWidth(p);
if (textWidth > maxTextWidth) {
count = getCharLength(p, textWidth/2);
- offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count);
+ offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
}
}
@@ -232,7 +233,7 @@ void KyraEngine_MR::objectChat(const char *str, int object, int vocHigh, int voc
"MTFR00S.EMC", "MTFR00Q.EMC", "MTFR00E.EMC", "MTFR00T.EMC",
"MTL00S.EMC", "MTL00Q.EMC", "MTL00E.EMC", "MTL00T.EMC",
"MTR00S.EMC", "MTR00Q.EMC", "MTR00E.EMC", "MTR00T.EMC",
- "MTA00S.EMC", "MTA00Q.EMC", "MTA00Q.EMC", "MTA00T.EMC"
+ "MTA00S.EMC", "MTA00Q.EMC", "MTA00E.EMC", "MTA00T.EMC"
};
int chat = talkScriptTable[chatType + _mainCharacter.facing * 4];
diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp
index cea52e911e..3d18f27c7e 100644
--- a/engines/kyra/vqa.cpp
+++ b/engines/kyra/vqa.cpp
@@ -362,9 +362,8 @@ void VQAMovie::close() {
delete[] _partialCodeBook;
delete[] _vectorPointers;
- if (_vm->_mixer->isSoundHandleActive(_sound)) {
+ if (_vm->_mixer->isSoundHandleActive(_sound))
_vm->_mixer->stopHandle(_sound);
- }
_frameInfo = NULL;
_frame = NULL;
@@ -655,11 +654,10 @@ void VQAMovie::play() {
while (1) {
uint32 elapsedTime;
- if (_vm->_mixer->isSoundHandleActive(_sound)) {
+ if (_vm->_mixer->isSoundHandleActive(_sound))
elapsedTime = _vm->_mixer->getSoundElapsedTime(_sound);
- } else {
+ else
elapsedTime = _system->getMillis() - startTick;
- }
if (elapsedTime >= (i * 1000) / _header.frameRate)
break;