[Scummvm-cvs-logs] scummvm master -> 086dd66a654e5b08c7c15b8715c4b15e211f6727

athrxx athrxx at scummvm.org
Sun Nov 11 19:45:39 CET 2012


This automated email contains information about 8 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
4e65b67c30 KYRA: (LoL) - fix warning in Screen_LoL::drawGridBox()
17ed912ed5 AUDIO: remove unused variables in FM-TOWNS imuse driver
8789087be9 KYRA: fix LOL sfx volume
e016e7dfc2 KYRA: implement LOL sfx priority handling
9840744acc KYRA: move HOF sequence player into its own class
1bb8f22567 KYRA: finish implementation of new HOF sequence player code
93e69aa4da KYRA: clean up audio resource handling
086dd66a65 KYRA: fix several GCC compile issues in previous commits


Commit: 4e65b67c309f2dcdf5e2d65828b41912abef9ac8
    https://github.com/scummvm/scummvm/commit/4e65b67c309f2dcdf5e2d65828b41912abef9ac8
Author: athrxx (athrxx at scummvm.org)
Date: 2012-11-11T10:14:26-08:00

Commit Message:
KYRA: (LoL) - fix warning in Screen_LoL::drawGridBox()

Changed paths:
    engines/kyra/screen_lol.cpp



diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp
index 3726b1f..714a9d8 100644
--- a/engines/kyra/screen_lol.cpp
+++ b/engines/kyra/screen_lol.cpp
@@ -233,8 +233,6 @@ void Screen_LoL::drawGridBox(int x, int y, int w, int h, int col) {
 				*(p + tmp) = col;
 				p += 2;
 			}
-		} else {
-			w = 1;
 		}
 
 		if (s == 1) {


Commit: 17ed912ed538eee539ab199c738ccfa3709f7e31
    https://github.com/scummvm/scummvm/commit/17ed912ed538eee539ab199c738ccfa3709f7e31
Author: athrxx (athrxx at scummvm.org)
Date: 2012-11-11T10:14:26-08:00

Commit Message:
AUDIO: remove unused variables in FM-TOWNS imuse driver

Changed paths:
    audio/softsynth/fmtowns_pc98/towns_midi.cpp



diff --git a/audio/softsynth/fmtowns_pc98/towns_midi.cpp b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
index b820394..46b1a64 100644
--- a/audio/softsynth/fmtowns_pc98/towns_midi.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_midi.cpp
@@ -147,17 +147,10 @@ private:
 	TownsMidiOutputChannel *_out;
 
 	uint8 *_instrument;
-	uint8 _prg;
 	uint8 _chanIndex;
-	uint8 _effectLevel;
 	uint8 _priority;
-	uint8 _ctrlVolume;
 	uint8 _tl;
-	uint8 _pan;
-	uint8 _panEff;
-	uint8 _percS;
 	int8 _transpose;
-	uint8 _fld_1f;
 	int8 _detune;
 	int8 _modWheel;
 	uint8 _sustain;
@@ -659,9 +652,8 @@ const uint16 TownsMidiOutputChannel::_freqLSB[] = {
 	0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B, 0x055B
 };
 
-TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _out(0), _prg(0), _chanIndex(chanIndex),
-	_effectLevel(0), _priority(0), _ctrlVolume(0), _tl(0), _pan(0), _panEff(0), _transpose(0), _percS(0), _pitchBendFactor(0), _pitchBend(0), _sustain(0), _freqLSB(0),
-	_fld_1f(0), _detune(0), _modWheel(0), _allocated(false) {
+TownsMidiInputChannel::TownsMidiInputChannel(MidiDriver_TOWNS *driver, int chanIndex) : MidiChannel(), _driver(driver), _out(0), _chanIndex(chanIndex),
+	_priority(0), _tl(0), _transpose(0), _pitchBendFactor(0), _pitchBend(0), _sustain(0), _freqLSB(0), _detune(0), _modWheel(0), _allocated(false) {
 	_instrument = new uint8[30];
 	memset(_instrument, 0, 30);
 }


Commit: 8789087be9749f7a13fbfdd72a2c984c0bc9e158
    https://github.com/scummvm/scummvm/commit/8789087be9749f7a13fbfdd72a2c984c0bc9e158
Author: athrxx (athrxx at scummvm.org)
Date: 2012-11-11T10:14:27-08:00

Commit Message:
KYRA: fix LOL sfx volume

Changed paths:
    engines/kyra/sound_lol.cpp



diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp
index cb9be43..6c88312 100644
--- a/engines/kyra/sound_lol.cpp
+++ b/engines/kyra/sound_lol.cpp
@@ -165,10 +165,19 @@ void LoLEngine::snd_playSoundEffect(int track, int volume) {
 		return;
 
 	volume &= 0xff;
-	int16 volIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2 + 1]);
+	// Priority setting (used for acquiring one of the 4 pcm channels) currently not implemented.
+	// int16 vprIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2 + 1]);
+	// uint16 priority = (vprIndex > 0) ? (vprIndex * volume) >> 8 : -vprIndex;
 
-	uint16 vocLevel = (volIndex > 0) ? (volIndex * volume) >> 8 : -volIndex;
-	vocLevel = CLIP(volume >> 4, 2, 13) * 7 + 164;
+	static const uint8 volTable1[] = { 223, 159, 95, 47, 15, 0 };
+	static const uint8 volTable2[] = { 255, 191, 127, 63, 30, 0 };
+
+	for (int i = 0; i < 6; i++) {
+		if (volTable1[i] < volume) {
+			volume = volTable2[i];
+			break;
+		}
+	}
 
 	int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]);
 
@@ -180,7 +189,7 @@ void LoLEngine::snd_playSoundEffect(int track, int volume) {
 
 	if (hasVocFile) {
 		if (_sound->isVoicePresent(_ingameSoundList[vocIndex]))
-			_sound->voicePlay(_ingameSoundList[vocIndex], 0, vocLevel & 0xff, true);
+			_sound->voicePlay(_ingameSoundList[vocIndex], 0, volume, true);
 	} else if (_flags.platform == Common::kPlatformPC) {
 		if (_sound->getSfxType() == Sound::kMidiMT32)
 			track = (track < _ingameMT32SoundIndexSize) ? (_ingameMT32SoundIndex[track] - 1) : -1;


Commit: e016e7dfc2b1e3cdb39c01d81c5a34eee66a277b
    https://github.com/scummvm/scummvm/commit/e016e7dfc2b1e3cdb39c01d81c5a34eee66a277b
Author: athrxx (athrxx at scummvm.org)
Date: 2012-11-11T10:14:28-08:00

Commit Message:
KYRA: implement LOL sfx priority handling

Changed paths:
    engines/kyra/sound.cpp
    engines/kyra/sound.h
    engines/kyra/sound_intern.h
    engines/kyra/sound_lol.cpp
    engines/kyra/sound_towns.cpp



diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index 73c20ee..9d3e5f6 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -73,7 +73,7 @@ bool Sound::isVoicePresent(const char *file) const {
 	return false;
 }
 
-int32 Sound::voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx) {
+int32 Sound::voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, uint8 priority, bool isSfx) {
 	Audio::SeekableAudioStream *audioStream = getVoiceStream(file);
 
 	if (!audioStream) {
@@ -81,7 +81,7 @@ int32 Sound::voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volum
 	}
 
 	int playTime = audioStream->getLength().msecs();
-	playVoiceStream(audioStream, handle, volume, isSfx);
+	playVoiceStream(audioStream, handle, volume, priority, isSfx);
 	return playTime;
 }
 
@@ -109,12 +109,20 @@ Audio::SeekableAudioStream *Sound::getVoiceStream(const char *file) const {
 	}
 }
 
-bool Sound::playVoiceStream(Audio::AudioStream *stream, Audio::SoundHandle *handle, uint8 volume, bool isSfx) {
+bool Sound::playVoiceStream(Audio::AudioStream *stream, Audio::SoundHandle *handle, uint8 volume, uint8 priority, bool isSfx) {
 	int h = 0;
-	while (h < kNumChannelHandles && _mixer->isSoundHandleActive(_soundChannels[h]))
+	while (h < kNumChannelHandles && _mixer->isSoundHandleActive(_soundChannels[h].handle))
 		++h;
 
 	if (h >= kNumChannelHandles) {
+		h = 0;
+		while (h < kNumChannelHandles && _soundChannels[h].priority > priority)
+			++h;
+		if (h < kNumChannelHandles)
+			voiceStop(&_soundChannels[h].handle);
+	}
+
+	if (h >= kNumChannelHandles) {
 		// When we run out of handles we need to destroy the stream object,
 		// this is to avoid memory leaks in some scenes where too many sfx
 		// are started.
@@ -123,9 +131,10 @@ bool Sound::playVoiceStream(Audio::AudioStream *stream, Audio::SoundHandle *hand
 		return false;
 	}
 
-	_mixer->playStream(isSfx ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType, &_soundChannels[h], stream, -1, volume);
+	_mixer->playStream(isSfx ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType, &_soundChannels[h].handle, stream, -1, volume);
+	_soundChannels[h].priority = priority;
 	if (handle)
-		*handle = _soundChannels[h];
+		*handle = _soundChannels[h].handle;
 
 	return true;
 }
@@ -133,8 +142,8 @@ bool Sound::playVoiceStream(Audio::AudioStream *stream, Audio::SoundHandle *hand
 void Sound::voiceStop(const Audio::SoundHandle *handle) {
 	if (!handle) {
 		for (int h = 0; h < kNumChannelHandles; ++h) {
-			if (_mixer->isSoundHandleActive(_soundChannels[h]))
-				_mixer->stopHandle(_soundChannels[h]);
+			if (_mixer->isSoundHandleActive(_soundChannels[h].handle))
+				_mixer->stopHandle(_soundChannels[h].handle);
 		}
 	} else {
 		_mixer->stopHandle(*handle);
@@ -144,7 +153,7 @@ void Sound::voiceStop(const Audio::SoundHandle *handle) {
 bool Sound::voiceIsPlaying(const Audio::SoundHandle *handle) const {
 	if (!handle) {
 		for (int h = 0; h < kNumChannelHandles; ++h) {
-			if (_mixer->isSoundHandleActive(_soundChannels[h]))
+			if (_mixer->isSoundHandleActive(_soundChannels[h].handle))
 				return true;
 		}
 	} else {
@@ -156,7 +165,7 @@ bool Sound::voiceIsPlaying(const Audio::SoundHandle *handle) const {
 
 bool Sound::allVoiceChannelsPlaying() const {
 	for (int i = 0; i < kNumChannelHandles; ++i)
-		if (!_mixer->isSoundHandleActive(_soundChannels[i]))
+		if (!_mixer->isSoundHandleActive(_soundChannels[i].handle))
 			return false;
 	return true;
 }
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index 63cec48..384aeb4 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -184,11 +184,11 @@ public:
 	 * @param handle    store a copy of the sound handle
 	 * @return playtime of the voice file (-1 marks unknown playtime)
 	 */
-	virtual int32 voicePlay(const char *file, Audio::SoundHandle *handle = 0, uint8 volume = 255, bool isSfx = false);
+	virtual int32 voicePlay(const char *file, Audio::SoundHandle *handle = 0, uint8 volume = 255, uint8 priority = 255, bool isSfx = false);
 
 	Audio::SeekableAudioStream *getVoiceStream(const char *file) const;
 
-	bool playVoiceStream(Audio::AudioStream *stream, Audio::SoundHandle *handle = 0, uint8 volume = 255, bool isSfx = false);
+	bool playVoiceStream(Audio::AudioStream *stream, Audio::SoundHandle *handle = 0, uint8 volume = 255, uint8 priority = 255, bool isSfx = false);
 
 	/**
 	 * Checks if a voice is being played.
@@ -238,7 +238,13 @@ protected:
 		kNumChannelHandles = 4
 	};
 
-	Audio::SoundHandle _soundChannels[kNumChannelHandles];
+	struct SoundChannel {
+		SoundChannel() : handle(), priority(0) {}
+		Audio::SoundHandle handle;
+		int priority;
+	};
+	
+	SoundChannel _soundChannels[kNumChannelHandles];
 
 	int _musicEnabled;
 	bool _sfxEnabled;
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index 827a487..e09fe7e 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -193,7 +193,7 @@ public:
 	void haltTrack();
 	void beginFadeOut();
 
-	int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx);
+	int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume = 255, uint8 priority = 255, bool isSfx = true);
 	void playSoundEffect(uint8 track, uint8 volume = 0xff);
 
 	void updateVolumeSettings();
diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp
index 6c88312..3c2c931 100644
--- a/engines/kyra/sound_lol.cpp
+++ b/engines/kyra/sound_lol.cpp
@@ -165,9 +165,8 @@ void LoLEngine::snd_playSoundEffect(int track, int volume) {
 		return;
 
 	volume &= 0xff;
-	// Priority setting (used for acquiring one of the 4 pcm channels) currently not implemented.
-	// int16 vprIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2 + 1]);
-	// uint16 priority = (vprIndex > 0) ? (vprIndex * volume) >> 8 : -vprIndex;
+	int16 prIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2 + 1]);
+	uint16 priority = (prIndex > 0) ? (prIndex * volume) >> 8 : -prIndex;
 
 	static const uint8 volTable1[] = { 223, 159, 95, 47, 15, 0 };
 	static const uint8 volTable2[] = { 255, 191, 127, 63, 30, 0 };
@@ -189,7 +188,7 @@ void LoLEngine::snd_playSoundEffect(int track, int volume) {
 
 	if (hasVocFile) {
 		if (_sound->isVoicePresent(_ingameSoundList[vocIndex]))
-			_sound->voicePlay(_ingameSoundList[vocIndex], 0, volume, true);
+			_sound->voicePlay(_ingameSoundList[vocIndex], 0, volume, priority, true);
 	} else if (_flags.platform == Common::kPlatformPC) {
 		if (_sound->getSfxType() == Sound::kMidiMT32)
 			track = (track < _ingameMT32SoundIndexSize) ? (_ingameMT32SoundIndex[track] - 1) : -1;
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 4b25db3..01624d5 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -569,15 +569,24 @@ void SoundTownsPC98_v2::beginFadeOut() {
 	haltTrack();
 }
 
-int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle, uint8, bool) {
+int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, uint8 priority, bool) {
 	static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 };
 	static const char patternHOF[] = "%s.PCM";
 	static const char patternLOL[] = "%s.VOC";
 
 	int h = 0;
 	if (_currentSFX) {
-		while (h < kNumChannelHandles && _mixer->isSoundHandleActive(_soundChannels[h]))
+		while (h < kNumChannelHandles && _mixer->isSoundHandleActive(_soundChannels[h].handle))
 			h++;
+
+		if (h >= kNumChannelHandles) {
+			h = 0;
+			while (h < kNumChannelHandles && _soundChannels[h].priority > priority)
+				++h;
+			if (h < kNumChannelHandles)
+				voiceStop(&_soundChannels[h].handle);
+		}
+
 		if (h >= kNumChannelHandles)
 			return 0;
 	}
@@ -630,9 +639,10 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle,
 	}
 
 	_currentSFX = Audio::makeRawStream(sfx, outsize, sfxRate * 10, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN);
-	_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundChannels[h], _currentSFX);
+	_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundChannels[h].handle, _currentSFX, -1, volume);
+	_soundChannels[h].priority = priority;
 	if (handle)
-		*handle = _soundChannels[h];
+		*handle = _soundChannels[h].handle;
 
 	delete[] data;
 	return 1;


Commit: 9840744acc6e43135ef5e28d041b1d55dd86804b
    https://github.com/scummvm/scummvm/commit/9840744acc6e43135ef5e28d041b1d55dd86804b
Author: athrxx (athrxx at scummvm.org)
Date: 2012-11-11T10:14:29-08:00

Commit Message:
KYRA: move HOF sequence player into its own class

(also cleaning up and fixing things while doing that)

Changed paths:
    engines/kyra/kyra_hof.cpp
    engines/kyra/kyra_hof.h
    engines/kyra/kyra_lok.h
    engines/kyra/kyra_v1.cpp
    engines/kyra/kyra_v1.h
    engines/kyra/lol.cpp
    engines/kyra/lol.h
    engines/kyra/resource.h
    engines/kyra/scene_lol.cpp
    engines/kyra/screen_hof.cpp
    engines/kyra/screen_hof.h
    engines/kyra/screen_lol.cpp
    engines/kyra/screen_lol.h
    engines/kyra/screen_v2.cpp
    engines/kyra/screen_v2.h
    engines/kyra/sequences_hof.cpp
    engines/kyra/sequences_lol.cpp
    engines/kyra/staticres.cpp



diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 7fbecb7..885e3d5 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -52,13 +52,6 @@ KyraEngine_HoF::KyraEngine_HoF(OSystem *system, const GameFlags &flags) : KyraEn
 	_screen = 0;
 	_text = 0;
 
-	_seqProcessedString = 0;
-	_activeWSA = 0;
-	_activeText = 0;
-	_seqWsa = 0;
-	_sequences = 0;
-	_sequenceSoundList = 0;
-
 	_gamePlayBuffer = 0;
 	_cCodeBuffer = _optionsBuffer = _chapterBuffer = 0;
 
@@ -89,7 +82,6 @@ KyraEngine_HoF::KyraEngine_HoF(OSystem *system, const GameFlags &flags) : KyraEn
 
 	memset(&_invWsa, 0, sizeof(_invWsa));
 	_itemAnimDefinition = 0;
-	_demoAnimData = 0;
 	_nextAnimItem = 0;
 
 	for (int i = 0; i < 15; i++)
@@ -136,7 +128,6 @@ KyraEngine_HoF::KyraEngine_HoF(OSystem *system, const GameFlags &flags) : KyraEn
 	memset(_cauldronStateTables, 0, sizeof(_cauldronStateTables));
 
 	_menuDirectlyToLoad = false;
-	_menu = 0;
 	_chatIsNote = false;
 	memset(&_npcScriptData, 0, sizeof(_npcScriptData));
 
@@ -148,7 +139,6 @@ KyraEngine_HoF::KyraEngine_HoF(OSystem *system, const GameFlags &flags) : KyraEn
 
 KyraEngine_HoF::~KyraEngine_HoF() {
 	cleanup();
-	seq_uninit();
 
 	delete _screen;
 	delete _text;
@@ -157,15 +147,6 @@ KyraEngine_HoF::~KyraEngine_HoF() {
 	_text = 0;
 	delete _invWsa.wsa;
 
-	if (_sequenceSoundList) {
-		for (int i = 0; i < _sequenceSoundListSize; i++) {
-			if (_sequenceSoundList[i])
-				delete[] _sequenceSoundList[i];
-		}
-		delete[] _sequenceSoundList;
-		_sequenceSoundList = NULL;
-	}
-
 	delete[] _dlgBuffer;
 	for (int i = 0; i < 19; i++)
 		delete[] _conversationState[i];
@@ -179,41 +160,13 @@ KyraEngine_HoF::~KyraEngine_HoF() {
 void KyraEngine_HoF::pauseEngineIntern(bool pause) {
 	KyraEngine_v2::pauseEngineIntern(pause);
 
+	seq_pausePlayer(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;
-
-		if (_activeText) {
-			for (int x = 0; x < 10; x++) {
-				if (_activeText[x].duration != -1)
-					_activeText[x].startTime += pausedTime;
-			}
-		}
-
-		if (_activeWSA) {
-			for (int x = 0; x < 8; x++) {
-				if (_activeWSA[x].flags != -1)
-					_activeWSA[x].nextFrame += pausedTime;
-			}
-		}
-
 		_nextIdleAnim += pausedTime;
-
-		for (int x = 0; x < _itemAnimDefinitionSize; x++)
-			_activeItemAnim[x].nextFrameTime += pausedTime;
-
 		_tim->refreshTimersAfterPause(pausedTime);
 	}
 }
@@ -254,13 +207,6 @@ Common::Error KyraEngine_HoF::init() {
 	if (!_sound->init())
 		error("Couldn't init sound");
 
-	_abortIntroFlag = false;
-
-	if (_sequenceStrings) {
-		for (int i = 0; i < MIN(33, _sequenceStringsSize); i++)
-			_sequenceStringsDuration[i] = (int) strlen(_sequenceStrings[i]) * 8;
-	}
-
 	// No mouse display in demo
 	if (_flags.isDemo && !_flags.isTalkie)
 		return Common::kNoError;
@@ -279,28 +225,24 @@ Common::Error KyraEngine_HoF::init() {
 }
 
 Common::Error KyraEngine_HoF::go() {
+	int menuChoice = 0;
+
 	if (_gameToLoad == -1) {
 		if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
 			seq_showStarcraftLogo();
 
 		if (_flags.isDemo && !_flags.isTalkie) {
-#ifdef ENABLE_LOL
-			if (_flags.gameID == GI_LOL)
-				seq_playSequences(kSequenceLoLDemoScene1, kSequenceLoLDemoScene6);
-			else
-#endif // ENABLE_LOL
-				seq_playSequences(kSequenceDemoVirgin, kSequenceDemoFisher);
-			_menuChoice = 4;
+			menuChoice = seq_playDemo();
 		} else {
-			seq_playSequences(kSequenceVirgin, kSequenceZanfaun);
+			menuChoice = seq_playIntro();
 		}
 	} else {
-		_menuChoice = 1;
+		menuChoice = 1;
 	}
 
 	_res->unloadAllPakFiles();
 
-	if (_menuChoice != 4) {
+	if (menuChoice != 4) {
 		// load just the pak files needed for ingame
 		_staticres->loadStaticResourceFile();
 
@@ -317,17 +259,17 @@ Common::Error KyraEngine_HoF::go() {
 		}
 	}
 
-	_menuDirectlyToLoad = (_menuChoice == 3) ? true : false;
+	_menuDirectlyToLoad = (menuChoice == 3) ? true : false;
 	_menuDirectlyToLoad &= saveFileLoadable(0);
 
-	if (_menuChoice & 1) {
+	if (menuChoice & 1) {
 		startup();
 		if (!shouldQuit())
 			runLoop();
 		cleanup();
 
 		if (_showOutro)
-			seq_playSequences(kSequenceFunters, kSequenceFrash);
+			seq_playOutro();
 	}
 
 	return Common::kNoError;
diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h
index 182854c..3ee6446 100644
--- a/engines/kyra/kyra_hof.h
+++ b/engines/kyra/kyra_hof.h
@@ -35,158 +35,13 @@
 
 namespace Kyra {
 
-enum Sequences {
-	kSequenceVirgin = 0,
-	kSequenceWestwood,
-	kSequenceTitle,
-	kSequenceOverview,
-	kSequenceLibrary,
-	kSequenceHand,
-	kSequencePoint,
-	kSequenceZanfaun,
-
-	kSequenceFunters,
-	kSequenceFerb,
-	kSequenceFish,
-	kSequenceFheep,
-	kSequenceFarmer,
-	kSequenceFuards,
-	kSequenceFirates,
-	kSequenceFrash,
-
-	kSequenceArraySize
-};
-
-enum NestedSequences {
-	kSequenceFiggle = 0,
-	kSequenceOver1,
-	kSequenceOver2,
-	kSequenceForest,
-	kSequenceDragon,
-	kSequenceDarm,
-	kSequenceLibrary2,
-	kSequenceLibrary3,
-	kSequenceMarco,
-	kSequenceHand1a,
-	kSequenceHand1b,
-	kSequenceHand1c,
-	kSequenceHand2,
-	kSequenceHand3,
-	kSequenceHand4
-};
-
-enum SequencesDemo {
-	kSequenceDemoVirgin = 0,
-	kSequenceDemoWestwood,
-	kSequenceDemoTitle,
-	kSequenceDemoHill,
-	kSequenceDemoOuthome,
-	kSequenceDemoWharf,
-	kSequenceDemoDinob,
-	kSequenceDemoFisher
-};
-
-enum NestedSequencesDemo {
-	kSequenceDemoWharf2 = 0,
-	kSequenceDemoDinob2,
-	kSequenceDemoWater,
-	kSequenceDemoBail,
-	kSequenceDemoDig
-};
-
-#ifdef ENABLE_LOL
-enum SequencesLoLDemo {
-	kSequenceLoLDemoScene1 = 0,
-	kSequenceLoLDemoText1,
-	kSequenceLoLDemoScene2,
-	kSequenceLoLDemoText2,
-	kSequenceLoLDemoScene3,
-	kSequenceLoLDemoText3,
-	kSequenceLoLDemoScene4,
-	kSequenceLoLDemoText4,
-	kSequenceLoLDemoScene5,
-	kSequenceLoLDemoText5,
-	kSequenceLoLDemoScene6
-};
-#endif // ENABLE_LOL
-
-class WSAMovie_v2;
-class KyraEngine_HoF;
+//class WSAMovie_v2;
+//class KyraEngine_HoF;
 class TextDisplayer_HoF;
+class SeqPlayer_HOF;
 
 struct TIM;
 
-typedef int (KyraEngine_HoF::*SeqProc)(WSAMovie_v2 *, int, int, int);
-
-struct ActiveWSA {
-	SeqProc callback;
-	WSAMovie_v2 *movie;
-	const FrameControl *control;
-	int16 flags;
-	uint16 startFrame;
-	uint16 endFrame;
-	uint16 frameDelay;
-	uint32 nextFrame;
-	uint16 currentFrame;
-	uint16 lastFrame;
-	uint16 x;
-	uint16 y;
-	uint16 startupCommand;
-	uint16 finalCommand;
-};
-
-struct ActiveText {
-	uint16 strIndex;
-	uint16 x;
-	uint16 y;
-	uint16 width;
-	int32 duration;
-	uint32 startTime;
-	int16 textcolor;
-};
-
-struct Sequence {
-	const char *wsaFile;
-	const char *cpsFile;
-	uint16 flags;
-	uint8 startupCommand;
-	uint8 finalCommand;
-	int16 stringIndex1;
-	int16 stringIndex2;
-	uint16 startFrame;
-	uint16 numFrames;
-	uint16 frameDelay;
-	uint16 xPos;
-	uint16 yPos;
-	uint16 duration;
-};
-
-struct NestedSequence {
-	const char *wsaFile;
-	const FrameControl *wsaControl;
-	uint16 flags;
-	uint16 startframe;
-	uint16 endFrame;
-	uint16 frameDelay;
-	uint16 x;
-	uint16 y;
-	uint16 startupCommand;
-	uint16 finalCommand;
-};
-
-struct HofSeqData {
-	const Sequence *seq;
-	int numSeq;
-	const NestedSequence *seqn;
-	int numSeqn;
-};
-
-struct ItemAnimData_v1 {
-	int16 itemIndex;
-	uint16 y;
-	const uint16 *frames;
-};
-
 class KyraEngine_HoF : public KyraEngine_v2 {
 friend class Debugger_HoF;
 friend class TextDisplayer_HoF;
@@ -202,98 +57,19 @@ public:
 	GUI *gui() const { return _gui; }
 	virtual TextDisplayer *text() { return _text; }
 	int language() const { return _lang; }
+	const AudioDataStruct *soundData(int index) { return &_soundData[index]; }
+
 protected:
 	static const EngineDesc _hofEngineDesc;
 
 	// intro/outro
-	void seq_playSequences(int startSeq, int endSeq = -1);
-
-	int seq_introWestwood(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introTitle(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introLibrary(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introHand(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introPoint(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introZanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-
-	int seq_introOver1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introOver2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introForest(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introDragon(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introDarm(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introLibrary2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introMarco(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introHand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introHand1b(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introHand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introHand2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_introHand3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-
-	int seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_finaleFrash(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-
-	int seq_finaleFiggle(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-
-	int seq_demoVirgin(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoWestwood(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoTitle(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoHill(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoOuthome(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoWharf(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoDinob(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoFisher(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-
-	int seq_demoWharf2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoDinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoWater(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoBail(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_demoDig(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-
-#ifdef ENABLE_LOL
-	int seq_lolDemoScene1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_lolDemoScene2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_lolDemoScene3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_lolDemoScene4(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_lolDemoScene5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_lolDemoText5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-	int seq_lolDemoScene6(WSAMovie_v2 *wsaObj, int x, int y, int frm);
-#endif // ENABLE_LOL
-
-	void seq_sequenceCommand(int command);
-	void seq_loadNestedSequence(int wsaNum, int seqNum);
-	void seq_nestedSequenceFrame(int command, int wsaNum);
-	void seq_animatedSubFrame(int srcPage, int dstPage, int delaytime,
-	    int steps, int x, int y, int w, int h, int openClose, int directionFlags);
-	bool seq_processNextSubFrame(int wsaNum);
-	void seq_resetActiveWSA(int wsaNum);
-	void seq_unloadWSA(int wsaNum);
-	void seq_processWSAs();
-	void seq_cmpFadeFrame(const char *cmpFile);
-	void seq_playTalkText(uint8 chatNum);
-	void seq_resetAllTextEntries();
-	uint32 seq_activeTextsTimeLeft();
-	void seq_waitForTextsTimeout();
-	int seq_setTextEntry(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width);
-	void seq_processText();
-	char *seq_preprocessString(const char *str, int width);
-	void seq_printCreditsString(uint16 strIndex, int x, int y, const uint8 *colorMap, uint8 textcolor);
-	void seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, int textColor, int x, int y, int width,
-	    WSAMovie_v2 * wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos);
-	void seq_finaleActorScreen();
-	void seq_displayScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed, int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData = 0, const char *const *specialData = 0);
-	void seq_scrollPage(int bottom, int top);
 	void seq_showStarcraftLogo();
 
-	MainMenu *_menu;
+	int seq_playIntro();
+	int seq_playOutro();
+	int seq_playDemo();
 
-	void seq_init();
-	void seq_uninit();
+	void seq_pausePlayer(bool toggle);
 
 	Common::Error init();
 	Common::Error go();
@@ -312,6 +88,7 @@ protected:
 	static const int _pcSpkSfxMapSize;
 
 	AudioDataStruct _soundData[3];
+
 protected:
 	// game initialization
 	void startup();
@@ -841,11 +618,11 @@ protected:
 	bool _chatAltFlag;
 
 	// sequence player
-	ActiveWSA *_activeWSA;
+/*	ActiveWSA *_activeWSA;
 	ActiveText *_activeText;
-
-	const char * const *_sequencePakList;
-	int _sequencePakListSize;
+	*/
+	/*const char * const *_sequencePakList;
+	int _sequencePakListSize;*/
 	const char * const *_ingamePakList;
 	int _ingamePakListSize;
 
@@ -861,34 +638,33 @@ protected:
 	int _cdaTrackTableIngameSize;
 	const uint8 *_cdaTrackTableFinale;
 	int _cdaTrackTableFinaleSize;
-	const char * const *_sequenceSoundList;
-	int _sequenceSoundListSize;
 	const char * const *_ingameSoundList;
 	int _ingameSoundListSize;
 	const uint16 *_ingameSoundIndex;
 	int _ingameSoundIndexSize;
-	const char * const *_sequenceStrings;
-	int _sequenceStringsSize;
 	const uint16 *_ingameTalkObjIndex;
 	int _ingameTalkObjIndexSize;
 	const char * const *_ingameTimJpStr;
 	int _ingameTimJpStrSize;
-	const HofSeqData *_sequences;
+
 	const ItemAnimDefinition *_itemAnimDefinition;
 	int _itemAnimDefinitionSize;
+
+	/*const HofSeqData *_sequences;
+
 	const ItemAnimData_v1 *_demoAnimData;
 	int _demoAnimSize;
 
-	int _sequenceStringsDuration[33];
+	int _sequenceStringsDuration[33];*/
 
-	static const uint8 _seqTextColorPresets[];
+/*	static const uint8 _seqTextColorPresets[];
 	char *_seqProcessedString;
 	WSAMovie_v2 *_seqWsa;
 
 	bool _abortIntroFlag;
-	int _menuChoice;
+	int _menuChoice;*/
 
-	uint32 _seqFrameDelay;
+	/*uint32 _seqFrameDelay;
 	uint32 _seqStartTime;
 	uint32 _seqSubFrameStartTime;
 	uint32 _seqEndTime;
@@ -902,10 +678,7 @@ protected:
 	bool _seqSpecialFlag;
 	bool _seqSubframePlaying;
 	uint8 _seqTextColor[2];
-	uint8 _seqTextColorMap[16];
-
-	const SeqProc *_callbackS;
-	const SeqProc *_callbackN;
+	uint8 _seqTextColorMap[16];*/
 
 	static const uint8 _rainbowRoomData[];
 
diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h
index e5fb3cd..71177f5 100644
--- a/engines/kyra/kyra_lok.h
+++ b/engines/kyra/kyra_lok.h
@@ -134,6 +134,8 @@ public:
 	const uint8 * const *palTable1() { return &_specialPalettes[0]; }
 	const uint8 * const *palTable2() { return &_specialPalettes[29]; }
 
+	const AudioDataStruct *soundData(int index) { return &_soundData[index]; }
+
 protected:
 	virtual Common::Error go();
 	virtual Common::Error init();
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index 2672618..f6fc4c3 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -172,19 +172,6 @@ Common::Error KyraEngine_v1::init() {
 	assert(_res);
 	_res->reset();
 
-	if (_flags.isDemo) {
-		// HACK: check whether this is the HOF demo or the LOL demo.
-		// The LOL demo needs to be detected and run as KyraEngine_HoF,
-		// but the static resource loader and the sequence player will
-		// need correct IDs.
-		if (_res->exists("scene1.cps"))
-#ifdef ENABLE_LOL
-			_flags.gameID = GI_LOL;
-#else
-			error("Lands of Lore demo is not supported in this build");
-#endif // !ENABLE_LOL
-	}
-
 	_staticres = new StaticResource(this);
 	assert(_staticres);
 	if (!_staticres->init())
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index 0033969..c83f0a6 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -242,6 +242,8 @@ public:
 	virtual bool snd_voiceIsPlaying();
 	virtual void snd_stopVoice();
 
+	virtual const AudioDataStruct *soundData(int index) { return 0; }
+
 	// delay functionallity
 	virtual void delayUntil(uint32 timestamp, bool updateGameTimers = false, bool update = false, bool isMainLoop = false);
 	virtual void delay(uint32 millis, bool update = false, bool isMainLoop = false);
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index d3028c5..ed7fe52 100644
--- a/engines/kyra/lol.cpp
+++ b/engines/kyra/lol.cpp
@@ -499,6 +499,11 @@ void LoLEngine::initKeymap() {
 #endif
 }
 
+void LoLEngine::pauseEngineIntern(bool pause) {
+	KyraEngine_v1::pauseEngineIntern(pause);
+	pauseDemoPlayer(pause);
+}
+
 Common::Error LoLEngine::go() {
 	int action = -1;
 
@@ -2361,7 +2366,7 @@ int LoLEngine::processMagicIce(int charNum, int spellLevel) {
 
 	playSpellAnimation(0, 0, 0, 2, 0, 0, 0, s.getData(), tpal.getData(), 40, false);
 
-	_screen->fadePaletteStep(s.getData(), tpal.getData(), _system->getMillis(), _tickLength);
+	_screen->timedPaletteFadeStep(s.getData(), tpal.getData(), _system->getMillis(), _tickLength);
 	if (mov->opened()) {
 		int r = true;
 		if (spellLevel > 2) {
@@ -2430,7 +2435,7 @@ int LoLEngine::processMagicIce(int charNum, int spellLevel) {
 
 	playSpellAnimation(0, 0, 0, 2, 0, 0, 0, tpal.getData(), swampCol.getData(), 40, 0);
 
-	_screen->fadePaletteStep(tpal.getData(), swampCol.getData(), _system->getMillis(), _tickLength);
+	_screen->timedPaletteFadeStep(tpal.getData(), swampCol.getData(), _system->getMillis(), _tickLength);
 
 	if (breakWall)
 		breakIceWall(tpal.getData(), swampCol.getData());
@@ -2886,7 +2891,7 @@ int LoLEngine::processMagicVaelansCube() {
 	uint32 endTime = _system->getMillis() + 70 * _tickLength;
 
 	while (_system->getMillis() < endTime) {
-		_screen->fadePaletteStep(tmpPal1, tmpPal2, _system->getMillis() - ctime, 70 * _tickLength);
+		_screen->timedPaletteFadeStep(tmpPal1, tmpPal2, _system->getMillis() - ctime, 70 * _tickLength);
 		updateInput();
 	}
 
@@ -2915,7 +2920,7 @@ int LoLEngine::processMagicVaelansCube() {
 	endTime = _system->getMillis() + 70 * _tickLength;
 
 	while (_system->getMillis() < endTime) {
-		_screen->fadePaletteStep(tmpPal2, tmpPal1, _system->getMillis() - ctime, 70 * _tickLength);
+		_screen->timedPaletteFadeStep(tmpPal2, tmpPal1, _system->getMillis() - ctime, 70 * _tickLength);
 		updateInput();
 	}
 
@@ -3244,7 +3249,7 @@ void LoLEngine::playSpellAnimation(WSAMovie_v2 *mov, int firstFrame, int lastFra
 				continue;
 			}
 
-			if (!_screen->fadePaletteStep(pal1, pal2, _system->getMillis() - startTime, _tickLength * fadeDelay) && !mov)
+			if (!_screen->timedPaletteFadeStep(pal1, pal2, _system->getMillis() - startTime, _tickLength * fadeDelay) && !mov)
 				return;
 
 			if (del) {
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
index dcd1380..06f9e32 100644
--- a/engines/kyra/lol.h
+++ b/engines/kyra/lol.h
@@ -270,9 +270,13 @@ public:
 
 	virtual void initKeymap();
 
+	void pauseEngineIntern(bool pause);
+
 	Screen *screen();
 	GUI *gui() const;
 
+	const AudioDataStruct *soundData(int index) { return &_soundData[index]; }
+
 private:
 	Screen_LoL *_screen;
 	GUI_LoL *_gui;
@@ -400,6 +404,10 @@ private:
 	static const int _outroMonsterScaleTableX[];
 	static const int _outroMonsterScaleTableY[];
 
+	// Non-interactive demo
+	int playDemo();
+	void pauseDemoPlayer(bool toggle);
+
 	// timers
 	void setupTimers();
 
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h
index f2bc4e8..74ac1b6 100644
--- a/engines/kyra/resource.h
+++ b/engines/kyra/resource.h
@@ -742,6 +742,8 @@ enum KyraResources {
 struct Shape;
 struct Room;
 struct AmigaSfxTable;
+struct HoFSeqData;
+struct HoFSeqItemAnimData;
 
 class StaticResource {
 public:
@@ -760,8 +762,8 @@ public:
 	const Shape *loadShapeTable(int id, int &entries);
 	const AmigaSfxTable *loadAmigaSfxTable(int id, int &entries);
 	const Room *loadRoomTable(int id, int &entries);
-	const HofSeqData *loadHofSequenceData(int id, int &entries);
-	const ItemAnimData_v1 *loadShapeAnimData_v1(int id, int &entries);
+	const HoFSeqData *loadHoFSequenceData(int id, int &entries);
+	const HoFSeqItemAnimData *loadHoFSeqItemAnimData(int id, int &entries);
 	const ItemAnimDefinition *loadItemAnimDefinition(int id, int &entries);
 #if defined(ENABLE_EOB) || defined(ENABLE_LOL)
 	const uint16 *loadRawDataBe16(int id, int &entries);
@@ -803,8 +805,8 @@ private:
 	bool loadShapeTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
 	bool loadAmigaSfxTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
 	bool loadRoomTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
-	bool loadHofSequenceData(Common::SeekableReadStream &stream, void *&ptr, int &size);
-	bool loadShapeAnimData_v1(Common::SeekableReadStream &stream, void *&ptr, int &size);
+	bool loadHoFSequenceData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+	bool loadHoFSeqItemAnimData(Common::SeekableReadStream &stream, void *&ptr, int &size);
 	bool loadItemAnimDefinition(Common::SeekableReadStream &stream, void *&ptr, int &size);
 #if defined(ENABLE_EOB) || defined(ENABLE_LOL)
 	bool loadRawDataBe16(Common::SeekableReadStream &stream, void *&ptr, int &size);
@@ -829,8 +831,8 @@ private:
 	void freeShapeTable(void *&ptr, int &size);
 	void freeAmigaSfxTable(void *&ptr, int &size);
 	void freeRoomTable(void *&ptr, int &size);
-	void freeHofSequenceData(void *&ptr, int &size);
-	void freeHofShapeAnimDataV1(void *&ptr, int &size);
+	void freeHoFSequenceData(void *&ptr, int &size);
+	void freeHoFSeqItemAnimData(void *&ptr, int &size);
 	void freeItemAnimDefinition(void *&ptr, int &size);
 #if defined(ENABLE_EOB) || defined(ENABLE_LOL)
 	void freeRawDataBe16(void *&ptr, int &size);
@@ -857,7 +859,7 @@ private:
 		kAmigaSfxTable = 4,
 
 		k2SeqData = 5,
-		k2ShpAnimDataV1 = 6,
+		k2SeqItemAnimData = 6,
 		k2ItemAnimDefinition = 7,
 
 		kLoLCharData = 8,
diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp
index 628654f..d916348 100644
--- a/engines/kyra/scene_lol.cpp
+++ b/engines/kyra/scene_lol.cpp
@@ -1183,11 +1183,11 @@ void LoLEngine::processGasExplosion(int soundId) {
 			p2[i * 3] = 0x3f;
 
 		uint32 ctime = _system->getMillis();
-		while (_screen->fadePaletteStep(_screen->getPalette(0).getData(), p2, _system->getMillis() - ctime, 10))
+		while (_screen->timedPaletteFadeStep(_screen->getPalette(0).getData(), p2, _system->getMillis() - ctime, 10))
 			updateInput();
 
 		ctime = _system->getMillis();
-		while (_screen->fadePaletteStep(p2, _screen->getPalette(0).getData(), _system->getMillis() - ctime, 50))
+		while (_screen->timedPaletteFadeStep(p2, _screen->getPalette(0).getData(), _system->getMillis() - ctime, 50))
 			updateInput();
 	}
 
diff --git a/engines/kyra/screen_hof.cpp b/engines/kyra/screen_hof.cpp
index ac6ee5e..7fdbdeb 100644
--- a/engines/kyra/screen_hof.cpp
+++ b/engines/kyra/screen_hof.cpp
@@ -93,12 +93,6 @@ void Screen_HoF::cmpFadeFrameStep(int srcPage, int srcW, int srcH, int srcX, int
 	}
 }
 
-void Screen_HoF::copyPageMemory(int srcPage, int srcPos, int dstPage, int dstPos, int numBytes) {
-	const uint8 *src = getPagePtr(srcPage) + srcPos;
-	uint8 *dst = getPagePtr(dstPage) + dstPos;
-	memcpy(dst, src, numBytes);
-}
-
 void Screen_HoF::copyRegionEx(int srcPage, int srcW, int srcH, int dstPage, int dstX, int dstY, int dstW, int dstH, const ScreenDim *dim, bool flag) {
 	int x0 = dim->sx << 3;
 	int y0 = dim->sy;
diff --git a/engines/kyra/screen_hof.h b/engines/kyra/screen_hof.h
index 51c6a00..07fcd96 100644
--- a/engines/kyra/screen_hof.h
+++ b/engines/kyra/screen_hof.h
@@ -37,7 +37,7 @@ public:
 	// sequence player
 	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);
 private:
 	KyraEngine_HoF *_vm;
diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp
index 714a9d8..4e64f51 100644
--- a/engines/kyra/screen_lol.cpp
+++ b/engines/kyra/screen_lol.cpp
@@ -808,34 +808,6 @@ bool Screen_LoL::fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedT
 	return res;
 }
 
-bool Screen_LoL::fadePaletteStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 targetTime) {
-	Palette &p1 = getPalette(1);
-
-	bool res = false;
-	for (int i = 0; i < p1.getNumColors() * 3; i++) {
-		uint8 out = 0;
-
-		if (elapsedTime < targetTime) {
-			int32 d = ((pal2[i] & 0x3f) - (pal1[i] & 0x3f));
-			if (d)
-				res = true;
-
-			int32 val = ((((d << 8) / (int32)targetTime) * (int32)elapsedTime) >> 8);
-			out = ((pal1[i] & 0x3f) + (int8)val);
-		} else {
-			out = p1[i] = (pal2[i] & 0x3f);
-			res = false;
-		}
-
-		(*_internFadePalette)[i] = out;
-	}
-
-	setScreenPalette(*_internFadePalette);
-	updateScreen();
-
-	return res;
-}
-
 Palette **Screen_LoL::generateFadeTable(Palette **dst, Palette *src1, Palette *src2, int numTabs) {
 	int len = _use16ColorMode ? 48 : 768;
 	if (!src1)
diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h
index 0949670..8ceb843 100644
--- a/engines/kyra/screen_lol.h
+++ b/engines/kyra/screen_lol.h
@@ -65,7 +65,6 @@ public:
 	void loadSpecialColors(Palette &dst);
 	void copyColor(int dstColorIndex, int srcColorIndex);
 	bool fadeColor(int dstColorIndex, int srcColorIndex, uint32 elapsedTicks, uint32 totalTicks);
-	bool fadePaletteStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 targetTime);
 	Palette **generateFadeTable(Palette **dst, Palette *src1, Palette *src2, int numTabs);
 
 	void generateGrayOverlay(const Palette &Pal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColors);
diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp
index 7d4b064..1131460 100644
--- a/engines/kyra/screen_v2.cpp
+++ b/engines/kyra/screen_v2.cpp
@@ -162,6 +162,34 @@ void Screen_v2::getFadeParams(const Palette &pal, int delay, int &delayInc, int
 	}
 }
 
+bool Screen_v2::timedPaletteFadeStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 totalTime) {
+	Palette &p1 = getPalette(1);
+
+	bool res = false;
+	for (int i = 0; i < p1.getNumColors() * 3; i++) {
+		uint8 out = 0;
+
+		if (elapsedTime < totalTime) {
+			int32 d = ((pal2[i] & 0x3f) - (pal1[i] & 0x3f));
+			if (d)
+				res = true;
+
+			int32 val = ((((d << 8) / (int32)totalTime) * (int32)elapsedTime) >> 8);
+			out = ((pal1[i] & 0x3f) + (int8)val);
+		} else {
+			out = p1[i] = (pal2[i] & 0x3f);
+			res = false;
+		}
+
+		(*_internFadePalette)[i] = out;
+	}
+
+	setScreenPalette(*_internFadePalette);
+	updateScreen();
+
+	return res;
+}
+
 const uint8 *Screen_v2::getPtrToShape(const uint8 *shpFile, int shape) {
 	uint16 shapes = READ_LE_UINT16(shpFile);
 
@@ -322,6 +350,12 @@ void Screen_v2::wsaFrameAnimationStep(int x1, int y1, int x2, int y2,
 		addDirtyRect(x2, y2, w2, h2);
 }
 
+void Screen_v2::copyPageMemory(int srcPage, int srcPos, int dstPage, int dstPos, int numBytes) {
+	const uint8 *src = getPagePtr(srcPage) + srcPos;
+	uint8 *dst = getPagePtr(dstPage) + dstPos;
+	memcpy(dst, src, numBytes);
+}
+
 bool Screen_v2::calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, int &x2, int &y2, int &w2) {
 	x2 = 0;
 	y2 = 0;
diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h
index f84c923..31c0b9f 100644
--- a/engines/kyra/screen_v2.h
+++ b/engines/kyra/screen_v2.h
@@ -43,6 +43,8 @@ public:
 
 	virtual void getFadeParams(const Palette &pal, int delay, int &delayInc, int &diff);
 
+	bool timedPaletteFadeStep(uint8 *pal1, uint8 *pal2, uint32 elapsedTime, uint32 totalTime);
+
 	// shape handling
 	uint8 *getPtrToShape(uint8 *shpFile, int shape);
 	const uint8 *getPtrToShape(const uint8 *shpFile, int shape);
@@ -66,6 +68,9 @@ public:
 
 	// special WSA handling
 	void wsaFrameAnimationStep(int x1, int y1, int x2, int y2, int w1, int h1, int w2, int h2, int srcPage, int dstPage, int dim);
+
+	// used in non-interactive HoF/LoL demos
+	void copyPageMemory(int srcPage, int srcPos, int dstPage, int dstPos, int numBytes);
 protected:
 	uint8 *_wsaFrameAnimBuffer;
 };
diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index f2abfb8..26e2fd7 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -21,2711 +21,3349 @@
  */
 
 #include "kyra/kyra_hof.h"
-#include "kyra/timer.h"
+#include "kyra/screen_hof.h"
+#include "kyra/screen_lol.h"
 #include "kyra/resource.h"
 #include "kyra/sound.h"
+#include "kyra/sequences_hof.h"
+#include "kyra/timer.h"
 
 #include "common/system.h"
 
 namespace Kyra {
 
-void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
-	seq_init();
+enum SequenceID {
+	kSequenceNoLooping = -1,
+	kSequenceVirgin = 0,
+	kSequenceWestwood,
+	kSequenceTitle,
+	kSequenceOverview,
+	kSequenceLibrary,
+	kSequenceHand,
+	kSequencePoint,
+	kSequenceZanfaun,
+
+	kSequenceFunters,
+	kSequenceFerb,
+	kSequenceFish,
+	kSequenceFheep,
+	kSequenceFarmer,
+	kSequenceFuards,
+	kSequenceFirates,
+	kSequenceFrash,
+
+	kSequenceHoFDemoVirgin,
+	kSequenceHoFDemoWestwood,
+	kSequenceHoFDemoTitle,
+	kSequenceHoFDemoHill,
+	kSequenceHoFDemoOuthome,
+	kSequenceHoFDemoWharf,
+	kSequenceHoFDemoDinob,
+	kSequenceHoFDemoFisher,
+
+// The following enums remain active even if LoL is disabled
+	kSequenceLoLDemoScene1,
+	kSequenceLoLDemoText1,
+	kSequenceLoLDemoScene2,
+	kSequenceLoLDemoText2,
+	kSequenceLoLDemoScene3,
+	kSequenceLoLDemoText3,
+	kSequenceLoLDemoScene4,
+	kSequenceLoLDemoText4,
+	kSequenceLoLDemoScene5,
+	kSequenceLoLDemoText5,
+	kSequenceLoLDemoScene6,
+
+	kSequenceArraySize
+};
+
+enum NestedSequenceID {
+	kNestedSequenceFiggle = 0,
+
+	kNestedSequenceOver1,
+	kNestedSequenceOver2,
+	kNestedSequenceForest,
+	kNestedSequenceDragon,
+	kNestedSequenceDarm,
+	kNestedSequenceLibrary2,
+	kNestedSequenceLibrary3,
+	kNestedSequenceMarco,
+	kNestedSequenceHand1a,
+	kNestedSequenceHand1b,
+	kNestedSequenceHand1c,
+	kNestedSequenceHand2,
+	kNestedSequenceHand3,
+	kNestedSequenceHand4,
+
+	kNestedSequenceHoFDemoWharf2,
+	kNestedSequenceHoFDemoDinob2,
+	kNestedSequenceHoFDemoWater,
+	kNestedSequenceHoFDemoBail,
+	kNestedSequenceHoFDemoDig,
+
+	kNestedSequenceArraySize
+};
+
+typedef int (SeqPlayer_HOF::*SeqProc)(WSAMovie_v2 *, int, int, int);
+
+struct SeqPlayerConfig {
+	SeqPlayerConfig(const HoFSeqData *data, const SeqProc *callbacks, const SeqProc *nestedCallbacks) : seq(data->seq), seqProc(callbacks), numSeq(data->numSeq), nestedSeq(data->nestedSeq), nestedSeqProc(nestedCallbacks), numNestedSeq(data->numNestedSeq) {}
+	const HoFSequence *seq;
+	const SeqProc *seqProc;
+	int numSeq;
+	const HoFNestedSequence *nestedSeq;
+	const SeqProc *nestedSeqProc;
+	int numNestedSeq;
+};
+
+class SeqPlayer_HOF {
+public:
+	SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system, bool startupSaveLoadable = false);
+	~SeqPlayer_HOF();
+
+	int play(SequenceID firstScene, SequenceID loopStartScene);
+	void pause(bool toggle);
+
+	static SeqPlayer_HOF *instance() { return _instance; }
+
+private:
+	// Init
+	void setupCallbacks();
+
+	// Playback loop
+	void runLoop();
+	void playScenes();
+
+	bool checkAbortPlayback();
+	bool checkPlaybackStatus();
+
+	bool _abortRequested;
+
+	uint32 _seqWsaChatTimeout;
+	uint32 _seqWsaChatFrameTimeout;
+
+	int _seqScrollTextCounter;
+	uint8 _seqTextColor[2];
+	uint8 _seqTextColorMap[16];
+
+	// Sequence transitions
+	void doTransition(int type);
+	void nestedFrameAnimTransition(int srcPage, int dstPage, int delaytime, int steps, int x, int y, int w, int h, int openClose, int directionFlags);
+	void nestedFrameFadeTransition(const char *cmpFile);
+
+	// Animations
+	void playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int numFrames, int frameRate, int x, int y, const SeqProc callback, Palette *fadePal1, Palette *fadePal2, int fadeRate, bool restoreScreen);
+
+	void startNestedAnimation(int animSlot, int sequenceID);
+	void closeNestedAnimation(int animSlot);
+	void unloadNestedAnimation(int animSlot);
+	void doNestedFrameTransition(int transitionType, int animSlot);
+	void updateAllNestedAnimations();	
+	bool updateNestedAnimation(int animSlot);
+
+	struct AnimSlot {
+		SeqProc callback;
+		WSAMovie_v2 *movie;
+		const FrameControl *control;
+		int16 flags;
+		uint16 startFrame;
+		uint16 endFrame;
+		uint16 frameDelay;
+		uint32 nextFrame;
+		uint16 currentFrame;
+		uint16 lastFrame;
+		uint16 x;
+		uint16 y;
+		uint16 fadeInTransitionType;
+		uint16 fadeOutTransitionType;
+	};
 
-	bool allowSkip = (_flags.isDemo && !_flags.isTalkie) || startSeq != kSequenceTitle;
+	AnimSlot _animSlots[8];
+
+	bool _updateAnimations;
+	uint32 _animDuration;
+	int _animCurrentFrame;
+	int _callbackCurrentFrame;
+
+	// Subtitles/Dialogue/Sound
+	void seq_playTalkText(uint8 chatNum);
+	void seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, int textColor, int x, int y, int width, WSAMovie_v2 * wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos);
+	void seq_printCreditsString(uint16 strIndex, int x, int y, const uint8 *colorMap, uint8 textcolor);
+	int seq_setTextEntry(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width);
+
+	void seq_processText();
+	char *seq_preprocessString(const char *str, int width);
+
+	void waitForSubTitlesTimeout();
+	uint32 ticksTillSubTitlesTimeout();
+	void seq_resetAllTextEntries();
+	void fadeOutMusic();
+
+	struct TextSlot {
+		uint16 strIndex;
+		uint16 x;
+		uint16 y;
+		uint16 width;
+		int32 duration;
+		uint32 startTime;
+		int16 textcolor;
+	};
 
-	if (endSeq == -1)
-		endSeq = startSeq;
+	TextSlot _textSlots[10];
 
-	assert(startSeq >= 0 && endSeq < kSequenceArraySize && startSeq <= endSeq);
+	char *_tempString;
 
-	_sound->setSoundList(&_soundData[(startSeq > kSequenceZanfaun) ? kMusicFinale : kMusicIntro]);
-	_sound->loadSoundFile(0);
+	const char * const *_sequenceStrings;
+	const char * const *_sequenceSoundList;
+	int _sequenceSoundListSize;
 
-	_screen->_charWidth = (_flags.gameID == GI_LOL) ? 0 : -2;
+	Audio::SoundHandle _speechHandle;
 
-	memset(_activeWSA, 0, sizeof(ActiveWSA) * 8);
-	for (int i = 0; i < 8; ++i)
-		_activeWSA[i].flags = -1;
+	int _textDuration[33];
+	static const uint8 _textColorPresets[];
 
-	memset(_activeText, 0, sizeof(ActiveText) * 10);
-	seq_resetAllTextEntries();
+	// HOF credits
+	void seq_finaleActorScreen();
+	void seq_displayScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed, int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData = 0, const char *const *specialData = 0);
 
-	_screen->hideMouse();
-	int oldPage = _screen->setCurPage(2);
+	bool _talkieFinaleExtraFlag;
 
-	for (int i = 0; i < 4; ++i)
-		_screen->getPalette(i).clear();
+	// HOF demo specific
+	void seq_scrollPage(int bottom, int top);
 
-	_screen->clearPage(10);
-	_screen->clearPage(12);
+	ActiveItemAnim _hofDemoActiveItemAnim[5];
+	uint32 _fisherAnimCurTime;
 
-	_seqSubframePlaying = false;
+	const HoFSeqItemAnimData *_hofDemoAnimData;
+	uint8 *_hofDemoShapeData;
+	uint8 *_hofDemoItemShapes[20];
 
-	_seqWsaCurrentFrame = 0;
-	_seqTextColor[0] = _seqTextColor[1] = 0;
-	_seqEndTime = 0;
-	_menuChoice = 0;
+	// Misc
+	void delayTicks(uint32 ticks);
+	void delayUntil(uint32 dest);
+	void setCountDown(uint32 ticks);
+	bool countDownRunning();
 
-	for (int seqNum = startSeq; seqNum <= endSeq && !((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice); seqNum++) {
-		_screen->clearPage(0);
-		_screen->clearPage(8);
-		_screen->copyPalette(1, 0);
-		_seqFrameCounter = 0;
-		_seqStartTime = _system->getMillis();
+	uint32 _countDownRemainder;
+	uint32 _countDownLastUpdate;
 
-		allowSkip = (_flags.isDemo && !_flags.isTalkie) || seqNum != kSequenceTitle;
+	enum SeqPlayerTargetInfo {
+		kHoF = 0,
+		kHoFDemo,
+		kLoLDemo
+	};
 
-		Sequence cseq = _sequences->seq[seqNum];
-		SeqProc cb = _callbackS[seqNum];
+	SeqPlayerTargetInfo _target;
+	int _firstScene, _loopStartScene, _curScene, _preventSkipBeforeScene, _lastScene;
+	bool _startupSaveLoadable, _isFinale, _preventLooping;
+
+	SeqPlayerConfig *_config;
+
+	MainMenu *_menu;
+	int _result;
+
+	bool _abortPlayback;
+
+	KyraEngine_v1 *_vm;
+	Screen_v2 *_screen;
+	Screen_HoF *_screenHoF;
+	OSystem *_system;
+
+	static SeqPlayer_HOF *_instance;
+
+private:
+	// Sequence specific callback functions
+	int cbHOF_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_title(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_library(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_hand(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_point(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+	int cbHOF_over1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_over2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_forest(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_dragon(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_darm(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_library2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_marco(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_hand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_hand1b(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_hand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_hand2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_hand3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+	int cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_ferb(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_fish(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_fheep(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_farmer(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_firates(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+	int cbHOF_figgle(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+	int cbHOFDEMO_virgin(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_title(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_hill(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_outhome(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_wharf(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_dinob(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_fisher(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+
+	int cbHOFDEMO_wharf2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_dinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_water(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_bail(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbHOFDEMO_dig(WSAMovie_v2 *wsaObj, int x, int y, int frm);
 
-		if (cseq.flags & 2) {
-			_screen->loadBitmap(cseq.cpsFile, 2, 2, &_screen->getPalette(0));
-			_screen->setScreenPalette(_screen->getPalette(0));
-		} else {
-			_screen->setCurPage(2);
-			_screen->clearPage(2);
-			_screen->loadPalette("goldfont.col", _screen->getPalette(0));
-		}
+#ifdef ENABLE_LOL
+	int cbLOLDEMO_scene1(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbLOLDEMO_scene2(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbLOLDEMO_scene3(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbLOLDEMO_scene4(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbLOLDEMO_scene5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbLOLDEMO_text5(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+	int cbLOLDEMO_scene6(WSAMovie_v2 *wsaObj, int x, int y, int frm);
+#endif // ENABLE_LOL
+};
+
+SeqPlayer_HOF *SeqPlayer_HOF::_instance = 0;
+
+SeqPlayer_HOF::SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *system, bool startupSaveLoadable) : _vm(vm), _screen(screen), _system(system), _startupSaveLoadable(startupSaveLoadable) {
+	// We use a static pointer for pauseEngine functionality. Since we don't
+	// ever need more than one SeqPlayer_HOF object at the same time we keep
+	// this simple and just add an assert to detect typos, regressions, etc.
+	assert(_instance == 0);
+
+	memset(_animSlots, 0, sizeof(_animSlots));
+	memset(_textSlots, 0, sizeof(_textSlots));
+	memset(_hofDemoActiveItemAnim, 0, sizeof(_hofDemoActiveItemAnim));
+
+	_screenHoF = _vm->game() == GI_KYRA2 ? (Screen_HoF*)screen : 0;
+	_config = 0;
+	_result = 0;
+	_sequenceSoundList = 0;
+	_hofDemoAnimData = 0;
+	_hofDemoShapeData = 0;
+	_isFinale = false;
+	_preventLooping = false;
+	_menu = 0;
+	_abortRequested = false;
 
-		if (cb && !(_flags.isDemo && !_flags.isTalkie))
-			(this->*cb)(0, 0, 0, -1);
+	_updateAnimations = false;
+	_animDuration = 0;
+	_animCurrentFrame = 0;
+	_callbackCurrentFrame = 0;
 
-		if (cseq.flags & 1) {
-			_seqWsa->close();
-			_seqWsa->open(cseq.wsaFile, 0, &_screen->getPalette(0));
-			_screen->setScreenPalette(_screen->getPalette(0));
-			_seqWsa->displayFrame(0, 2, cseq.xPos, cseq.yPos, 0, 0, 0);
-		}
+	_abortPlayback = false;
+	_curScene = 0;
+	_preventSkipBeforeScene = -1;
+	_lastScene = 0;
 
-		if (cseq.flags & 4) {
-			int cp = _screen->setCurPage(2);
-			Screen::FontId cf =	_screen->setFont(_flags.lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
-			if (cseq.stringIndex1 != -1) {
-				int sX = (320 - _screen->getTextWidth(_sequenceStrings[cseq.stringIndex1])) / 2;
-				_screen->printText(_sequenceStrings[cseq.stringIndex1], sX, 100 - _screen->getFontHeight(), 1, 0);
-			}
-			if (cseq.stringIndex2 != -1) {
-				int sX = (320 - _screen->getTextWidth(_sequenceStrings[cseq.stringIndex2])) / 2;
-				_screen->printText(_sequenceStrings[cseq.stringIndex2], sX, 100, 1, 0);
-			}
-			_screen->setFont(cf);
-			_screen->setCurPage(cp);
-		}
+	_fisherAnimCurTime = 0;
 
-		_screen->copyPage(2, 12);
-		_screen->copyPage(0, 2);
-		_screen->copyPage(2, 10);
-		_screen->copyPage(12, 2);
+	_tempString = new char[200];
 
-		seq_sequenceCommand(cseq.startupCommand);
+	_countDownRemainder = 0;
+	_countDownLastUpdate = 0;
 
-		if (!((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice)) {
-			_screen->copyPage(2, 0);
-			_screen->updateScreen();
-		}
+	int tempSize = 0;
+	_vm->resource()->unloadAllPakFiles();
+	_vm->resource()->loadPakFile(StaticResource::staticDataFilename());
+	const char *const *files = _vm->staticres()->loadStrings(k2SeqplayPakFiles, tempSize);
+	_vm->resource()->loadFileList(files, tempSize);
 
-		if (cseq.flags & 1) {
-			int x = cseq.xPos;
-			int y = cseq.yPos;
+	_sequenceStrings = _vm->staticres()->loadStrings(k2SeqplayStrings, tempSize);
+	uint8 multiplier = (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) ? 12 : 8;
+	for (int i = 0; i < MIN(33, tempSize); i++)
+		_textDuration[i] = (int) strlen(_sequenceStrings[i]) * multiplier;
+
+	if (_sequenceSoundList) {
+		for (int i = 0; i < _sequenceSoundListSize; i++) {
+			if (_sequenceSoundList[i])
+				delete[] _sequenceSoundList[i];
+		}
+		delete[] _sequenceSoundList;
+		_sequenceSoundList = 0;
+	}
 
-			_seqFrameDelay = cseq.frameDelay;
+	const char *const *seqSoundList = _vm->staticres()->loadStrings(k2SeqplaySfxFiles, _sequenceSoundListSize);
 
-			if (_seqWsa) {
-				if (x < 0) {
-					_seqWsa->setWidth(_seqWsa->width() + x);
-					x = 0;
-				}
+	// replace sequence talkie files with localized versions
+	const char *const *tlkfiles = _vm->staticres()->loadStrings(k2SeqplayTlkFiles, tempSize);
+	char **tmpSndLst = new char *[_sequenceSoundListSize];
 
-				if (y < 0) {
-					_seqWsa->setHeight(_seqWsa->height() + y);
-					y = 0;
-				}
+	for (int i = 0; i < _sequenceSoundListSize; i++) {
+		const int len = strlen(seqSoundList[i]);
 
-				if (cseq.xPos + _seqWsa->width() > 319)
-					_seqWsa->setWidth(320 - cseq.xPos);
+		tmpSndLst[i] = new char[len + 1];
+		tmpSndLst[i][0] = 0;
 
-				if (cseq.yPos + _seqWsa->height() > 199)
-					_seqWsa->setHeight(199 - cseq.yPos);
+		if (tlkfiles && len > 1) {
+			for (int ii = 0; ii < tempSize; ii++) {
+				if (strlen(tlkfiles[ii]) > 1 && !scumm_stricmp(&seqSoundList[i][1], &tlkfiles[ii][1]))
+					strcpy(tmpSndLst[i], tlkfiles[ii]);
 			}
-			uint8 dir = (cseq.startFrame > cseq.numFrames) ? 0 : 1;
-			_seqWsaCurrentFrame = cseq.startFrame;
+		}
 
-			bool loop = true;
-			while (loop && !((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice)) {
-				_seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength;
+		if (tmpSndLst[i][0] == 0)
+			strcpy(tmpSndLst[i], seqSoundList[i]);
+	}
 
-				if (_seqWsa || !cb)
-					_screen->copyPage(12, 2);
+	tlkfiles = seqSoundList = 0;
+	_vm->staticres()->unloadId(k2SeqplayTlkFiles);
+	_vm->staticres()->unloadId(k2SeqplaySfxFiles);
+	_sequenceSoundList = tmpSndLst;
 
-				if (cb) {
-					int f = _seqWsaCurrentFrame % _seqWsa->frames();
-					(this->*cb)(_seqWsa, cseq.xPos, cseq.yPos, f);
-				}
 
-				if (_seqWsa) {
-					int f = _seqWsaCurrentFrame % _seqWsa->frames();
-					_seqWsa->displayFrame(f, 2, cseq.xPos, cseq.yPos, 0, 0, 0);
-				}
+	if (_vm->gameFlags().platform == Common::kPlatformPC98)
+		_vm->sound()->loadSoundFile("SOUND.DAT");
 
-				_screen->copyPage(2, 12);
+	_screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
 
-				seq_processWSAs();
-				seq_processText();
+	if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
+		if (_vm->game() == GI_KYRA2) {
+			_hofDemoAnimData = _vm->staticres()->loadHoFSeqItemAnimData(k2SeqplayShapeAnimData, tempSize);
+			uint8 *shp = _vm->resource()->fileData("ICONS.SHP", 0);
+			uint32 outsize = READ_LE_UINT16(shp + 4);
+			_hofDemoShapeData = new uint8[outsize];
+			Screen::decodeFrame4(shp + 10, _hofDemoShapeData, outsize);
+			for (int i = 0; i < 20; i++)
+				_hofDemoItemShapes[i] = _screen->getPtrToShape(_hofDemoShapeData, i);
+			delete[] shp;
+		}
+	} else {
+		const MainMenu::StaticData data = {
+			{ _sequenceStrings[97], _sequenceStrings[96], _sequenceStrings[95], _sequenceStrings[98], 0 },
+			{ 0x01, 0x04, 0x0C, 0x04, 0x00, 0xd7, 0xd6 },
+			{ 0xd8, 0xda, 0xd9, 0xd8 },
+			(_vm->gameFlags().lang == Common::JA_JPN) ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT, 240
+		};
 
-				if ((_seqWsa || !cb) && !((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice)) {
-					_screen->copyPage(2, 0);
-					_screen->updateScreen();
-				}
+		_menu = new MainMenu(_vm);
+		_menu->init(data, MainMenu::Animation());
+	}
 
-				bool loop2 = true;
-				while (loop2 && !((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice)) {
-					if (_seqWsa) {
-						seq_processText();
-						if (!((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice)) {
-							_screen->copyPage(2, 0);
-							_screen->updateScreen();
-						}
+	_instance = this;
+}
 
-						uint32 now = _system->getMillis();
-						if (now >= _seqEndTime) {
-							loop2 = false;
-						} else {
-							uint32 tdiff = _seqEndTime - now;
-							uint32 dly = tdiff < _tickLength ? tdiff : _tickLength;
-							delay(dly);
-						}
-					} else {
-						loop = loop2 = false;
-					}
-				}
+SeqPlayer_HOF::~SeqPlayer_HOF() {
+	_instance = 0;
 
-				if (loop) {
-					if (dir == 1) {
-						if (++_seqWsaCurrentFrame >= cseq.numFrames)
-							loop = false;
-					} else {
-						if (--_seqWsaCurrentFrame < cseq.numFrames)
-							loop = false;
-					}
-				}
-			}
-			_seqWsa->close();
-		} else {
-			_seqFrameDelay = cseq.frameDelay;
-			_seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength;
-			while (!((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice)) {
-				_seqSubFrameStartTime = _system->getMillis();
-				seq_processWSAs();
-				if (cb)
-					(this->*cb)(0, 0, 0, 0);
+	if (_sequenceSoundList) {
+		for (int i = 0; i < _sequenceSoundListSize; i++) {
+			if (_sequenceSoundList[i])
+				delete[] _sequenceSoundList[i];
+		}
+		delete[] _sequenceSoundList;
+		_sequenceSoundList = NULL;
+	}
 
-				seq_processText();
+	delete[] _tempString;
+	delete[] _hofDemoShapeData;
+	delete _menu;
 
-				_screen->copyPage(2, 0);
-				_screen->updateScreen();
-				_screen->copyPage(12, 2);
+	_screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+}
 
-				uint32 now = _system->getMillis();
-				if (now >= _seqEndTime && !_seqSubframePlaying)
-					break;
+int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
+	bool incompatibleData = false;
+	MusicDataID soundSet = kMusicIntro;
+	_firstScene = firstScene;
+	_loopStartScene = loopStartScene;
+	_preventLooping = false;
+	_result = 0;
 
-				uint32 tdiff = _seqEndTime - _seqSubFrameStartTime;
-				int32 dly = _tickLength - (now - _seqSubFrameStartTime);
-				if (dly > 0)
-					delay(MIN<uint32>(dly, tdiff));
-				else
-					updateInput();
-			}
+	if (firstScene >= kSequenceArraySize || firstScene < kSequenceVirgin || loopStartScene >= kSequenceArraySize || loopStartScene < kSequenceNoLooping) {
+		return 0;
+	} else if (firstScene >= kSequenceLoLDemoScene1) {
+#ifndef ENABLE_LOL
+		error("SeqPlayer_HOF::play(): The Lands of Lore sub engine (including this non-interactive demo) has been disabled in this build");
+#endif
+		incompatibleData = (_vm->game() != GI_LOL);
+		_firstScene -= kSequenceLoLDemoScene1;
+		if (loopStartScene != kSequenceNoLooping)
+			_loopStartScene -= kSequenceLoLDemoScene1;
+		_lastScene = kSequenceLoLDemoScene6 - kSequenceLoLDemoScene1;
+		_target = kLoLDemo;
+		_screen->_charWidth = 0;
+	} else if (firstScene >= kSequenceHoFDemoVirgin) {
+		incompatibleData = (_vm->game() != GI_KYRA2 || _vm->gameFlags().isDemo || _vm->gameFlags().isTalkie);
+		_firstScene -= kSequenceHoFDemoVirgin;
+		if (loopStartScene != kSequenceNoLooping)
+			_loopStartScene -= kSequenceHoFDemoVirgin;
+		_lastScene = kSequenceHoFDemoFisher - kSequenceHoFDemoVirgin;
+		_target = kHoFDemo;
+		_screen->_charWidth = -2;
+	} else {
+		_isFinale = _preventLooping = firstScene > kSequenceZanfaun;
+		incompatibleData = (_vm->game() != GI_KYRA2 || (_vm->gameFlags().isDemo && (!_vm->gameFlags().isTalkie || _isFinale)));
+		_target = kHoF;
+		_screen->_charWidth = -2;
+		if (_isFinale) {
+			soundSet = kMusicFinale;
+			_lastScene = kSequenceFrash;
+		} else {
+			_lastScene = kSequenceZanfaun;
 		}
+	}
 
-		if (cb && !(_flags.isDemo && !_flags.isTalkie))
-			(this->*cb)(0, 0, 0, -2);
-
-		uint32 ct = seq_activeTextsTimeLeft();
-		uint32 dl = cseq.duration * _tickLength;
-		if (dl < ct)
-			dl = ct;
-		_seqEndTime = _system->getMillis() + dl;
-
-		while (!((skipFlag() && allowSkip) || shouldQuit() || (_abortIntroFlag && allowSkip) || _menuChoice)) {
-			_seqSubFrameStartTime = _system->getMillis();
-			seq_processWSAs();
+	if (incompatibleData)
+		error("SeqPlayer_HOF::play(): Requested sequences do not match the available sequence data for this target");
 
-			_screen->copyPage(2, 0);
-			_screen->updateScreen();
-			_screen->copyPage(12, 2);
+	_vm->sound()->setSoundList(_vm->soundData(soundSet));
+	_vm->sound()->loadSoundFile(0);
 
-			uint32 now = _system->getMillis();
-			if (now >= _seqEndTime && !_seqSubframePlaying) {
-				break;
-			}
+	setupCallbacks();
+	runLoop();
 
-			uint32 tdiff = _seqEndTime - _seqSubFrameStartTime;
-			int32 dly = _tickLength - (now - _seqSubFrameStartTime);
-			if (dly > 0)
-				delay(MIN<uint32>(dly, tdiff));
-			else
-				updateInput();
-		}
+	return _result;
+}
 
-		seq_sequenceCommand(cseq.finalCommand);
-		seq_resetAllTextEntries();
+void SeqPlayer_HOF::pause(bool toggle) {
+	if (toggle) {
 
-		if (_abortIntroFlag || skipFlag()) {
-			_sound->haltTrack();
-			_sound->voiceStop();
-		}
-
-		if (!_flags.isDemo || _flags.isTalkie) {
-			if ((seqNum != kSequenceTitle && seqNum < kSequenceZanfaun &&
-			(_abortIntroFlag || skipFlag())) || seqNum == kSequenceZanfaun) {
-				_abortIntroFlag = false;
-				_eventList.clear();
-				seqNum = kSequenceWestwood;
-			} else if (seqNum < kSequenceFrash && (_abortIntroFlag || skipFlag())) {
-				_abortIntroFlag = false;
-				_eventList.clear();
-				seqNum = kSequenceFirates;
+	} else {
+		//
+		// Timers in KyraEngine_HoF::nestedFrameFadeTransition() and KyraEngine_HoF::nestedFrameAnimTransition()
+		// have been left out for now. I think we don't need them here.
+
+	/*	_fisherAnimCurTime += pausedTime;
+		_seqSubFrameStartTime += pausedTime;
+		_seqEndTime += pausedTime;
+		_seqSubFrameEndTimeInternal += pausedTime;
+		_seqWsaChatTimeout += pausedTime;
+		_seqWsaChatFrameTimeout += pausedTime;
+
+		if (_textSlots) {
+			for (int x = 0; x < 10; x++) {
+				if (_textSlots[x].duration != -1)
+					_textSlots[x].startTime += pausedTime;
 			}
-		} else if (seqNum == endSeq && !(_abortIntroFlag || skipFlag())) {
-			seqNum = 0;
 		}
 
-		if (_menuChoice) {
-			_abortIntroFlag = false;
-			_eventList.clear();
-
-			if (_menuChoice == 2) {
-				seqNum = kSequenceTitle;
-				_menuChoice = 0;
+		if (_animSlots) {
+			for (int x = 0; x < 8; x++) {
+				if (_animSlots[x].flags != -1)
+					_animSlots[x].nextFrame += pausedTime;
 			}
 		}
-	}
 
-	if (_flags.isDemo && !_flags.isTalkie) {
-		_eventList.clear();
-		_screen->fadeToBlack();
+		for (int x = 0; x < _itemAnimDefinitionSize; x++)
+			_activeItemAnim[x].nextFrameTime += pausedTime;*/
 	}
+}
 
-	if (!_menuChoice)
-		delay(1200);
-
-	_screen->setCurPage(oldPage);
-	_screen->showMouse();
+void SeqPlayer_HOF::setupCallbacks() {
+#define SCB(x) &SeqPlayer_HOF::cbHOF_##x
+	static const SeqProc seqCallbacksHoF[] = { 0, SCB(westwood), SCB(title), SCB(overview), SCB(library), SCB(hand), SCB(point), SCB(zanfaun), SCB(funters), SCB(ferb), SCB(fish), SCB(fheep), SCB(farmer), SCB(fuards), SCB(firates), SCB(frash) };
+	static const SeqProc nestedSeqCallbacksHoF[] = { SCB(figgle), SCB(over1), SCB(over2), SCB(forest), SCB(dragon), SCB(darm), SCB(library2), SCB(library2), SCB(marco), SCB(hand1a), SCB(hand1b), SCB(hand1c), SCB(hand2), SCB(hand3), 0 };
+#undef SCB
+#define SCB(x) &SeqPlayer_HOF::cbHOFDEMO_##x
+	static const SeqProc seqCallbacksHoFDemo[] = {	SCB(virgin), SCB(westwood), SCB(title), SCB(hill), SCB(outhome), SCB(wharf), SCB(dinob), SCB(fisher) };
+	static const SeqProc nestedSeqCallbacksHoFDemo[] = { SCB(wharf2), SCB(dinob2), SCB(water), SCB(bail), SCB(dig), 0 };
+#undef SCB
+#ifdef ENABLE_LOL
+#define SCB(x) &SeqPlayer_HOF::cbLOLDEMO_##x
+	static const SeqProc seqCallbacksLoLDemo[] = { SCB(scene1), SCB(scene2), SCB(scene3), SCB(scene4), SCB(scene5), SCB(text5), SCB(scene6), 0 };
+#undef SCB
+#else
+	static const SeqProc seqCallbacksLoLDemo[] = { 0 };
+#endif
+	static const SeqProc nestedSeqCallbacksLoLDemo[] = { 0 };
+
+	static const SeqProc *seqCallbacks[] = { seqCallbacksHoF, seqCallbacksHoFDemo, seqCallbacksLoLDemo};
+	static const SeqProc *nestedSeqCallbacks[] = { nestedSeqCallbacksHoF, nestedSeqCallbacksHoFDemo, nestedSeqCallbacksLoLDemo};
+
+	int tmpSize = 0;
+	delete _config;
+	_config = new SeqPlayerConfig(_vm->staticres()->loadHoFSequenceData(k2SeqplaySeqData, tmpSize), seqCallbacks[_target], nestedSeqCallbacks[_target]);
+}
+
+void SeqPlayer_HOF::runLoop() {
+	memset(_animSlots, 0, sizeof(_animSlots));
+	memset(_textSlots, 0, sizeof(_textSlots));
+	memset(_hofDemoActiveItemAnim, 0, sizeof(_hofDemoActiveItemAnim));
+	for (int i = 0; i < 8; ++i)
+		_animSlots[i].flags = -1;
 
-	for (int i = 0; i < 8; i++)
-		seq_unloadWSA(i);
+	_screen->clearPage(10);
+	_screen->clearPage(12);
+	_screen->hideMouse();
+	int oldPage = _screen->setCurPage(2);
 
-	_seqWsa->close();
+	for (int i = 0; i < 4; ++i)
+		_screen->getPalette(i).clear();
 
-	_screen->_charWidth = 0;
+	_updateAnimations = false;
+	_animCurrentFrame = 0;
+	_seqTextColor[0] = _seqTextColor[1] = 0;
+	_curScene = _firstScene;
 
-	seq_uninit();
-}
+	do {
+		playScenes();
+		doTransition(0);
+		seq_resetAllTextEntries();
+		fadeOutMusic();
+		_firstScene = ((!_startupSaveLoadable || _preventLooping) && _curScene >= _loopStartScene) ? kSequenceNoLooping : _loopStartScene;
+	} while (!_vm->shouldQuit() && _firstScene != kSequenceNoLooping);
 
-int KyraEngine_HoF::seq_introWestwood(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == -2) {
-		if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
-			delay(300 * _tickLength);
-	} else if (!frm) {
-		_sound->playTrack(2);
-	}
+	checkPlaybackStatus();
 
-	return 0;
-}
+	for (int i = 0; i < 8; i++)
+		unloadNestedAnimation(i);
 
-int KyraEngine_HoF::seq_introTitle(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 1) {
-		_sound->playTrack(3);
-	} else if (frm == 25) {
-		int cp = _screen->setCurPage(0);
-		_screen->showMouse();
-		_system->updateScreen();
-		_menuChoice = _menu->handle(11) + 1;
-		_seqEndTime = 0;
-		_seqSubframePlaying = false;
-		if (_menuChoice == 4)
-			quitGame();
+	if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie)
+		_screen->fadeToBlack();
 
-		_screen->hideMouse();
-		_screen->setCurPage(cp);
-	}
+	if (!_result)
+		delayTicks(75);
 
-	return 0;
+	_screen->setCurPage(oldPage);
+	_screen->_charWidth = 0;
+	_screen->showMouse();
 }
 
-int KyraEngine_HoF::seq_introOverview(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	uint8 *tmpPal = _screen->getPalette(3).getData() + 0x101;
-	memset(tmpPal, 0, 256);
-	_seqSubFrameEndTimeInternal = 0;
-	uint32 now = 0;
+void SeqPlayer_HOF::playScenes() {
+	_vm->sound()->stopAllSoundEffects();
+	_curScene = _firstScene;
 
-	switch (_seqFrameCounter) {
-	case 0:
-		_seqSubframePlaying = true;
-		_sound->playTrack(4);
-		_seqSubFrameEndTimeInternal = _system->getMillis() + 60 * _tickLength;
+	_screen->copyPalette(1, 0);
+	WSAMovie_v2 anim(_vm);
+	_abortRequested = 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), 1, 255) & 0xff;
+	while (!_vm->shouldQuit()) {
+		if (checkAbortPlayback())
+			if (checkPlaybackStatus())
+				break;
 
-		_screen->setTextColorMap(_seqTextColorMap);
+		_callbackCurrentFrame = 0;
 
-		now = _system->getMillis();
-		if (_seqSubFrameEndTimeInternal > now)
-			delay(_seqSubFrameEndTimeInternal - now);
-		break;
+		if (_curScene > _lastScene)
+			break;
 
-	case 1:
-		_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;
+		const Kyra::HoFSequence &sq = _config->seq[_curScene];
 
-		for (int i = 0; i < 256; i++) {
-			int v = (tmpPal[i] == 1) ? i : _screen->getPalette(3)[i];
-			v *= 3;
-			_screen->getPalette(2)[3 * i] = _screen->getPalette(0)[v];
-			_screen->getPalette(2)[3 * i + 1] = _screen->getPalette(0)[v + 1];
-			_screen->getPalette(2)[3 * i + 2] = _screen->getPalette(0)[v + 2];
+		if (sq.flags & 2) {
+			_screen->loadBitmap(sq.cpsFile, 2, 2, &_screen->getPalette(0));
+			_screen->setScreenPalette(_screen->getPalette(0));
+		} else {
+			_screen->setCurPage(2);
+			_screen->clearPage(2);
+			_screen->loadPalette("GOLDFONT.COL", _screen->getPalette(0));
 		}
-		break;
 
-	case 40:
-		seq_loadNestedSequence(0, kSequenceOver1);
-		break;
+		if (_config->seqProc[_curScene] && !(_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie))
+			(this->*_config->seqProc[_curScene])(0, 0, 0, -1);
 
-	case 60:
-		seq_loadNestedSequence(1, kSequenceOver2);
-		break;
+		if (sq.flags & 1) {
+			anim.open(sq.wsaFile, 0, &_screen->getPalette(0));
+			if (!(sq.flags & 2))
+				anim.displayFrame(0, 2, sq.xPos, sq.yPos, 0x4000, 0, 0);
+		}
 
-	case 120:
-		seq_playTalkText(0);
-		break;
+		if (sq.flags & 4) {
+			int cp = _screen->setCurPage(2);
+			Screen::FontId cf =	_screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
 
-	case 200:
-		seq_waitForTextsTimeout();
-		_screen->fadePalette(_screen->getPalette(2), 64);
-		break;
+			if (sq.stringIndex1 != -1)
+				_screen->printText(_sequenceStrings[sq.stringIndex1], (320 - _screen->getTextWidth(_sequenceStrings[sq.stringIndex1])) / 2, 100 - _screen->getFontHeight(), 1, 0);
 
-	case 201:
-		_screen->setScreenPalette(_screen->getPalette(2));
-		_screen->updateScreen();
-		_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));
-		_screen->updateScreen();
-		seq_resetActiveWSA(0);
-		seq_resetActiveWSA(1);
-		break;
+			if (sq.stringIndex2 != -1)
+				_screen->printText(_sequenceStrings[sq.stringIndex2], (320 - _screen->getTextWidth(_sequenceStrings[sq.stringIndex2])) / 2, 100, 1, 0);
 
-	case 282:
-		seq_loadNestedSequence(0, kSequenceForest);
-		seq_playTalkText(1);
-		break;
+			_screen->setFont(cf);
+			_screen->setCurPage(cp);
+		}
 
-	case 354:
-	case 434:
-		if (!((_seqFrameCounter == 354 && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) || (_seqFrameCounter == 434 && _flags.platform == Common::kPlatformPC)))
-			break;
+		_screen->copyPage(2, 12);
+		_screen->copyPage(0, 2);
+		_screen->copyPage(2, 10);
+		_screen->copyPage(12, 2);
 
-		seq_resetActiveWSA(0);
-		seq_loadNestedSequence(0, kSequenceDragon);
-		break;
+		doTransition(sq.fadeInTransitionType);
 
-	case 400:
-	case 540:
-		if (!((_seqFrameCounter == 400 && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) || (_seqFrameCounter == 540 && _flags.platform == Common::kPlatformPC)))
-			break;
+		if (!(checkAbortPlayback() || _vm->shouldQuit() || _result)) {
+			_screen->copyPage(2, 0);
+			_screen->updateScreen();
+		}
 
-		seq_waitForTextsTimeout();
-		seq_resetActiveWSA(0);
-		_seqEndTime = 0;
-		_seqSubframePlaying = false;
-		break;
+		//_screen->copyPage(2, 6);
 
-	default:
-		break;
-	}
+		if (sq.flags & 1) {
+			playAnimation(&anim, sq.startFrame, sq.numFrames, sq.duration, sq.xPos, sq.yPos, _config->seqProc[_curScene], &_screen->getPalette(1), &_screen->getPalette(0), 30, 0);
+			anim.close();
+		} else {
+			_animDuration = sq.duration;
+			setCountDown(_animDuration);
+
+			while (!checkAbortPlayback() && !_vm->shouldQuit() && (countDownRunning() || _updateAnimations)) {
+				uint32 endFrame = (_system->getMillis() + _vm->tickLength()) & ~(_vm->tickLength() - 1);
+				updateAllNestedAnimations();
+				// Due to bugged coding / sequence data in the FM-Towns and PC-98 versions these animations will only play correctly on slow hardware.
+				// If the hardware is too fast the animations will not finish. This bug was probably irrelevant for original FM-Towns or PC-98 machines.
+				// We compensate this with a small extra delay.
+				if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+					delayTicks(1);
+				
+				if (_config->seqProc[_curScene])
+					(this->*_config->seqProc[_curScene])(0, 0, 0, 0);
 
-	_seqFrameCounter++;
-	return 0;
-}
+				seq_processText();
 
-int KyraEngine_HoF::seq_introLibrary(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (_seqFrameCounter) {
-	case 0:
-		_seqSubframePlaying = true;
-		_sound->playTrack(5);
+				_screen->copyPage(2, 0);
+				_screen->updateScreen();
+				_screen->copyPage(12, 2);
 
-		_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), 1, 255) & 0xff;
+				// See comment above.
+				if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+					delayTicks(1);
 
-		_screen->setTextColorMap(_seqTextColorMap);
-		break;
+				do {
+					if (checkAbortPlayback())
+						if (checkPlaybackStatus())
+							break;				
+				} while (_system->getMillis() < endFrame);
+			}
+		}
 
-	case 1:
-		seq_loadNestedSequence(0, kSequenceLibrary3);
-		seq_playTalkText(4);
-		break;
+		if (_config->seqProc[_curScene] && !(_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie))
+			(this->*_config->seqProc[_curScene])(0, 0, 0, -2);
 
-	case 100:
-		seq_waitForTextsTimeout();
+		uint32 textTimeOut = ticksTillSubTitlesTimeout();
+		setCountDown(sq.timeout < textTimeOut ? textTimeOut : sq.timeout);
 
-		_screen->copyPage(12, 2);
-		_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);
+		while (!checkAbortPlayback() && !_vm->shouldQuit() && (countDownRunning() || _updateAnimations)) {
+			updateAllNestedAnimations();
+			_screen->copyPage(2, 0);
+			_screen->updateScreen();
+			_screen->copyPage(12, 2);
+		}
 
-		seq_resetActiveWSA(0);
-		seq_loadNestedSequence(0, kSequenceDarm);
-		break;
+		doTransition(sq.fadeOutTransitionType);
+		_curScene++;
+	}
 
-	case 104:
-		seq_playTalkText(5);
-		break;
+	if (checkAbortPlayback() || _vm->shouldQuit()) {
+		seq_resetAllTextEntries();
+		_vm->sound()->haltTrack();
+		_vm->sound()->voiceStop();
+	}
+}
 
-	case 240:
-		seq_waitForTextsTimeout();
-		seq_resetActiveWSA(0);
-		seq_loadNestedSequence(0, kSequenceLibrary2);
-		break;
+bool SeqPlayer_HOF::checkAbortPlayback() {
+	Common::Event event;
 
-	case 340:
-		seq_resetActiveWSA(0);
-		_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();
+	if (_abortRequested)
+		return true;
 
-		seq_loadNestedSequence(0, kSequenceMarco);
-		seq_playTalkText(6);
-		break;
+	while (_system->getEventManager()->pollEvent(event)) {
+		switch (event.type) {
+		case Common::EVENT_KEYDOWN:
+			if (event.kbd.keycode == Common::KEYCODE_q && event.kbd.hasFlags(Common::KBD_CTRL)) {
+				_abortRequested = true;
+				_vm->quitGame();
+				return true;
+			} else if (event.kbd.keycode != Common::KEYCODE_ESCAPE && event.kbd.keycode != Common::KEYCODE_RETURN && event.kbd.keycode != Common::KEYCODE_SPACE)
+				continue;
+		case Common::EVENT_LBUTTONDOWN:
+		case Common::EVENT_RBUTTONDOWN:
+		case Common::EVENT_LBUTTONUP:
+		case Common::EVENT_RBUTTONUP:
+			_abortRequested = true;
+			return true;
+		}
+	}
 
-	case 480:
-	case 660:
-		if (!((_seqFrameCounter == 480 && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) || (_seqFrameCounter == 660 && _flags.platform == Common::kPlatformPC)))
-			break;
+	return false;
+}
 
-		_screen->copyPage(2, 12);
-		seq_waitForTextsTimeout();
-		seq_resetActiveWSA(0);
-		_seqEndTime = 0;
-		_seqSubframePlaying = false;
-		break;
+bool SeqPlayer_HOF::checkPlaybackStatus() {
+	_updateAnimations = false;
 
-	default:
-		break;
+	if (_curScene <= _preventSkipBeforeScene || _curScene == _loopStartScene) {
+		_abortRequested = false;
+		return false;
 	}
 
-	_seqFrameCounter++;
-	return 0;
+	if (_loopStartScene == kSequenceNoLooping) {
+		doTransition(0);
+		fadeOutMusic();
+		_abortPlayback = true;
+	} else {
+		return true;
+	}
+
+	return false;
 }
 
+void SeqPlayer_HOF::doTransition(int type) {
+	for (int i = 0; i < 8; i++)
+		closeNestedAnimation(i);
 
-int KyraEngine_HoF::seq_introHand(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (_seqFrameCounter) {
+	switch (type) {
 	case 0:
-		_seqSubframePlaying = true;
-		_sound->playTrack(6);
-
-		_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), 1, 255) & 0xff;
-
-		_screen->setTextColorMap(_seqTextColorMap);
+		_screen->fadeToBlack(36);
+		_screen->getPalette(0).clear();
+		_screen->getPalette(1).clear();
 		break;
 
 	case 1:
-		seq_loadNestedSequence(0, kSequenceHand1a);
-		seq_loadNestedSequence(1, kSequenceHand1b);
-		seq_loadNestedSequence(2, kSequenceHand1c);
-		seq_playTalkText(7);
+		seq_playTalkText(_vm->_rnd.getRandomBit());
+
+		_screen->getPalette(0).fill(0, 256, 0x3F);
+		_screen->fadePalette(_screen->getPalette(0), 16);
+
+		_screen->copyPalette(1, 0);
 		break;
 
-	case 201:
-		seq_waitForTextsTimeout();
-		_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();
-		seq_resetActiveWSA(0);
-		seq_resetActiveWSA(1);
-		seq_resetActiveWSA(2);
-		seq_loadNestedSequence(0, kSequenceHand2);
-		seq_playTalkText(8);
+	case 3:
+		_screen->copyPage(2, 0);
+		_screen->fadePalette(_screen->getPalette(0), 16);
+		_screen->copyPalette(1, 0);
 		break;
 
-	case 260:
-	case 395:
-		if (!((_seqFrameCounter == 260 && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) || (_seqFrameCounter == 395 && _flags.platform == Common::kPlatformPC)))
-			break;
+	case 4:
+		_screen->copyPage(2, 0);
+		_screen->fadePalette(_screen->getPalette(0), 36);
+		_screen->copyPalette(1, 0);
+		break;
 
-		seq_waitForTextsTimeout();
-		seq_resetActiveWSA(0);
-		seq_loadNestedSequence(1, kSequenceHand3);
-		seq_playTalkText(9);
+	case 5:
+		_screen->copyPage(2, 0);
 		break;
 
-	case 365:
-	case 500:
-		if (!((_seqFrameCounter == 365 && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) || (_seqFrameCounter == 500 && _flags.platform == Common::kPlatformPC)))
-			break;
+	case 6:
+		// UNUSED
+		// seq_loadBLD("library.bld");
+		break;
 
-		seq_waitForTextsTimeout();
-		seq_resetActiveWSA(1);
-		seq_loadNestedSequence(0, kSequenceHand4);
+	case 7:
+		// UNUSED
+		// seq_loadBLD("marco.bld");
 		break;
 
-	case 405:
-	case 540:
-		if (!((_seqFrameCounter == 405 && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) || (_seqFrameCounter == 540 && _flags.platform == Common::kPlatformPC)))
-			break;
+	case 8:
+		_screen->fadeToBlack(16);
+		_screen->getPalette(0).clear();
+		_screen->getPalette(1).clear();
 
-		seq_playTalkText(10);
+		delayTicks(120);
 		break;
 
-	case 484:
-	case 630:
-		if (!((_seqFrameCounter == 484 && (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) || (_seqFrameCounter == 630 && _flags.platform == Common::kPlatformPC)))
-			break;
+	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;
+		}
 
-		seq_waitForTextsTimeout();
-		seq_resetActiveWSA(0);
-		_seqEndTime = 0;
-		_seqSubframePlaying = false;
-		break;
+		//int a = 0x100;
+		//int d = (0x800 << 5) - 0x100;
+		//pal[3 * i] = pal[3 * i + 1] = pal[3 * i + 2] = 0x3f;
+
+		_screen->fadePalette(pal, 64);
+		_screen->copyPalette(1, 0);
+		} break;
 
 	default:
 		break;
 	}
-
-	_seqFrameCounter++;
-	return 0;
 }
 
-int KyraEngine_HoF::seq_introPoint(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == -2) {
-		seq_waitForTextsTimeout();
-		_seqEndTime = 0;
-	}
+void SeqPlayer_HOF::nestedFrameAnimTransition(int srcPage, int dstPage, int delaytime, int steps, int x, int y, int w, int h, int openClose, int directionFlags) {
+	if (openClose) {
+		for (int i = 1; i < steps; i++) {
+			uint32 endtime = _system->getMillis() + delaytime * _vm->tickLength();
 
-	switch (_seqFrameCounter) {
-	case -2:
-		seq_waitForTextsTimeout();
-		break;
+			int w2 = (((w * 256) / steps) * i) / 256;
+			int h2 = (((h * 256) / steps) * i) / 256;
 
-	case 0:
-		_sound->playTrack(7);
+			int ym = (directionFlags & 2) ? (h - h2) : 0;
+			int xm = (directionFlags & 1) ? (w - w2) : 0;
 
-		_seqTextColor[1] = 0xf7;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_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).getData(), 0x24, 0, 0, 0, 0x100, false);
-		break;
+			_screen->wsaFrameAnimationStep(0, 0, x + xm, y + ym, w, h, w2, h2, srcPage, dstPage, 0);
 
-	case 1:
-		seq_playTalkText(11);
-		break;
+			_screen->copyPage(dstPage, 6);
+			_screen->copyPage(dstPage, 0);
+			_screen->updateScreen();
 
-	default:
-		break;
-	}
+			_screen->copyPage(12, dstPage);
+			delayUntil(endtime);
+		}
 
-	_seqFrameCounter++;
-	return 0;
+		_screen->wsaFrameAnimationStep(0, 0, x, y, w, h, w, h, srcPage, dstPage, 0);
+		_screen->copyPage(dstPage, 6);
+		_screen->copyPage(dstPage, 0);
+		_screen->updateScreen();
+	} else {
+		_screen->copyPage(12, dstPage);
+		for (int i = steps; i; i--) {
+			uint32 endtime = _system->getMillis() + delaytime * _vm->tickLength();
+
+			int w2 = (((w * 256) / steps) * i) / 256;
+			int h2 = (((h * 256) / steps) * i) / 256;
+
+			int ym = (directionFlags & 2) ? (h - h2) : 0;
+			int xm = (directionFlags & 1) ? (w - w2) : 0;
+
+			_screen->wsaFrameAnimationStep(0, 0, x + xm, y + ym, w, h, w2, h2, srcPage, dstPage, 0);
+
+			_screen->copyPage(dstPage, 6);
+			_screen->copyPage(dstPage, 0);
+			_screen->updateScreen();
+
+			_screen->copyPage(12, dstPage);
+			delayUntil(endtime);
+		}
+	}
 }
 
-int KyraEngine_HoF::seq_introZanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == -2) {
-		seq_waitForTextsTimeout();
-		_seqEndTime = 0;
-		return 0;
+void SeqPlayer_HOF::nestedFrameFadeTransition(const char *cmpFile) {
+	_screen->copyPage(10, 2);
+	_screen->copyPage(4, 10);
+	_screen->clearPage(6);
+	_screen->loadBitmap(cmpFile, 6, 6, 0);
+	_screen->copyPage(12, 4);
+
+	for (int i = 0; i < 3; i++) {
+		uint32 endtime = _system->getMillis() + 4 * _vm->tickLength();
+		assert(_screenHoF);
+		_screenHoF->cmpFadeFrameStep(4, 320, 200, 0, 0, 2, 320, 200, 0, 0, 320, 200, 6);
+		_screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+		_screen->updateScreen();
+		delayUntil(endtime);
 	}
 
-	switch (_seqFrameCounter) {
-	case 0:
-		_sound->playTrack(8);
+	_screen->copyPage(4, 0);
+	_screen->updateScreen();
+	_screen->copyPage(4, 2);
+	_screen->copyPage(4, 6);
+	_screen->copyPage(10, 4);
+}
 
-		_seqTextColor[1] = 0xfd;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_seqTextColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
-		break;
+void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastFrame, int frameRate, int x, int y, const SeqProc callback, Palette *fadePal1, Palette *fadePal2, int fadeRate, bool restoreScreen) {
+	bool finished = false;
+	uint32 startTime = _system->getMillis();
 
-	case 1:
-		if (_flags.isTalkie) {
-			seq_playWsaSyncDialogue(21, 13, -1, 140, 70, 160, wsaObj, 0, 8, x, y);
-		} else {
-			seq_setTextEntry(21, 140, 70, 200, 160);
-			_seqFrameDelay = 200;
-		}
-		break;
+	int origW = wsaObj->width();
+	int origH = wsaObj->width();
+	int drwX = x;
+	int drwY = y;
+	int drwW = origW;
+	int drwH = origH;
 
-	case 2:
-	case 11:
-	case 21:
-		if (!_flags.isTalkie)
-			_seqFrameDelay = 12;
-		break;
+	_animDuration = frameRate;
 
-	case 9:
-		if (_flags.isTalkie)
-			seq_playWsaSyncDialogue(13, 14, -1, 140, (_flags.lang == Common::FR_FRA
-				|| _flags.lang == Common::DE_DEU) ? 50 : 70, 160, wsaObj, 9, 15, x, y);
-		break;
+	if (wsaObj) {
+		if (x < 0) {
+			drwW += x;
+			drwX = 0;
+		}
 
-	case 10:
-		if (!_flags.isTalkie) {
-			seq_waitForTextsTimeout();
-			seq_setTextEntry(13, 140, 50, _sequenceStringsDuration[13], 160);
-			_seqFrameDelay = 300;
+		if (y < 0) {
+			drwH += y;
+			drwY = 0;
 		}
-		break;
 
-	case 16:
-		if (_flags.isTalkie)
-			seq_playWsaSyncDialogue(18, 15, -1, 140, (_flags.lang == Common::FR_FRA) ? 50 :
-				(_flags.lang == Common::DE_DEU ? 40 : 70), 160, wsaObj, 10, 16, x, y);
-		break;
+		if (x + origW > 319)
+			origW = 320 - x;
 
-	case 17:
-		if (_flags.isTalkie)
-			_seqFrameDelay = 12;
-		break;
+		if (y + origH > 199)
+			origW = 200 - y;
+	}
 
-	case 20:
-		if (!_flags.isTalkie) {
-			seq_waitForTextsTimeout();
-			seq_setTextEntry(18, 160, 50, _sequenceStringsDuration[18], 160);
-			_seqFrameDelay = 200;
-		}
-		break;
+	int8 frameStep = (startFrame > lastFrame) ? -1 : 1;
+	_animCurrentFrame = startFrame;
 
-	case 26:
-		seq_waitForTextsTimeout();
-		break;
+	while (!_vm->shouldQuit() && !finished) {
+		if (checkAbortPlayback())
+			if (checkPlaybackStatus())
+				break;
 
-	case 46:
-		if (_flags.isTalkie) {
-			seq_playWsaSyncDialogue(16, 16, -1, 200, 50, 120, wsaObj, 46, 46, x, y);
-		} else {
-			seq_waitForTextsTimeout();
-			seq_setTextEntry(16, 200, 50, _sequenceStringsDuration[16], 120);
+		setCountDown(_animDuration);
+
+		if (wsaObj || callback)
+			_screen->copyPage(12, 2);
+
+		int frameIndex = _animCurrentFrame;
+		if (wsaObj)
+			frameIndex %= wsaObj->frames();
+
+		if (callback)
+			(this->*callback)(wsaObj, x, y, frameIndex);
+
+		if (wsaObj)
+			wsaObj->displayFrame(frameIndex, 2, x, y, 0, 0, 0);
+
+		_screen->copyPage(2, 12);
+
+		updateAllNestedAnimations();
+		seq_processText();
+
+		if (wsaObj || callback && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
+			_screen->copyPage(2, 0);
+			_screen->updateScreen();
 		}
 
-		_seqEndTime = _system->getMillis() + 120 * _tickLength;
-		break;
+		while (!_vm->shouldQuit()) {
+			if (checkAbortPlayback())
+				if (checkPlaybackStatus())
+					break;
 
-	default:
-		break;
-	}
+			if (fadePal1 && fadePal2) {
+				if (!_screen->timedPaletteFadeStep(fadePal1->getData(), fadePal2->getData(), _system->getMillis() - startTime, fadeRate * _vm->tickLength()) && !wsaObj)
+					break;
+			}
 
-	_seqFrameCounter++;
-	return 0;
-}
+			if (wsaObj || callback && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
+				_screen->copyPage(2, 0);
+				_screen->updateScreen();
+			}
 
-int KyraEngine_HoF::seq_introOver1(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 2)
-		seq_waitForTextsTimeout();
-	else if (frm == 3)
-		seq_playTalkText(12);
-	return frm;
-}
+			seq_processText();
 
+			if (!countDownRunning())
+				break;
+		}
 
-int KyraEngine_HoF::seq_introOver2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 1)
-		seq_playTalkText(12);
-	return frm;
+		if (wsaObj) {
+			_animCurrentFrame += frameStep;
+			if (_animCurrentFrame == lastFrame)
+				finished = true;
+		}
+
+		if (restoreScreen && (wsaObj || callback)) {
+			_screen->copyPage(12, 2);
+			_screen->copyRegion(drwX, drwY, drwX, drwY, drwW, drwH, 2, 0, Screen::CR_NO_P_CHECK);
+			_screen->updateScreen();
+		}
+	}
 }
 
-int KyraEngine_HoF::seq_introForest(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 11)
-		seq_waitForTextsTimeout();
-	else if (frm == 12)
-		seq_playTalkText(2);
+void SeqPlayer_HOF::startNestedAnimation(int animSlot, int sequenceID) {
+	if (_animSlots[animSlot].flags != -1)
+		return;
 
-	return frm;
-}
+	HoFNestedSequence s = _config->nestedSeq[sequenceID];
 
-int KyraEngine_HoF::seq_introDragon(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 11)
-		seq_waitForTextsTimeout();
-	else if (frm == 3)
-		seq_playTalkText(3);
-	return frm;
-}
+	if (!_animSlots[animSlot].movie) {
+		_animSlots[animSlot].movie = new WSAMovie_v2(_vm);
+		assert(_animSlots[animSlot].movie);
+	}
 
-int KyraEngine_HoF::seq_introDarm(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
-	return frm;
-}
+	_animSlots[animSlot].movie->close();
 
-int KyraEngine_HoF::seq_introLibrary2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
-	return frm;
-}
+	_animSlots[animSlot].movie->open(s.wsaFile, 0, 0);
 
-int KyraEngine_HoF::seq_introMarco(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 36) {
-		seq_waitForTextsTimeout();
-		_seqEndTime = 0;
+	if (!_animSlots[animSlot].movie->opened()) {
+		delete _animSlots[animSlot].movie;
+		_animSlots[animSlot].movie = 0;
+		return;
 	}
-	return frm;
-}
 
-int KyraEngine_HoF::seq_introHand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
-	return frm;
-}
+	_animSlots[animSlot].endFrame = s.endFrame;
+	_animSlots[animSlot].startFrame = _animSlots[animSlot].currentFrame = s.startframe;
+	_animSlots[animSlot].frameDelay = s.frameDelay;
+	_animSlots[animSlot].callback = _config->nestedSeqProc[sequenceID];
+	_animSlots[animSlot].control = s.wsaControl;
 
-int KyraEngine_HoF::seq_introHand1b(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 15)
-		frm = 12;
-	return frm;
-}
+	_animSlots[animSlot].flags = s.flags | 1;
+	_animSlots[animSlot].x = s.x;
+	_animSlots[animSlot].y = s.y;
+	_animSlots[animSlot].fadeInTransitionType = s.fadeInTransitionType;
+	_animSlots[animSlot].fadeOutTransitionType = s.fadeOutTransitionType;
+	_animSlots[animSlot].lastFrame = 0xffff;
 
-int KyraEngine_HoF::seq_introHand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 8)
-		frm = 4;
-	return frm;
+	doNestedFrameTransition(s.fadeInTransitionType, animSlot);
+
+	if (!s.fadeInTransitionType)
+		updateNestedAnimation(animSlot);
+
+	_animSlots[animSlot].nextFrame = _system->getMillis() & ~(_vm->tickLength() - 1);
 }
 
-int KyraEngine_HoF::seq_introHand2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
-	return frm;
+void SeqPlayer_HOF::closeNestedAnimation(int animSlot) {
+	if (_animSlots[animSlot].flags == -1)
+		return;
+
+	_animSlots[animSlot].flags = -1;
+	doNestedFrameTransition(_animSlots[animSlot].fadeOutTransitionType, animSlot);
+	_animSlots[animSlot].movie->close();
 }
 
-int KyraEngine_HoF::seq_introHand3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
-	return frm;
+void SeqPlayer_HOF::unloadNestedAnimation(int animSlot) {
+	if (_animSlots[animSlot].movie) {
+		_animSlots[animSlot].movie->close();
+		delete _animSlots[animSlot].movie;
+		_animSlots[animSlot].movie = 0;
+	}
 }
 
-int KyraEngine_HoF::seq_finaleFunters(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	_seqSubFrameEndTimeInternal = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	int chatFirstFrame = 0;
-	int chatLastFrame = 0;
-	uint16 voiceIndex = 0;
+void SeqPlayer_HOF::doNestedFrameTransition(int transitionType, int animSlot) {
+	int xa = 0, ya = 0;
+	transitionType--;
+	if (!_animSlots[animSlot].movie || _abortPlayback || _vm->shouldQuit())
+		return;
 
-	switch (frm) {
-	case -2:
-		seq_sequenceCommand(9);
+	switch (transitionType) {
+	case 0:
+		xa = -_animSlots[animSlot].movie->xAdd();
+		ya = -_animSlots[animSlot].movie->yAdd();
+		_animSlots[animSlot].movie->displayFrame(0, 8, xa, ya, 0, 0, 0);
+		nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
+							_animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 1, 2);
 		break;
 
-	case 0:
-		_sound->playTrack(3);
+	case 1:
+		xa = -_animSlots[animSlot].movie->xAdd();
+		ya = -_animSlots[animSlot].movie->yAdd();
+		_animSlots[animSlot].movie->displayFrame(0, 8, xa, ya, 0, 0, 0);
+		nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
+							_animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 1, 1);
+		break;
 
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
+	case 2:
+		waitForSubTitlesTimeout();
+		xa = -_animSlots[animSlot].movie->xAdd();
+		ya = -_animSlots[animSlot].movie->yAdd();
+		_animSlots[animSlot].movie->displayFrame(21, 8, xa, ya, 0, 0, 0);
+		nestedFrameAnimTransition(8, 2, 7, 8, _animSlots[animSlot].movie->xAdd(), _animSlots[animSlot].movie->yAdd(),
+							_animSlots[animSlot].movie->width(), _animSlots[animSlot].movie->height(), 0, 2);
+		break;
 
-		_seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
-		seq_printCreditsString(81, 240, 70, _seqTextColorMap, 252);
-		seq_printCreditsString(82, 240, 90, _seqTextColorMap, _seqTextColor[0]);
+	case 3:
+		_screen->copyPage(2, 10);
+		_animSlots[animSlot].movie->displayFrame(0, 2, 0, 0, 0, 0, 0);
 		_screen->copyPage(2, 12);
-		seq_playTalkText(_flags.isTalkie ? 28 : 24);
-		delay(_seqSubFrameEndTimeInternal - _system->getMillis());
-		_seqTextColor[0] = 1;
+		nestedFrameFadeTransition("scene2.cmp");
+		break;
 
-		if (_flags.isTalkie) {
-			chatY = (_flags.lang == Common::FR_FRA) ? 70 : 78;
-			chatFirstFrame = 9;
-			chatLastFrame = 15;
-			voiceIndex = 34;
-		} else {
-			chatY = (_flags.lang == Common::FR_FRA) ? 78 : 70;
-			chatFirstFrame = 0;
-			chatLastFrame = 8;
-		}
-		chatX = (_flags.lang == Common::FR_FRA) ? 84 : 88;
-		chatW = 100;
+	case 4:
+		_screen->copyPage(2, 10);
+		_animSlots[animSlot].movie->displayFrame(0, 2, 0, 0, 0, 0, 0);
+		_screen->copyPage(2, 12);
+		nestedFrameFadeTransition("scene3.cmp");
+		break;
 
-		seq_playWsaSyncDialogue(22, voiceIndex, 187, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+	default:
 		break;
+	}
+}
 
-	case 9:
-	case 16:
-		if (!((frm == 9 && !_flags.isTalkie) || (frm == 16 && _flags.isTalkie)))
-			break;
+void SeqPlayer_HOF::updateAllNestedAnimations() {
+	for (int i = 0; i < 8; i++) {
+		if (_animSlots[i].flags != -1) {
+			if (updateNestedAnimation(i))
+				closeNestedAnimation(i);
+		}
+	}
+}
 
-		_seqFrameDelay = 12;
+bool SeqPlayer_HOF::updateNestedAnimation(int animSlot) {
+	uint16 currentFrame = _animSlots[animSlot].currentFrame;
+	uint32 curTick = _system->getMillis() & ~(_vm->tickLength() - 1);
+	
+	if (_animSlots[animSlot].callback && currentFrame != _animSlots[animSlot].lastFrame) {
+		_animSlots[animSlot].lastFrame = currentFrame;
+		currentFrame = (this->*_animSlots[animSlot].callback)(_animSlots[animSlot].movie, _animSlots[animSlot].x, _animSlots[animSlot].y, currentFrame);
+	}
 
-		if (_flags.lang == Common::FR_FRA) {
-			chatX = 80;
-			chatW = 112;
+	if (_animSlots[animSlot].movie) {
+		if (_animSlots[animSlot].flags & 0x20) {
+			_animSlots[animSlot].movie->displayFrame(_animSlots[animSlot].control[currentFrame].index, 2, _animSlots[animSlot].x, _animSlots[animSlot].y, 0x4000, 0, 0);
+			_animSlots[animSlot].frameDelay = _animSlots[animSlot].control[currentFrame].delay;
 		} else {
-			chatX = (_flags.lang == Common::DE_DEU) ? 84 : 96;
-			chatW = 100;
+			_animSlots[animSlot].movie->displayFrame(currentFrame % _animSlots[animSlot].movie->frames(), 2, _animSlots[animSlot].x, _animSlots[animSlot].y, 0x4000, 0, 0);
 		}
+	}
 
-		if (_flags.isTalkie) {
-			chatFirstFrame = 0;
-			chatLastFrame = 8;
-			voiceIndex = 35;
-		} else {
-			chatFirstFrame = 9;
-			chatLastFrame = 15;
+	if (_animSlots[animSlot].flags & 0x10) {
+		currentFrame = (curTick - _animSlots[animSlot].nextFrame) / (_animSlots[animSlot].frameDelay * _vm->tickLength());
+	} else {
+		int diff = (curTick - _animSlots[animSlot].nextFrame) / (_animSlots[animSlot].frameDelay * _vm->tickLength());
+		if (diff > 0) {
+			currentFrame++;
+			_animSlots[animSlot].nextFrame = curTick;
 		}
-		chatY = 70;
+	}
 
-		seq_playWsaSyncDialogue(23, voiceIndex, 137, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
-		if (_flags.isTalkie)
-			_seqWsaCurrentFrame = 17;
-		break;
+	bool res = false;
 
-	default:
-		break;
+	if (currentFrame >= _animSlots[animSlot].endFrame) {
+		int sw = ((_animSlots[animSlot].flags & 0x1e) - 2);
+		switch (sw) {
+		case 0:
+			res = true;
+			currentFrame = _animSlots[animSlot].endFrame;
+			_screen->copyPage(2, 12);
+			break;
+
+		case 6:
+		case 8:
+			currentFrame = _animSlots[animSlot].endFrame - 1;
+			break;
+
+		case 2:
+		case 10:
+			currentFrame = _animSlots[animSlot].startFrame;
+			break;
+
+		default:
+			currentFrame = _animSlots[animSlot].endFrame - 1;
+			res = true;
+		}
 	}
 
-	_seqFrameCounter++;
-	return 0;
+	_animSlots[animSlot].currentFrame = currentFrame;
+	return res;
 }
 
-int KyraEngine_HoF::seq_finaleFerb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	_seqSubFrameEndTimeInternal = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	int chatFirstFrame = 0;
-	int chatLastFrame = 0;
-	uint16 voiceIndex = 0;
+void SeqPlayer_HOF::seq_playTalkText(uint8 chatNum) {
+	assert(chatNum < _sequenceSoundListSize);
 
-	switch (frm) {
-	case -2:
-		seq_sequenceCommand(9);
-		_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);
-		seq_printCreditsString(37, 240, _flags.isTalkie ? 100 : 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(38, 240, _flags.isTalkie ? 120 : 110, _seqTextColorMap, 252);
-		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(_seqSubFrameEndTimeInternal - _system->getMillis());
-		_seqEndTime = 0;
-		break;
+	if (chatNum < 12 && !_vm->gameFlags().isDemo && _vm->textEnabled())
+		seq_setTextEntry(chatNum, 160, 168, _textDuration[chatNum], 160);
 
-	case 0:
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 255;
-		_screen->setTextColorMap(_seqTextColorMap);
-		break;
+	_vm->sound()->voicePlay(_sequenceSoundList[chatNum], &_speechHandle);
+}
 
-	case 5:
-		if (!_flags.isTalkie)
-			seq_playTalkText(18);
-		_seqFrameDelay = 16;
+void SeqPlayer_HOF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, int textColor, int x, int y, int width, WSAMovie_v2 *wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos) {
+	int dur = int(strlen(_sequenceStrings[strIndex])) * (_vm->gameFlags().isTalkie ? 7 : 15);
+	if (_vm->textEnabled()) {
+		int entry = seq_setTextEntry(strIndex, x, y, dur, width);
+		_textSlots[entry].textcolor = textColor;
+	}
+	_seqWsaChatTimeout = _system->getMillis() + dur * _vm->tickLength();
+	int curframe = firstframe;
 
-		if (_flags.isTalkie) {
-			chatFirstFrame = 5;
-			chatLastFrame = 8;
-			voiceIndex = 22;
-		} else {
-			chatLastFrame = 14;
+	if (vocIndex && _vm->speechEnabled()) {
+		while (_vm->sound()->voiceIsPlaying() && !_abortPlayback)
+			delayTicks(1);
+		seq_playTalkText(vocIndex);
+	}
+
+	while (_system->getMillis() < _seqWsaChatTimeout && !_abortPlayback) {
+		if (lastframe < 0) {
+			int t = ABS(lastframe);
+			if (t < curframe)
+				curframe = t;
 		}
-		chatX = 116;
-		chatY = 90;
-		chatW = 60;
 
-		seq_playWsaSyncDialogue(24, voiceIndex, 149, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
-		break;
+		if (ABS(lastframe) < curframe)
+			curframe = firstframe;
 
-	case 11:
-		if (_flags.isTalkie)
-			seq_playWsaSyncDialogue(24, 22, 149, 116, 90, 60, wsaObj, 11, 14, x, y);
-		break;
+		_seqWsaChatFrameTimeout = _system->getMillis() + _animDuration * _vm->tickLength();
+		setCountDown(_animDuration);
 
-	case 16:
-		seq_playTalkText(_flags.isTalkie ? 23 : 19);
-		_seqFrameDelay = _flags.isTalkie ? 20 : 16;
+		if (wsa)
+			wsa->displayFrame(curframe % wsa->frames(), 2, wsaXpos, wsaYpos, 0, 0, 0);
 
-		if (_flags.lang == Common::FR_FRA) {
-			chatY = 48;
-			chatW = 88;
-		} else {
-			chatY = 60;
-			chatW = 100;
-		}
-		chatX = 60;
+		_screen->copyPage(2, 12);
 
-		if (_flags.isTalkie)
-			voiceIndex = 36;
+		seq_processText();
 
-		seq_playWsaSyncDialogue(25, voiceIndex, 143, chatX, chatY, chatW, wsaObj, 16, 25, x, y);
-		_seqFrameDelay = 16;
-		break;
+		uint32 tm = _system->getMillis();
+		if (_seqWsaChatFrameTimeout > tm && _seqWsaChatTimeout > tm)
+			_vm->delay(MIN(_seqWsaChatFrameTimeout - tm, _seqWsaChatTimeout - tm));
 
-	default:
-		break;
+		if (_vm->speechEnabled() && !_vm->textEnabled() && !_vm->snd_voiceIsPlaying())
+			break;
+
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		curframe++;
 	}
 
-	_seqFrameCounter++;
-	return 0;
-}
+	if (_abortPlayback)
+		_vm->sound()->voiceStop();
 
-int KyraEngine_HoF::seq_finaleFish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	_seqSubFrameEndTimeInternal = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	uint16 voiceIndex = 0;
+	if (ABS(lastframe) < curframe)
+		curframe = ABS(lastframe);
 
-	switch (frm) {
-	case -2:
-		seq_sequenceCommand(9);
-		_seqSubFrameEndTimeInternal = _system->getMillis() + 480 * _tickLength;
+	if (curframe == firstframe)
+		curframe++;
 
-		seq_printCreditsString(40, 240, _flags.isTalkie ? 55 : 40, _seqTextColorMap, 252);
-		seq_printCreditsString(41, 240, _flags.isTalkie ? 65 : 50, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(42, 240, _flags.isTalkie ? 75 : 60, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(43, 240, _flags.isTalkie ? 95 : 80, _seqTextColorMap, 252);
-		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(_seqSubFrameEndTimeInternal - _system->getMillis());
-		_seqEndTime = 0;
-		break;
+	_animCurrentFrame = curframe;
+}
 
-	case 0:
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
-		break;
+void SeqPlayer_HOF::seq_printCreditsString(uint16 strIndex, int x, int y, const uint8 *colorMap, uint8 textcolor) {
+	uint8 colormap[16];
+	if (_abortPlayback || _vm->shouldQuit() || _result)
+		return;
 
-	case 4:
-		chatX = 94;
-		chatY = 42;
-		chatW = 100;
-		if (_flags.isTalkie)
-			voiceIndex = 37;
-		seq_playWsaSyncDialogue(26, voiceIndex, 149, chatX, chatY, chatW, wsaObj, 3, 12, x, y);
-		break;
+	Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
 
-	case 14:
-		seq_playTalkText(_flags.isTalkie ? 19 : 15);
-		break;
+	memset(&_screen->getPalette(0)[0x2fa], 0x3f, 6);
+	_screen->getPalette(0)[0x2f6] = 0x3f;
+	_screen->getPalette(0)[0x2f5] = 0x20;
+	_screen->getPalette(0)[0x2f4] = 0x30;
+	colormap[0] = colorMap[0];
+	colormap[1] = 0xfd;
+	memcpy(&colormap[2], &colorMap[2], 14);
+	uint8 seqTextColor0 = _seqTextColor[0];
 
-	case 23:
-		seq_playTalkText(_flags.isTalkie ? 20 : 16);
-		break;
+	_seqTextColor[0] = 253;
+	_screen->setTextColorMap(colormap);
+	seq_resetAllTextEntries();
+	seq_setTextEntry(strIndex, x, y, 0x80, 0x78);
+	seq_processText();
+	_screen->copyPage(2, 0);
+	_screen->updateScreen();
+	_screen->getPalette(0)[0x2f7] = _screen->getPalette(0)[textcolor * 3];
+	_screen->getPalette(0)[0x2f8] = _screen->getPalette(0)[textcolor * 3 + 1];
+	_screen->getPalette(0)[0x2f9] = _screen->getPalette(0)[textcolor * 3 + 2];
+	_screen->fadePalette(_screen->getPalette(0), 0x18);
 
-	case 29:
-		chatX = (_flags.lang == Common::DE_DEU) ? 82 : ((_flags.lang == Common::FR_FRA) ? 92 : 88);
-		chatY = 40;
-		chatW = 100;
+	_seqTextColor[0] = textcolor;
+	_screen->setTextColorMap(colorMap);
+	seq_resetAllTextEntries();
+	seq_setTextEntry(strIndex, x, y, 0x80, 0x78);
+	seq_processText();
+	_screen->copyPage(2, 0);
+	_screen->updateScreen();
+	_screen->getPalette(0)[0x2f7] = _screen->getPalette(0)[0x2f8] = _screen->getPalette(0)[0x2f9] = 0;
+	_screen->fadePalette(_screen->getPalette(0), 1);
+	_screen->copyPage(2, 12);
+	seq_resetAllTextEntries();
 
-		if (_flags.isTalkie) {
-			if (_flags.lang == Common::DE_DEU)
-				chatY = 35;
-			voiceIndex = 38;
-		}
+	_seqTextColor[0] = seqTextColor0;
 
-		seq_playWsaSyncDialogue(27, voiceIndex, 187, chatX, chatY, chatW, wsaObj, 28, 34, x, y);
-		break;
+	_screen->setFont(of);
+}
 
-	case 45:
-		seq_playTalkText(_flags.isTalkie ? 21 : 17);
-		break;
+int SeqPlayer_HOF::seq_setTextEntry(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width) {
+	for (int i = 0; i < 10; i++) {
+		if (_textSlots[i].duration != -1) {
+			if (i < 9)
+				continue;
+			else
+				return -1;
+		}
 
-	case 50:
-		seq_playTalkText(_flags.isTalkie ? 29 : 25);
-		break;
+		_textSlots[i].strIndex = strIndex;
+		_textSlots[i].x = posX;
+		_textSlots[i].y = posY;
+		_textSlots[i].duration = duration * _vm->tickLength();
+		_textSlots[i].width = width;
+		_textSlots[i].startTime = _system->getMillis();
+		_textSlots[i].textcolor = -1;
 
-	default:
-		break;
+		return i;
 	}
-
-	_seqFrameCounter++;
-	return 0;
+	return -1;
 }
 
-int KyraEngine_HoF::seq_finaleFheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	_seqSubFrameEndTimeInternal = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	int chatFirstFrame = 0;
-	int chatLastFrame = 0;
-	uint16 voiceIndex = 0;
+void SeqPlayer_HOF::seq_processText() {
+	int curPage = _screen->setCurPage(2);
+	char outputStr[70];
 
-	switch (frm) {
-	case -2:
-		_screen->copyPage(12, 2);
-		_screen->copyPage(2, 0);
-		_screen->updateScreen();
-		seq_sequenceCommand(9);
-		_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]);
-		seq_printCreditsString(52, 240, 50, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(53, 240, 60, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(54, 240, 70, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(55, 240, 80, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(56, 240, 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(57, 240, 100, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(58, 240, 110, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(60, 240, 120, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(61, 240, 130, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(62, 240, 140, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(63, 240, 150, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(64, 240, 160, _seqTextColorMap, _seqTextColor[0]);
+	for (int i = 0; i < 10; i++) {
+		if (_textSlots[i].startTime + _textSlots[i].duration > _system->getMillis() && _textSlots[i].duration != -1) {
 
-		delay(_seqSubFrameEndTimeInternal - _system->getMillis());
-		_seqEndTime = 0;
-		break;
+			char *srcStr = seq_preprocessString(_sequenceStrings[_textSlots[i].strIndex], _textSlots[i].width);
+			int yPos = _textSlots[i].y;
 
-	case 0:
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
-		break;
-
-	case 2:
-		seq_playTalkText(_flags.isTalkie ? 25 : 21);
+			while (*srcStr) {
+				uint32 linePos = 0;
+				for (; *srcStr; linePos++) {
+					if (*srcStr == '\r')
+						break;
+					outputStr[linePos] = *srcStr;
+					srcStr++;
+				}
+				outputStr[linePos] = 0;
+				if (*srcStr == '\r')
+					srcStr++;
 
-		if (_flags.lang == Common::FR_FRA) {
-			chatX = 92;
-			chatY = 72;
+				uint8 textColor = (_textSlots[i].textcolor >= 0) ? _textSlots[i].textcolor : _seqTextColor[0];
+				_screen->printText(outputStr, _textSlots[i].x - (_screen->getTextWidth(outputStr) / 2), yPos, textColor, 0);
+				yPos += 10;
+			}
 		} else {
-			chatX = (_flags.lang == Common::DE_DEU) ? 90 : 98;
-			chatY = 84;
+			_textSlots[i].duration = -1;
 		}
+	}
 
-		if (_flags.isTalkie) {
-			chatFirstFrame = 8;
-			chatLastFrame = 9;
-			voiceIndex = 39;
+	_screen->setCurPage(curPage);
+}
+
+char *SeqPlayer_HOF::seq_preprocessString(const char *srcStr, int width) {
+	char *dstStr = _tempString;
+	int lineStart = 0;
+	int linePos = 0;
+
+	while (*srcStr) {
+		while (*srcStr && *srcStr != ' ')
+			dstStr[lineStart + linePos++] = *srcStr++;
+		dstStr[lineStart + linePos] = 0;
+
+		int len = _screen->getTextWidth(&dstStr[lineStart]);
+		if (width >= len && *srcStr) {
+			dstStr[lineStart + linePos++] = *srcStr++;
 		} else {
-			chatFirstFrame = 2;
-			chatLastFrame = -8;
+			dstStr[lineStart + linePos] = '\r';
+			lineStart += linePos + 1;
+			linePos = 0;
+			if (*srcStr)
+				srcStr++;
 		}
-		chatW = 100;
+	}
+	dstStr[lineStart + linePos] = 0;
 
-		seq_playWsaSyncDialogue(28, voiceIndex, -1, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
-		if (_flags.isTalkie)
-			_seqWsaCurrentFrame = 4;
-		break;
+	return strlen(_tempString) ? dstStr : 0;
+}
 
-	case 9:
-		seq_playTalkText(_flags.isTalkie ? 24 : 20);
-		_seqFrameDelay = 100;
-		break;
+void SeqPlayer_HOF::waitForSubTitlesTimeout() {
+	uint32 timeOut = _system->getMillis() + ticksTillSubTitlesTimeout() * _vm->tickLength();
 
-	default:
-		break;
+	if (_vm->textEnabled()) {
+		delayUntil(timeOut);
+	} else if (_vm->speechEnabled()) {
+		while (_vm->snd_voiceIsPlaying())
+			delayTicks(1);
 	}
 
-	_seqFrameCounter++;
-	return 0;
+	seq_resetAllTextEntries();
 }
 
-int KyraEngine_HoF::seq_finaleFarmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	_seqSubFrameEndTimeInternal = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	uint16 voiceIndex = 0;
+uint32 SeqPlayer_HOF::ticksTillSubTitlesTimeout() {
+	uint32 longest = 0;
 
-	switch (frm) {
-	case -2:
-		_screen->copyPage(12, 2);
-		_screen->copyPage(2, 0);
-		_screen->updateScreen();
-		seq_sequenceCommand(9);
-		_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]);
-		seq_printCreditsString(83, 240, 80, _seqTextColorMap, 252);
-		seq_printCreditsString(48, 240, 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(65, 240, 110, _seqTextColorMap, 252);
-		seq_printCreditsString(66, 240, 120, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(67, 240, 130, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(68, 240, 140, _seqTextColorMap, _seqTextColor[0]);
-		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(_seqSubFrameEndTimeInternal - _system->getMillis());
-		_seqEndTime = 0;
-		break;
+	for (int i = 0; i < 10; i++) {
+		uint32 timeOut = (_textSlots[i].duration + _textSlots[i].startTime);
+		uint32 curtime = _system->getMillis();
+		if (_textSlots[i].duration != -1 && timeOut > curtime) {
+			timeOut -= curtime;
+			if (longest < timeOut)
+				longest = timeOut;
+		}
+	}
 
-	case 0:
-		_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), 1, 254) & 0xff);
-		_screen->setTextColorMap(_seqTextColorMap);
-		seq_playTalkText(_flags.isTalkie ? 30 : 26);
-		break;
+	uint32 tl = _vm->tickLength();
+	return (longest + (tl - 1)) / tl;
+}
 
-	case 6:
-		if (_flags.isTalkie)
-			seq_playTalkText(18);
-		break;
+void SeqPlayer_HOF::seq_resetAllTextEntries() {
+	for (int i = 0; i < 10; i++)
+		_textSlots[i].duration = -1;
+}
 
-	case 12:
-		if (!_flags.isTalkie)
-			seq_playTalkText(14);
+void SeqPlayer_HOF::fadeOutMusic() {
+	_vm->sound()->beginFadeOut();
+	delayTicks(80);
+}
 
-		chatX = 90;
-		chatY = 30;
-		chatW = 100;
+void SeqPlayer_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 };
 
-		if (_flags.isTalkie) {
-			if (_flags.lang == Common::FR_FRA || _flags.lang == Common::DE_DEU) {
-				chatX = 75;
-				chatY = 25;
-			}
-			voiceIndex = 40;
-		}
+	_screen->loadBitmap("finale.cps", 3, 3, &_screen->getPalette(0));
+	_screen->setFont(Screen::FID_GOLDFONT_FNT);
 
-		seq_playWsaSyncDialogue(29, voiceIndex, 150, chatX, chatY, chatW, wsaObj, 12, -21, x, y);
-		break;
+	int talkieCreditsSize, talkieCreditsSpecialSize;
+	const uint8 *talkieCredits = _vm->staticres()->loadRawData(k2SeqplayCredits, talkieCreditsSize);
+	const char * const *talkieCreditsSpecial = _vm->staticres()->loadStrings(k2SeqplayCreditsSpecial, talkieCreditsSpecialSize);
 
-	default:
-		break;
-	}
+	_vm->sound()->setSoundList(_vm->soundData(kMusicIngame));
+	_vm->sound()->loadSoundFile(3);
+	_vm->sound()->playTrack(3);
 
-	_seqFrameCounter++;
-	return 0;
-}
+	_screen->setTextColorMap(colormap);
+	_screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
+	_screen->updateScreen();
+	_screen->fadeFromBlack();
 
-int KyraEngine_HoF::seq_finaleFuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	_seqSubFrameEndTimeInternal = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	int chatFirstFrame = 0;
-	int chatLastFrame = 0;
-	//int textCol = 0;
+	_screen->_charWidth = -2;
+	uint8 *dataPtr = new uint8[0xafd];
+	memcpy(dataPtr, talkieCredits, talkieCreditsSize);
+	_vm->staticres()->unloadId(k2SeqplayCredits);
 
-	uint16 voiceIndex = 0;
+	seq_displayScrollText(dataPtr, &d, 2, 6, 5, 1, Screen::FID_GOLDFONT_FNT, Screen::FID_GOLDFONT_FNT, 0, talkieCreditsSpecial);
+	delayTicks(8);
 
-	switch (frm) {
-	case -2:
-		seq_sequenceCommand(9);
-		_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]);
-		seq_printCreditsString(73, 240, 50, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(74, 240, 60, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(75, 240, 70, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(101, 240, 80, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(102, 240, 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(87, 240, 100, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(88, 240, 110, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(89, 240, 120, _seqTextColorMap, _seqTextColor[0]);
-		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(_seqSubFrameEndTimeInternal - _system->getMillis());
-		_seqEndTime = 0;
-		break;
+	delete[] dataPtr;
+	_vm->staticres()->unloadId(k2SeqplayCreditsSpecial);
+	_vm->sound()->setSoundList(_vm->soundData(kMusicFinale));
+	_vm->sound()->loadSoundFile(0);
+}
 
-	case 0:
-		for (int i = 0; i < 0x300; i++)
-			_screen->getPalette(0)[i] &= 0x3f;
-		_seqTextColor[1] = 0xCf;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xfe;
+void SeqPlayer_HOF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed,
+	int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData, const char *const *specialData) {
+	if (!data)
+		return;
 
-		_screen->setTextColorMap(_seqTextColorMap);
-		break;
+	static const char mark[] = { 5, 13, 0 };
 
-	case 6:
-		_seqFrameDelay = 20;
+	_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);
 
-		if (_flags.isTalkie) {
-			chatX = 82;
-			//textCol = 143;
-			chatFirstFrame = 16;
-			chatLastFrame = 21;
-			voiceIndex = 41;
-		} else {
-			chatX = 62;
-			//textCol = 137;
-			chatFirstFrame = 9;
-			chatLastFrame = 13;
+	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
 		}
-		chatY = (_flags.lang == Common::FR_FRA || _flags.lang == Common::DE_DEU) ? 88 :100;
-		chatW = 80;
+	};
 
-		seq_playWsaSyncDialogue(30, voiceIndex, 137, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
-		if (_flags.isTalkie)
-			_seqWsaCurrentFrame = 8;
-		break;
+	ScrollTextData *textData = new ScrollTextData[36];
+	uint8 *ptr = data;
 
-	case 9:
-	case 16:
-		if (_flags.isTalkie) {
-			if (frm == 16)
+	bool loop = true;
+	int cnt = 0;
+
+	while (loop) {
+		uint32 loopEnd = _system->getMillis() + speed * _vm->tickLength();
+
+		while (cnt < 35 && *ptr) {
+			uint16 cH;
+
+			if (cnt)
+				cH = textData[cnt].y + textData[cnt].height + (textData[cnt].height >> 3);
+			else
+				cH = d->h;
+
+			char *str = (char *)ptr;
+
+			ptr = (uint8 *)strpbrk(str, mark);
+			if (!ptr)
+				ptr = (uint8 *)strchr(str, 0);
+
+			textData[cnt + 1].unk1 = *ptr;
+			*ptr = 0;
+			if (textData[cnt + 1].unk1)
+				ptr++;
+
+			if (*str == 3 || *str == 4)
+				textData[cnt + 1].adjust = *str++;
+			else
+				textData[cnt + 1].adjust = 0;
+
+			_screen->setFont(fid1);
+
+			if (*str == 1) {
+				_screen->setFont(fid2);
+				str++;
+			} else if (*str == 2) {
+				str++;
+			}
+
+			textData[cnt + 1].height = _screen->getFontHeight();
+
+			switch (textData[cnt + 1].adjust) {
+			case 3:
+				textData[cnt + 1].x = 157 - _screen->getTextWidth(str);
 				break;
-			chatX = 64;
-			//textCol = 137;
-			chatFirstFrame = 9;
-			chatLastFrame = 13;
-			voiceIndex = 42;
-		} else {
-			if (frm == 9)
+			case 4:
+				textData[cnt + 1].x = 161;
 				break;
-			chatX = 80;
-			//textCol = 143;
-			chatFirstFrame = 16;
-			chatLastFrame = 21;
+			default:
+				textData[cnt + 1].x = (((d->w << 3) - _screen->getTextWidth(str)) >> 1) + 1;
+			}
+
+			if (textData[cnt].unk1 == 5)
+				cH -= (textData[cnt].height + (textData[cnt].height >> 3));
+
+			textData[cnt + 1].y = cH;
+			textData[cnt + 1].text = (uint8 *)str;
+			cnt++;
 		}
-		chatY = 100;
-		chatW = 100;
 
-		seq_playWsaSyncDialogue(31, voiceIndex, 143, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
-		if (_flags.isTalkie)
-			_seqWsaCurrentFrame = 21;
-		break;
+		_screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage1, tempPage2);
 
-	default:
-		break;
-	}
+		int cnt2 = 0;
+		bool palCycle = 0;
 
-	_seqFrameCounter++;
-	return 0;
-}
+		while (cnt2 < cnt) {
+			const char *str = (const char *)textData[cnt2 + 1].text;
+			const char *str2 = str;
+			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;
 
-int KyraEngine_HoF::seq_finaleFirates(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	_seqSubFrameEndTimeInternal = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	uint16 voiceIndex = 0;
+			if (cH < d->h) {
+				_screen->setCurPage(tempPage2);
+				_screen->setFont(fid1);
+				if (textData[cnt2 + 1].height != _screen->getFontHeight())
+					_screen->setFont(fid2);
 
-	switch (frm) {
-	case -2:
-		_screen->copyPage(12, 2);
-		_screen->copyPage(2, 0);
+				if (specialData) {
+					if (!strcmp(str, specialData[0])) {
+						col1 = 112;
+						char cChar[2] = " ";
+						while (*str2) {
+							cChar[0] = *str2;
+							_screen->printText(cChar, x, y, col1++, 0);
+							x += _screen->getCharWidth((uint8)*str2++);
+						}
+						palCycle = true;
+					} else if (!strcmp(str, specialData[1])) {
+						col1 = 133;
+						char cChar[2] = " ";
+						while (*str2) {
+							cChar[0] = *str2;
+							_screen->printText(cChar, x, y, col1--, 0);
+							x += _screen->getCharWidth((uint8)*str2++);
+						}
+						palCycle = true;
+					} else {
+						_screen->printText(str, x, y, col1, 0);
+					}
+				} else {
+					_screen->printText(str, x, y, col1, 0);
+				}
+				_screen->setCurPage(0);
+			}
+
+			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();
-		seq_sequenceCommand(9);
-		_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]);
-		seq_printCreditsString(79, 240, 70, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(80, 240, 80, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(84, 240, 100, _seqTextColorMap, 252);
-		seq_printCreditsString(85, 240, 110, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(99, 240, 130, _seqTextColorMap, 252);
-		seq_printCreditsString(100, 240, 140, _seqTextColorMap, _seqTextColor[0]);
-		delay(_seqSubFrameEndTimeInternal - _system->getMillis());
-		_seqEndTime = 0;
-		break;
 
-	case 0:
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
-		break;
+		if (textData[1].y < -10) {
+			textData[1].text += strlen((char *)textData[1].text);
+			textData[1].text[0] = textData[1].unk1;
+			cnt--;
+			memcpy(&textData[1], &textData[2], cnt * sizeof(ScrollTextData));
+		}
 
-	case 6:
-		seq_playTalkText(_flags.isTalkie ? 31 : 27);
-		break;
+		if (palCycle) {
+			for (int col = 133; col > 112; col--)
+				_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));
+		}
 
-	case 14:
-	case 15:
-		if (!((frm == 15 && !_flags.isTalkie) || (frm == 14 && _flags.isTalkie)))
-			break;
+		delayUntil(loopEnd);
 
-		seq_playTalkText(_flags.isTalkie ? 31 : 27);
+		if ((cnt < 36) && ((d->sy + d->h) > (textData[cnt].y + textData[cnt].height)) && !_abortPlayback) {
+			delayTicks(500);
+			cnt = 0;
+		}
 
-		if (_flags.lang == Common::DE_DEU) {
-			chatX = 82;
-			chatY = 84;
-			chatW = 140;
-		} else {
-			chatX = 74;
-			chatY = (_flags.lang == Common::FR_FRA) ? 96: 108;
-			chatW = 80;
+		if (!cnt || _abortPlayback)
+			loop = false;
+	}
+
+	_vm->sound()->beginFadeOut();
+	_screen->fadeToBlack();
+
+	_abortPlayback = false;
+
+	delete[] textData;
+}
+
+void SeqPlayer_HOF::seq_scrollPage(int bottom, int top) {
+	int dstY, dstH, srcH;
+
+	static const ScreenDim d = { 0x00, 0x00, 0x28, 0x320, 0xFF, 0xFE, 0x00, 0x00 };
+
+	if (_seqScrollTextCounter - (top - 1) < 0) {
+		dstY = top - _seqScrollTextCounter;
+		dstH = _seqScrollTextCounter;
+		srcH = 0;
+	} else {
+		dstY = 0;
+		srcH = _seqScrollTextCounter - top;
+		dstH = (400 - srcH <= top) ? 400 - srcH : top;
+	}
+
+	if (dstH > 0) {
+		assert(_hofDemoAnimData);
+		for (int i = 0; i < 4; i++) {
+			const HoFSeqItemAnimData *def = &_hofDemoAnimData[i];
+			ActiveItemAnim *a = &_hofDemoActiveItemAnim[i];
+
+			_screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4);
+			_screen->drawShape(4, _hofDemoItemShapes[def->itemIndex + def->frames[a->currentFrame]], 12, def->y - 8, 0, 0);
+			if (_animCurrentFrame % 2 == 0)
+				a->currentFrame = (a->currentFrame + 1) % 20;
 		}
+		assert(_screenHoF);
+		_screenHoF->copyRegionEx(4, 0, srcH, 2, 2, dstY + bottom, 320, dstH, &d);
+	}
+}
 
-		if (_flags.isTalkie)
-			voiceIndex = 43;
+void SeqPlayer_HOF::delayTicks(uint32 ticks) {
+	uint32 len = ticks * _vm->tickLength();
+	while (len && !_vm->shouldQuit() && !checkAbortPlayback()) {
+		uint32 step = (len >= 10) ? 10 : len;
+		_system->delayMillis(step);
+		len -= step;
+	}
+}
 
-		seq_playWsaSyncDialogue(32, voiceIndex, 137, chatX, chatY, chatW, wsaObj, 14, 16, x, y);
-		break;
+void SeqPlayer_HOF::delayUntil(uint32 dest) {
+	for (uint32 ct = _system->getMillis(); ct < dest && !_vm->shouldQuit() && !checkAbortPlayback(); ) {
+		uint32 step = (dest - ct >= 10) ? 10 : (dest - ct);
+		_system->delayMillis(step);
+		ct = _system->getMillis();
+	}
+}
 
-	case 28:
-		seq_playTalkText(_flags.isTalkie ? 32 : 28);
-		break;
+void SeqPlayer_HOF::setCountDown(uint32 ticks) {
+	_countDownRemainder = ticks * _vm->tickLength();
+	_countDownLastUpdate = _system->getMillis() & ~(_vm->tickLength() - 1);
+}
+	
+bool SeqPlayer_HOF::countDownRunning() {
+	uint32 cur = _system->getMillis();
+	uint32 step = cur - _countDownLastUpdate;
+	_countDownLastUpdate = cur;
+	_countDownRemainder = (step <= _countDownRemainder) ? _countDownRemainder - step : 0;
+	return _countDownRemainder;
+}
 
-	case 29:
-		seq_playTalkText(_flags.isTalkie ? 33 : 29);
-		break;
+#define CASE_ALT(dosCase, towns98Case)\
+	case dosCase:\
+	case towns98Case:\
+		if (!((_callbackCurrentFrame == towns98Case && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == dosCase && _vm->gameFlags().platform == Common::kPlatformPC)))\
+			break;
 
-	case 31:
-		if (_flags.isTalkie)
-			voiceIndex = 44;
+int SeqPlayer_HOF::cbHOF_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == -2) {
+		if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+			delayTicks(300);
+	} else if (!frm) {
+		_vm->sound()->playTrack(2);
+	}
 
-		chatX = 90;
-		chatY = (_flags.lang == Common::DE_DEU) ? 60 : 76;
-		chatW = 80;
+	return 0;
+}
 
-		seq_playWsaSyncDialogue(33, voiceIndex, 143, chatX, chatY, chatW, wsaObj, 31, 34, x, y);
-		break;
+int SeqPlayer_HOF::cbHOF_title(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 1) {
+		_vm->sound()->playTrack(3);
+	} else if (frm == 25 && _startupSaveLoadable) {
+		int cp = _screen->setCurPage(0);
+		_screen->showMouse();
+		_system->updateScreen();
+		_result = _menu->handle(11) + 1;
+		_updateAnimations = false;
+		
+		if (_result == 1) {
+			_curScene = _lastScene;
+			_preventLooping = true;
+		} else {
+			setCountDown(200);
+		}
 
-	case 35:
-		_seqFrameDelay = 300;
-		break;
+		if (_result == 4)
+			_vm->quitGame();
 
-	default:
-		break;
+		_screen->hideMouse();
+		_screen->setCurPage(cp);
 	}
 
-	_seqFrameCounter++;
 	return 0;
 }
 
-int KyraEngine_HoF::seq_finaleFrash(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	int tmp = 0;
+int SeqPlayer_HOF::cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	uint8 *tmpPal = _screen->getPalette(3).getData() + 0x101;
+	memset(tmpPal, 0, 256);
+	uint32 frameEnd = 0;
+	uint32 curTime = 0;
 
-	switch (frm) {
-	case -2:
-		_screen->setCurPage(2);
-		_screen->clearCurPage();
-		_screen->copyPage(2, 12);
-		_screen->copyPage(2, 0);
-		_screen->updateScreen();
-		_seqFrameCounter = 0;
-		seq_loadNestedSequence(0, kSequenceFiggle);
-		break;
+	switch (_callbackCurrentFrame) {
+	case 0:
+		_updateAnimations = true;
+		fadeOutMusic();
+		_vm->sound()->playTrack(4);
+		frameEnd = _system->getMillis() + 60 * _vm->tickLength();
 
-	case -1:
-		if (_flags.isTalkie)
-			 seq_finaleActorScreen();
-		_seqSpecialFlag = _flags.isTalkie;
-		break;
+		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+		_screen->setTextColorMap(_seqTextColorMap);
 
-	case 0:
-		if (_seqFrameCounter == 1) {
-			_sound->playTrack(4);
-			_seqTextColor[1] = _screen->findLeastDifferentColor(_seqTextColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-			memset(_seqTextColorMap, _seqTextColor[1], 16);
-			_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-			_screen->setTextColorMap(_seqTextColorMap);
-		}
-		_seqFrameDelay = 10;
+		delayUntil(frameEnd);
 		break;
 
 	case 1:
-		if (_seqFrameCounter < 20 && _seqSpecialFlag) {
-			_seqWsaCurrentFrame = 0;
-		} else {
-			_seqFrameDelay = _flags.isTalkie ? 500 : (300 + _rnd.getRandomNumberRng(1, 300));
-			seq_playTalkText(_flags.isTalkie ? 26 : 22);
-			if (_seqSpecialFlag) {
-				_seqFrameCounter = 3;
-				_seqSpecialFlag = false;
-			}
+		assert(_screenHoF);
+		_screenHoF->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;
+
+		for (int i = 0; i < 256; i++) {
+			int v = (tmpPal[i] == 1) ? i : _screen->getPalette(3)[i];
+			v *= 3;
+			_screen->getPalette(2)[3 * i] = _screen->getPalette(0)[v];
+			_screen->getPalette(2)[3 * i + 1] = _screen->getPalette(0)[v + 1];
+			_screen->getPalette(2)[3 * i + 2] = _screen->getPalette(0)[v + 2];
 		}
 		break;
 
-	case 2:
-		_seqFrameDelay = 20;
+	case 40:
+		startNestedAnimation(0, kNestedSequenceOver1);
 		break;
 
-	case 3:
-		seq_playTalkText(_flags.isTalkie ? 27 : 23);
-		_seqFrameDelay = _flags.isTalkie ? 500 : (300 + _rnd.getRandomNumberRng(1, 300));
+	case 60:
+		startNestedAnimation(1, kNestedSequenceOver2);
 		break;
 
-	case 4:
-		_seqFrameDelay = 10;
+	case 120:
+		seq_playTalkText(0);
 		break;
 
-	case 5:
-		seq_playTalkText(_flags.isTalkie ? 27 : 23);
-		tmp = _seqFrameCounter / 6;
-		if (tmp == 2)
-			_seqFrameDelay = _flags.isTalkie ? 7 : (1 + _rnd.getRandomNumberRng(1, 10));
-		else if (tmp < 2)
-			_seqFrameDelay = _flags.isTalkie ? 500 : (300 + _rnd.getRandomNumberRng(1, 300));
+	case 200:
+		waitForSubTitlesTimeout();
+		_screen->fadePalette(_screen->getPalette(2), 64);
 		break;
 
-	case 6:
-		_seqFrameDelay = 10;
-		tmp = _seqFrameCounter / 6;
-		if (tmp == 2)
-			_seqWsaCurrentFrame = 4;
-		else if (tmp < 2)
-			_seqWsaCurrentFrame = 0;
+	case 201:
+		_screen->setScreenPalette(_screen->getPalette(2));
+		_screen->updateScreen();
+		_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));
+		_screen->updateScreen();
+		closeNestedAnimation(0);
+		closeNestedAnimation(1);
 		break;
 
-	case 7:
-		_seqFrameCounter = 0;
-		_seqFrameDelay = 5;
-		seq_playTalkText(_flags.isTalkie ? 26 : 22);
+	case 282:
+		startNestedAnimation(0, kNestedSequenceForest);
+		seq_playTalkText(1);
 		break;
 
-	case 11:
-		if (_seqFrameCounter < 8)
-			_seqWsaCurrentFrame = 8;
+	CASE_ALT(434, 354)
+	/*case 354:
+	case 434:
+		if (!((_callbackCurrentFrame == 354 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 434 && _vm->gameFlags().platform == Common::kPlatformPC)))
+			break;*/
+
+		closeNestedAnimation(0);
+		startNestedAnimation(0, kNestedSequenceDragon);
+		break;
+
+	CASE_ALT(540, 400)
+	/*case 400:
+	case 540:
+		if (!((_callbackCurrentFrame == 400 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 540 && _vm->gameFlags().platform == Common::kPlatformPC)))
+			break;*/
+
+		waitForSubTitlesTimeout();
+		closeNestedAnimation(0);
+		setCountDown(0);
+		_updateAnimations = false;
 		break;
 
 	default:
 		break;
 	}
 
-	_seqFrameCounter++;
+	_callbackCurrentFrame++;
 	return 0;
 }
 
-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 };
+int SeqPlayer_HOF::cbHOF_library(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	switch (_callbackCurrentFrame) {
+	case 0:
+		_updateAnimations = true;
+		_vm->sound()->playTrack(5);
 
-	_screen->loadBitmap("finale.cps", 3, 3, &_screen->getPalette(0));
-	_screen->setFont(Screen::FID_GOLDFONT_FNT);
+		assert(_screenHoF);
+		_screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
+		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
 
-	int talkieCreditsSize, talkieCreditsSpecialSize;
-	const uint8 *talkieCredits = _staticres->loadRawData(k2SeqplayCredits, talkieCreditsSize);
-	const char * const *talkieCreditsSpecial = _staticres->loadStrings(k2SeqplayCreditsSpecial, talkieCreditsSpecialSize);
+		_screen->setTextColorMap(_seqTextColorMap);
+		break;
 
-	_sound->setSoundList(&_soundData[kMusicIngame]);
-	_sound->loadSoundFile(3);
-	_sound->playTrack(3);
+	case 1:
+		startNestedAnimation(0, kNestedSequenceLibrary3);
+		seq_playTalkText(4);
+		break;
 
-	_screen->setTextColorMap(colormap);
-	_screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
-	_screen->updateScreen();
-	_screen->fadeFromBlack();
+	case 100:
+		waitForSubTitlesTimeout();
 
-	_screen->_charWidth = -2;
-	uint8 *dataPtr = new uint8[0xafd];
-	memcpy(dataPtr, talkieCredits, talkieCreditsSize);
-	_staticres->unloadId(k2SeqplayCredits);
+		_screen->copyPage(12, 2);
+		_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);
 
-	seq_displayScrollText(dataPtr, &d, 2, 6, 5, 1, Screen::FID_GOLDFONT_FNT, Screen::FID_GOLDFONT_FNT, 0, talkieCreditsSpecial);
-	delay(120);
+		closeNestedAnimation(0);
+		startNestedAnimation(0, kNestedSequenceDarm);
+		break;
 
-	delete[] dataPtr;
-	_staticres->unloadId(k2SeqplayCreditsSpecial);
-	_sound->setSoundList(&_soundData[kMusicFinale]);
-	_sound->loadSoundFile(0);
-}
+	case 104:
+		seq_playTalkText(5);
+		break;
 
-int KyraEngine_HoF::seq_finaleFiggle(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (_seqFrameCounter == 10)
-		_seqEndTime = 0;
-	if (_seqFrameCounter == 10 || _seqFrameCounter == 5 || _seqFrameCounter == 7)
-		seq_playTalkText(_flags.isTalkie ? 45 : 30);
+	case 240:
+		waitForSubTitlesTimeout();
+		closeNestedAnimation(0);
+		startNestedAnimation(0, kNestedSequenceLibrary2);
+		break;
 
-	_seqFrameCounter++;
-	return frm;
-}
+	case 340:
+		closeNestedAnimation(0);
+		_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();
 
-int KyraEngine_HoF::seq_demoVirgin(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (!frm)
-		delay(50 * _tickLength);
-	return 0;
-}
+		startNestedAnimation(0, kNestedSequenceMarco);
+		seq_playTalkText(6);
+		break;
 
-int KyraEngine_HoF::seq_demoWestwood(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (!frm)
-		_sound->playTrack(2);
-	return 0;
-}
-int KyraEngine_HoF::seq_demoTitle(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (!frm) {
-		_sound->playTrack(3);
-	} else if (frm == 25) {
-		delay(60 * _tickLength);
-		_seqEndTime = 0;
-		seq_sequenceCommand(0);
-	}
-	return 0;
-}
+	CASE_ALT(660, 480)
+	/*case 480:
+	case 660:
+		if (!((_callbackCurrentFrame == 480 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 660 && _vm->gameFlags().platform == Common::kPlatformPC)))
+			break;*/
 
-int KyraEngine_HoF::seq_demoHill(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (!frm) {
-		_sound->playTrack(4);
-	} else if (frm == 25) {
-		seq_loadNestedSequence(0, kSequenceDemoWater);
-		_seqFrameDelay--;
-	} else if (frm > 25 && frm < 50) {
-		if (_seqFrameDelay > 3)
-			_seqFrameDelay--;
-	} else if (frm == 95) {
-		_seqFrameDelay = 70;
-	} else if (frm == 96) {
-		_seqFrameDelay = 7;
-	} else if (frm == 129) {
-		seq_resetActiveWSA(0);
+		_screen->copyPage(2, 12);
+		waitForSubTitlesTimeout();
+		closeNestedAnimation(0);
+		setCountDown(0);
+		_updateAnimations = false;
+		break;
+
+	default:
+		break;
 	}
 
+	_callbackCurrentFrame++;
 	return 0;
 }
 
-int KyraEngine_HoF::seq_demoOuthome(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (frm) {
-	case 12:
-		seq_playTalkText(4);
+int SeqPlayer_HOF::cbHOF_hand(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	switch (_callbackCurrentFrame) {
+	case 0:
+		_updateAnimations = true;
+		_vm->sound()->playTrack(6);
+
+		assert(_screenHoF);
+		_screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
+		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+
+		_screen->setTextColorMap(_seqTextColorMap);
 		break;
 
-	case 32:
+	case 1:
+		startNestedAnimation(0, kNestedSequenceHand1a);
+		startNestedAnimation(1, kNestedSequenceHand1b);
+		startNestedAnimation(2, kNestedSequenceHand1c);
 		seq_playTalkText(7);
 		break;
 
-	case 36:
-		seq_playTalkText(10);
+	case 201:
+		waitForSubTitlesTimeout();
+		_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();
+		closeNestedAnimation(0);
+		closeNestedAnimation(1);
+		closeNestedAnimation(2);
+		startNestedAnimation(0, kNestedSequenceHand2);
+		seq_playTalkText(8);
 		break;
 
-	case 57:
+	CASE_ALT(395, 260)
+	/*case 260:
+	case 395:
+		if (!((_callbackCurrentFrame == 260 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 395 && _vm->gameFlags().platform == Common::kPlatformPC)))
+			break;*/
+
+		waitForSubTitlesTimeout();
+		closeNestedAnimation(0);
+		startNestedAnimation(1, kNestedSequenceHand3);
 		seq_playTalkText(9);
 		break;
 
-	case 80:
-	case 96:
-	case 149:
-		_seqFrameDelay = 70;
+	CASE_ALT(500, 365)
+	/*case 365:
+	case 500:
+		if (!((_callbackCurrentFrame == 365 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 500 && _vm->gameFlags().platform == Common::kPlatformPC)))
+			break;*/
+
+		waitForSubTitlesTimeout();
+		closeNestedAnimation(1);
+		startNestedAnimation(0, kNestedSequenceHand4);
 		break;
 
-	case 81:
-	case 97:
-		_seqFrameDelay = 5;
+	CASE_ALT(540, 405)
+	/*case 405:
+	case 540:
+		if (!((_callbackCurrentFrame == 405 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 540 && _vm->gameFlags().platform == Common::kPlatformPC)))
+			break;*/
+
+		seq_playTalkText(10);
 		break;
 
-	case 110:
-		seq_playTalkText(5);
+	CASE_ALT(630, 484)
+	/*case 484:
+	case 630:
+		if (!((_callbackCurrentFrame == 484 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 630 && _vm->gameFlags().platform == Common::kPlatformPC)))
+			break;*/
+
+		waitForSubTitlesTimeout();
+		closeNestedAnimation(0);
+		setCountDown(0);
+		_updateAnimations = false;
 		break;
 
-	case 137:
-		seq_playTalkText(6);
+	default:
 		break;
 	}
 
+	_callbackCurrentFrame++;
 	return 0;
 }
 
-int KyraEngine_HoF::seq_demoWharf(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (!_seqFrameCounter)
-		seq_loadNestedSequence(0, kSequenceDemoWharf2);
-
-	switch (frm) {
-	case 0:
-		seq_playTalkText(11);
-		break;
-
-	case 5:
-		if ((_seqFrameCounter / 8) <= 2 || _activeWSA[0].flags != -1)
-			_seqWsaCurrentFrame = 0;
-		else
-			seq_resetActiveWSA(0);
-		break;
+int SeqPlayer_HOF::cbHOF_point(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == -2) {
+		waitForSubTitlesTimeout();
+		setCountDown(0);
+	}
 
-	case 6:
-		seq_resetActiveWSA(0);
+	switch (_callbackCurrentFrame) {
+	case -2:
+		waitForSubTitlesTimeout();
 		break;
 
-	case 8:
-	case 10:
-		seq_playTalkText(2);
-		break;
+	case 0:
+		_vm->sound()->playTrack(7);
 
-	case 13:
-		seq_playTalkText(7);
+		_seqTextColor[1] = 0xf7;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+		_screen->setTextColorMap(_seqTextColorMap);
+		assert(_screenHoF);
+		_screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
 		break;
 
-	case 16:
-		seq_playTalkText(12);
+	case 1:
+		seq_playTalkText(11);
 		break;
 
 	default:
 		break;
 	}
 
-	_seqFrameCounter++;
+	_callbackCurrentFrame++;
 	return 0;
 }
 
-int KyraEngine_HoF::seq_demoDinob(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 0) {
-		if (!(_seqFrameCounter/8)) {
-			seq_loadNestedSequence(0, kSequenceDemoDinob2);
-			_seqWsaCurrentFrame = 0;
-		}
-	} else if (frm == 3) {
-		if (_activeWSA[0].flags != -1) {
-			_seqWsaCurrentFrame = 0;
-		} else {
-			seq_resetActiveWSA(0);
-			_screen->copyPage(2, 12);
-		}
-	} else if (frm == 4) {
-		seq_resetActiveWSA(0);
+int SeqPlayer_HOF::cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == -2) {
+		waitForSubTitlesTimeout();
+		setCountDown(0);
+		return 0;
 	}
 
-	_seqFrameCounter++;
-	return 0;
-}
-
-int KyraEngine_HoF::seq_demoFisher(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (((_system->getMillis() - _seqStartTime) / (5 * _tickLength)) > 0) {
-		_seqStartTime = _system->getMillis();
-		if (!_seqFrameCounter) {
-			seq_loadNestedSequence(0, kSequenceDemoBail);
-			seq_loadNestedSequence(1, kSequenceDemoDig);
-		}
-
-		if (_seqScrollTextCounter >= 0x18f && !_seqFrameCounter)
-			return 0;
-
-		if (!_seqFrameCounter) {
-			_screen->loadBitmap("adtext.cps", 4, 4, 0);
-			_screen->loadBitmap("adtext2.cps", 6, 6, 0);
-			_screen->copyPageMemory(6, 0, 4, 64000, 1024);
-			_screen->copyPageMemory(6, 1023, 6, 0, 64000);
-			_seqScrollTextCounter = 0;
-		}
+	switch (_callbackCurrentFrame) {
+	case 0:
+		_vm->sound()->playTrack(8);
 
-		seq_scrollPage(24, 144);
-		_seqFrameCounter++;
-		if (_seqFrameCounter < 0x256 || _seqFrameCounter > 0x31c) {
-			if (_seqFrameCounter < 0x174 || _seqFrameCounter > 0x1d7) {
-				if (_seqFrameCounter < 0x84 || _seqFrameCounter > 0xe7) {
-					_seqScrollTextCounter++;
-				}
-			}
-		}
+		_seqTextColor[1] = 0xfd;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+		_screen->setTextColorMap(_seqTextColorMap);
+		break;
 
-		if (_seqFrameCounter > 0x31e) {
-			seq_resetActiveWSA(0);
-			seq_resetActiveWSA(1);
-			_seqEndTime = 0;
-			_screen->copyPage(2, 12);
+	case 1:
+		if (_vm->gameFlags().isTalkie) {
+			seq_playWsaSyncDialogue(21, 13, -1, 140, 70, 160, wsaObj, 0, 8, x, y);
+		} else {
+			seq_setTextEntry(21, 140, 70, 200, 160);
+			_animDuration = 200;
 		}
+		break;
 
-	} else {
-		seq_scrollPage(24, 144);
-	}
-	return 0;
-}
+	case 2:
+	case 11:
+	case 21:
+		if (!_vm->gameFlags().isTalkie)
+			_animDuration = 12;
+		break;
 
-int KyraEngine_HoF::seq_demoWharf2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (frm == 69)
-		_seqWsaCurrentFrame = 8;
+	case 9:
+		if (_vm->gameFlags().isTalkie)
+			seq_playWsaSyncDialogue(13, 14, -1, 140, (_vm->gameFlags().lang == Common::FR_FRA
+				|| _vm->gameFlags().lang == Common::DE_DEU) ? 50 : 70, 160, wsaObj, 9, 15, x, y);
+		break;
 
-	return frm;
-}
+	case 10:
+		if (!_vm->gameFlags().isTalkie) {
+			waitForSubTitlesTimeout();
+			seq_setTextEntry(13, 140, 50, _textDuration[13], 160);
+			_animDuration = 300;
+		}
+		break;
 
-int KyraEngine_HoF::seq_demoDinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (frm) {
-	case 19:
-		seq_playTalkText(13);
+	case 16:
+		if (_vm->gameFlags().isTalkie)
+			seq_playWsaSyncDialogue(18, 15, -1, 140, (_vm->gameFlags().lang == Common::FR_FRA) ? 50 :
+				(_vm->gameFlags().lang == Common::DE_DEU ? 40 : 70), 160, wsaObj, 10, 16, x, y);
 		break;
 
-	case 54:
-		seq_playTalkText(15);
+	case 17:
+		if (_vm->gameFlags().isTalkie)
+			_animDuration = 12;
 		break;
 
-	case 61:
-		seq_playTalkText(16);
+	case 20:
+		if (!_vm->gameFlags().isTalkie) {
+			waitForSubTitlesTimeout();
+			seq_setTextEntry(18, 160, 50, _textDuration[18], 160);
+			_animDuration = 200;
+		}
 		break;
 
-	case 69:
-		seq_playTalkText(14);
+	case 26:
+		waitForSubTitlesTimeout();
 		break;
 
-	case 77:
-		seq_playTalkText(13);
+	case 46:
+		if (_vm->gameFlags().isTalkie) {
+			seq_playWsaSyncDialogue(16, 16, -1, 200, 50, 120, wsaObj, 46, 46, x, y);
+		} else {
+			waitForSubTitlesTimeout();
+			seq_setTextEntry(16, 200, 50, _textDuration[16], 120);
+		}
+
+		setCountDown(120);
 		break;
 
-	case 79:
-		_seqWsaCurrentFrame = 4;
+	default:
 		break;
 	}
 
+	_callbackCurrentFrame++;
+	return 0;
+}
+
+int SeqPlayer_HOF::cbHOF_over1(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 2)
+		waitForSubTitlesTimeout();
+	else if (frm == 3)
+		seq_playTalkText(12);
 	return frm;
 }
 
-int KyraEngine_HoF::seq_demoWater(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+int SeqPlayer_HOF::cbHOF_over2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	if (frm == 1)
-		seq_playTalkText(11);
+		seq_playTalkText(12);
 	return frm;
 }
 
-int KyraEngine_HoF::seq_demoBail(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+int SeqPlayer_HOF::cbHOF_forest(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 11)
+		waitForSubTitlesTimeout();
+	else if (frm == 12)
+		seq_playTalkText(2);
+
 	return frm;
 }
 
-int KyraEngine_HoF::seq_demoDig(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+int SeqPlayer_HOF::cbHOF_dragon(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 11)
+		waitForSubTitlesTimeout();
+	else if (frm == 3)
+		seq_playTalkText(3);
 	return frm;
 }
 
-#ifdef ENABLE_LOL
-int KyraEngine_HoF::seq_lolDemoScene1(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	Palette &tmpPal = _screen->getPalette(2);
-
-	if (!(_seqFrameCounter % 100)) {
-		if (_seqFrameCounter == 0) {
-			_sound->haltTrack();
-			_sound->playTrack(6);
-		}
-		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();
-		delay(8);
-	} else {
-		_screen->setScreenPalette(_screen->getPalette(0));
-		_screen->updateScreen();
-		if (_seqFrameCounter == 40)
-			seq_playTalkText(3);
-	}
+int SeqPlayer_HOF::cbHOF_darm(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	//NULLSUB (at least in FM-TOWNS version)
+	return frm;
+}
 
-	_seqFrameCounter++;
+int SeqPlayer_HOF::cbHOF_library2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
-int KyraEngine_HoF::seq_lolDemoScene2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (_seqFrameCounter - 17) {
-	case 0:
-		_seqFrameDelay = 8;
-		break;
-	case 3:
-	case 6:
-	case 9:
-		seq_playTalkText(8);
-		break;
-	case 15:
-		seq_playTalkText(9);
-		break;
-	case 18:
-		seq_playTalkText(2);
-		break;
-	default:
-		break;
+int SeqPlayer_HOF::cbHOF_marco(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 36) {
+		waitForSubTitlesTimeout();
+		setCountDown(0);
 	}
-	_seqFrameCounter++;
 	return frm;
 }
 
-int KyraEngine_HoF::seq_lolDemoScene3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (_seqFrameCounter == 1)
-		seq_playTalkText(6);
-	else if (frm == 26)
-		seq_playTalkText(7);
-
-	_seqFrameCounter++;
+int SeqPlayer_HOF::cbHOF_hand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
-int KyraEngine_HoF::seq_lolDemoScene4(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (_seqFrameCounter) {
-	case 11:
-	case 14:
-	case 17:
-	case 20:
-		seq_playTalkText(8);
-		break;
-	case 22:
-		seq_playTalkText(11);
-		break;
-	case 24:
-		seq_playTalkText(8);
-		break;
-	case 30:
-		seq_playTalkText(15);
-		break;
-	case 34:
-		seq_playTalkText(14);
-		break;
-	case 38:
-		seq_playTalkText(13);
-		break;
-	case 42:
-		seq_playTalkText(12);
-		break;
-	default:
-		break;
-	}
+int SeqPlayer_HOF::cbHOF_hand1b(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 15)
+		frm = 12;
+	return frm;
+}
 
-	_seqFrameCounter++;
+int SeqPlayer_HOF::cbHOF_hand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 8)
+		frm = 4;
 	return frm;
 }
 
-int KyraEngine_HoF::seq_lolDemoScene5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (_seqFrameCounter++) {
-	case 0:
-	case 4:
-	case 6:
-	case 8:
-	case 10:
-	case 14:
-	case 16:
-	case 18:
-	case 20:
-	case 22:
-	case 24:
-	case 26:
-	case 28:
-	case 30:
-		seq_playTalkText(15);
-		break;
-	case 32:
-		seq_playTalkText(16);
-		break;
-	case 42:
-		seq_playTalkText(6);
-		break;
-	default:
-		break;
-	}
+int SeqPlayer_HOF::cbHOF_hand2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
-int KyraEngine_HoF::seq_lolDemoText5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (_seqFrameCounter++ == 100)
-		seq_playTalkText(5);
+int SeqPlayer_HOF::cbHOF_hand3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
-int KyraEngine_HoF::seq_lolDemoScene6(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	while (_seqScrollTextCounter < 0x122) {
-		_seqEndTime = _system->getMillis() + 6 * _tickLength;
-		if (!_seqFrameCounter) {
-			_screen->loadBitmap("adtext.cps", 4, 4, 0);
-			_screen->loadBitmap("adtext2.cps", 6, 6, 0);
-			_screen->copyPageMemory(6, 0, 4, 64000, 1024);
-			_screen->copyPageMemory(6, 1023, 6, 0, 64000);
-			_seqScrollTextCounter = 0;
-		}
+int SeqPlayer_HOF::cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	uint32 frameEnd = 0;
+	int chatX = 0;
+	int chatY = 0;
+	int chatW = 0;
+	int chatFirstFrame = 0;
+	int chatLastFrame = 0;
+	uint16 voiceIndex = 0;
 
-		if (_seqFrameCounter % 175) {
-			_screen->setScreenPalette(_screen->getPalette(0));
-		} else {
-			Palette &tmpPal = _screen->getPalette(2);
-			tmpPal.copy(_screen->getPalette(0));
+	switch (frm) {
+	case -2:
+		doTransition(9);
+		break;
 
-			for (int i = 3; i < 0x300; i++) {
-				tmpPal[i] = ((int)tmpPal[i] * 120) / 64;
-				if (tmpPal[i] > 0x3f)
-					tmpPal[i] = 0x3f;
-			}
+	case 0:
+		_vm->sound()->playTrack(3);
 
-			seq_playTalkText(_rnd.getRandomBit());
-			_screen->setScreenPalette(tmpPal);
-			_screen->updateScreen();
-			delay(8);
+		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
+		_screen->setTextColorMap(_seqTextColorMap);
+
+		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+		seq_printCreditsString(81, 240, 70, _seqTextColorMap, 252);
+		seq_printCreditsString(82, 240, 90, _seqTextColorMap, _seqTextColor[0]);
+		_screen->copyPage(2, 12);
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 28 : 24);
+		delayUntil(frameEnd);
+		_seqTextColor[0] = 1;
+
+		if (_vm->gameFlags().isTalkie) {
+			chatY = (_vm->gameFlags().lang == Common::FR_FRA) ? 70 : 78;
+			chatFirstFrame = 9;
+			chatLastFrame = 15;
+			voiceIndex = 34;
+		} else {
+			chatY = (_vm->gameFlags().lang == Common::FR_FRA) ? 78 : 70;
+			chatFirstFrame = 0;
+			chatLastFrame = 8;
 		}
+		chatX = (_vm->gameFlags().lang == Common::FR_FRA) ? 84 : 88;
+		chatW = 100;
 
-		if (_seqFrameCounter == 40 || _seqFrameCounter == 80 || _seqFrameCounter == 150 || _seqFrameCounter == 300)
-			seq_playTalkText(3);
+		seq_playWsaSyncDialogue(22, voiceIndex, 187, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		break;
 
-		_screen->copyPage(12, 2);
-		seq_scrollPage(70, 130);
-		_screen->copyPage(2, 0);
-		_screen->updateScreen();
-		_seqFrameCounter++;
-		if (_seqFrameCounter < 128 || _seqFrameCounter > 207)
-			_seqScrollTextCounter++;
-		delayUntil(_seqEndTime);
-	}
-	_screen->copyPage(2, 12);
+	case 9:
+	case 16:
+		if (!((frm == 9 && !_vm->gameFlags().isTalkie) || (frm == 16 && _vm->gameFlags().isTalkie)))
+			break;
 
-	return 0;
-}
-#endif // ENABLE_LOL
+		_animDuration = 12;
 
-uint32 KyraEngine_HoF::seq_activeTextsTimeLeft() {
-	uint32 res = 0;
+		if (_vm->gameFlags().lang == Common::FR_FRA) {
+			chatX = 80;
+			chatW = 112;
+		} else {
+			chatX = (_vm->gameFlags().lang == Common::DE_DEU) ? 84 : 96;
+			chatW = 100;
+		}
 
-	for (int i = 0; i < 10; i++) {
-		uint32 chatend = (_activeText[i].duration + _activeText[i].startTime);
-		uint32 curtime = _system->getMillis();
-		if (_activeText[i].duration != -1 && chatend > curtime) {
-			chatend -= curtime;
-			if (res < chatend)
-				res = chatend;
+		if (_vm->gameFlags().isTalkie) {
+			chatFirstFrame = 0;
+			chatLastFrame = 8;
+			voiceIndex = 35;
+		} else {
+			chatFirstFrame = 9;
+			chatLastFrame = 15;
 		}
-	}
+		chatY = 70;
 
-	return res;
-}
+		seq_playWsaSyncDialogue(23, voiceIndex, 137, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		if (_vm->gameFlags().isTalkie)
+			_animCurrentFrame = 17;
+		break;
 
-void KyraEngine_HoF::seq_processWSAs() {
-	for (int i = 0; i < 8; i++) {
-		if (_activeWSA[i].flags != -1) {
-			if (seq_processNextSubFrame(i))
-				seq_resetActiveWSA(i);
-		}
+	default:
+		break;
 	}
+
+	_callbackCurrentFrame++;
+	return 0;
 }
 
-void KyraEngine_HoF::seq_processText() {
-	int curPage = _screen->setCurPage(2);
-	char outputStr[70];
+int SeqPlayer_HOF::cbHOF_ferb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	uint32 frameEnd = 0;
+	int chatX = 0;
+	int chatY = 0;
+	int chatW = 0;
+	int chatFirstFrame = 0;
+	int chatLastFrame = 0;
+	uint16 voiceIndex = 0;
 
-	for (int i = 0; i < 10; i++) {
-		if (_activeText[i].startTime + _activeText[i].duration > _system->getMillis() && _activeText[i].duration != -1) {
+	switch (frm) {
+	case -2:
+		doTransition(9);
+		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+		seq_printCreditsString(34, 240, _vm->gameFlags().isTalkie ? 60 : 40, _seqTextColorMap, 252);
+		seq_printCreditsString(35, 240, _vm->gameFlags().isTalkie ? 70 : 50, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(36, 240, _vm->gameFlags().isTalkie ? 90 : 70, _seqTextColorMap, 252);
+		seq_printCreditsString(37, 240, _vm->gameFlags().isTalkie ? 100 : 90, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(38, 240, _vm->gameFlags().isTalkie ? 120 : 110, _seqTextColorMap, 252);
+		seq_printCreditsString(39, 240, _vm->gameFlags().isTalkie ? 130 : 120, _seqTextColorMap, _seqTextColor[0]);
+		if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+			seq_printCreditsString(103, 240, 130, _seqTextColorMap, _seqTextColor[0]);
+		delayUntil(frameEnd);
+		setCountDown(0);
+		break;
 
-			char *srcStr = seq_preprocessString(_sequenceStrings[_activeText[i].strIndex], _activeText[i].width);
-			int yPos = _activeText[i].y;
+	case 0:
+		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColor[0] = _seqTextColorMap[1] = 255;
+		_screen->setTextColorMap(_seqTextColorMap);
+		break;
 
-			while (*srcStr) {
-				uint32 linePos = 0;
-				for (; *srcStr; linePos++) {
-					if (*srcStr == 0x0d) // Carriage return
-						break;
-					outputStr[linePos] = *srcStr;
-					srcStr++;
-				}
-				outputStr[linePos] = 0;
-				if (*srcStr == 0x0d)
-					srcStr++;
+	case 5:
+		if (!_vm->gameFlags().isTalkie)
+			seq_playTalkText(18);
+		_animDuration = 16;
 
-				uint8 textColor = (_activeText[i].textcolor >= 0) ? _activeText[i].textcolor : _seqTextColor[0];
-				_screen->printText(outputStr, _activeText[i].x - (_screen->getTextWidth(outputStr) / 2), yPos, textColor, 0);
-				yPos += 10;
-			}
+		if (_vm->gameFlags().isTalkie) {
+			chatFirstFrame = 5;
+			chatLastFrame = 8;
+			voiceIndex = 22;
 		} else {
-			_activeText[i].duration = -1;
+			chatLastFrame = 14;
 		}
-	}
+		chatX = 116;
+		chatY = 90;
+		chatW = 60;
 
-	_screen->setCurPage(curPage);
-}
+		seq_playWsaSyncDialogue(24, voiceIndex, 149, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		break;
 
-char *KyraEngine_HoF::seq_preprocessString(const char *srcStr, int width) {
-	char *dstStr = _seqProcessedString;
-	int lineStart = 0;
-	int linePos = 0;
+	case 11:
+		if (_vm->gameFlags().isTalkie)
+			seq_playWsaSyncDialogue(24, 22, 149, 116, 90, 60, wsaObj, 11, 14, x, y);
+		break;
 
-	while (*srcStr) {
-		while (*srcStr && *srcStr != 0x20) // Space
-			dstStr[lineStart + linePos++] = *srcStr++;
-		dstStr[lineStart + linePos] = 0;
+	case 16:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 23 : 19);
+		_animDuration = _vm->gameFlags().isTalkie ? 20 : 16;
 
-		int len = _screen->getTextWidth(&dstStr[lineStart]);
-		if (width >= len && *srcStr) {
-			dstStr[lineStart + linePos++] = *srcStr++;
+		if (_vm->gameFlags().lang == Common::FR_FRA) {
+			chatY = 48;
+			chatW = 88;
 		} else {
-			dstStr[lineStart + linePos] = 0x0d; // Carriage return
-			lineStart += linePos + 1;
-			linePos = 0;
-			if (*srcStr)
-				srcStr++;
+			chatY = 60;
+			chatW = 100;
 		}
-	}
-	dstStr[lineStart + linePos] = 0;
+		chatX = 60;
 
-	return strlen(_seqProcessedString) ? dstStr : 0;
-}
+		if (_vm->gameFlags().isTalkie)
+			voiceIndex = 36;
 
-void KyraEngine_HoF::seq_sequenceCommand(int command) {
-	for (int i = 0; i < 8; i++)
-		seq_resetActiveWSA(i);
+		seq_playWsaSyncDialogue(25, voiceIndex, 143, chatX, chatY, chatW, wsaObj, 16, 25, x, y);
+		_animDuration = 16;
+		break;
 
-	switch (command) {
-	case 0:
-		_screen->fadeToBlack(36);
-		_screen->getPalette(0).clear();
-		_screen->getPalette(1).clear();
+	default:
 		break;
+	}
 
-	case 1:
-		seq_playTalkText(_rnd.getRandomBit());
+	_callbackCurrentFrame++;
+	return 0;
+}
 
-		_screen->getPalette(0).fill(0, 256, 0x3F);
-		_screen->fadePalette(_screen->getPalette(0), 16);
+int SeqPlayer_HOF::cbHOF_fish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	uint32 frameEnd = 0;
+	int chatX = 0;
+	int chatY = 0;
+	int chatW = 0;
+	uint16 voiceIndex = 0;
 
-		_screen->copyPalette(1, 0);
+	switch (frm) {
+	case -2:
+		doTransition(9);
+		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+
+		seq_printCreditsString(40, 240, _vm->gameFlags().isTalkie ? 55 : 40, _seqTextColorMap, 252);
+		seq_printCreditsString(41, 240, _vm->gameFlags().isTalkie ? 65 : 50, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(42, 240, _vm->gameFlags().isTalkie ? 75 : 60, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(43, 240, _vm->gameFlags().isTalkie ? 95 : 80, _seqTextColorMap, 252);
+		seq_printCreditsString(44, 240, _vm->gameFlags().isTalkie ? 105 : 90, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(93, 240, _vm->gameFlags().isTalkie ? 125 : 110, _seqTextColorMap, 252);
+		seq_printCreditsString(94, 240, _vm->gameFlags().isTalkie ? 135 : 120, _seqTextColorMap, _seqTextColor[0]);
+		delayUntil(frameEnd);
+		setCountDown(0);
 		break;
 
-	case 3:
-		_screen->copyPage(2, 0);
-		_screen->fadePalette(_screen->getPalette(0), 16);
-		_screen->copyPalette(1, 0);
+	case 0:
+		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
+		_screen->setTextColorMap(_seqTextColorMap);
 		break;
 
 	case 4:
-		_screen->copyPage(2, 0);
-		_screen->fadePalette(_screen->getPalette(0), 36);
-		_screen->copyPalette(1, 0);
+		chatX = 94;
+		chatY = 42;
+		chatW = 100;
+		if (_vm->gameFlags().isTalkie)
+			voiceIndex = 37;
+		seq_playWsaSyncDialogue(26, voiceIndex, 149, chatX, chatY, chatW, wsaObj, 3, 12, x, y);
 		break;
 
-	case 5:
-		_screen->copyPage(2, 0);
+	case 14:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 19 : 15);
 		break;
 
-	case 6:
-		// UNUSED
-		// seq_loadBLD("library.bld");
+	case 23:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 20 : 16);
 		break;
 
-	case 7:
-		// UNUSED
-		// seq_loadBLD("marco.bld");
-		break;
+	case 29:
+		chatX = (_vm->gameFlags().lang == Common::DE_DEU) ? 82 : ((_vm->gameFlags().lang == Common::FR_FRA) ? 92 : 88);
+		chatY = 40;
+		chatW = 100;
 
-	case 8:
-		_screen->fadeToBlack(16);
-		_screen->getPalette(0).clear();
-		_screen->getPalette(1).clear();
+		if (_vm->gameFlags().isTalkie) {
+			if (_vm->gameFlags().lang == Common::DE_DEU)
+				chatY = 35;
+			voiceIndex = 38;
+		}
 
-		delay(120 * _tickLength);
+		seq_playWsaSyncDialogue(27, voiceIndex, 187, chatX, chatY, chatW, wsaObj, 28, 34, x, y);
 		break;
 
-	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;
-		}
-
-		//int a = 0x100;
-		//int d = (0x800 << 5) - 0x100;
-		//pal[3 * i] = pal[3 * i + 1] = pal[3 * i + 2] = 0x3f;
+	case 45:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 21 : 17);
+		break;
 
-		_screen->fadePalette(pal, 64);
-		_screen->copyPalette(1, 0);
-		} break;
+	case 50:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 29 : 25);
+		break;
 
 	default:
 		break;
 	}
-}
-
-void KyraEngine_HoF::seq_cmpFadeFrame(const char *cmpFile) {
-	_screen->copyPage(10, 2);
-	_screen->copyPage(4, 10);
-	_screen->clearPage(6);
-	_screen->loadBitmap(cmpFile, 6, 6, 0);
-	_screen->copyPage(12, 4);
-
-	for (int i = 0; i < 3; i++) {
-		uint32 endtime = _system->getMillis() + 4 * _tickLength;
-		_screen->cmpFadeFrameStep(4, 320, 200, 0, 0, 2, 320, 200, 0, 0, 320, 200, 6);
-		_screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0);
-		_screen->updateScreen();
-		delayUntil(endtime);
-	}
 
-	_screen->copyPage(4, 0);
-	_screen->updateScreen();
-	_screen->copyPage(4, 2);
-	_screen->copyPage(4, 6);
-	_screen->copyPage(10, 4);
+	_callbackCurrentFrame++;
+	return 0;
 }
 
-void KyraEngine_HoF::seq_playTalkText(uint8 chatNum) {
-	assert(chatNum < _sequenceSoundListSize);
-
-	if (chatNum < 12 && !_flags.isDemo && textEnabled())
-		seq_setTextEntry(chatNum, 160, 168, _sequenceStringsDuration[chatNum], 160);
+int SeqPlayer_HOF::cbHOF_fheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	uint32 frameEnd = 0;
+	int chatX = 0;
+	int chatY = 0;
+	int chatW = 0;
+	int chatFirstFrame = 0;
+	int chatLastFrame = 0;
+	uint16 voiceIndex = 0;
 
-	_sound->voicePlay(_sequenceSoundList[chatNum], &_speechHandle);
-}
+	switch (frm) {
+	case -2:
+		_screen->copyPage(12, 2);
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		doTransition(9);
+		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+		seq_printCreditsString(49, 240, 20, _seqTextColorMap, 252);
+		seq_printCreditsString(50, 240, 30, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(51, 240, 40, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(52, 240, 50, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(53, 240, 60, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(54, 240, 70, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(55, 240, 80, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(56, 240, 90, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(57, 240, 100, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(58, 240, 110, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(60, 240, 120, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(61, 240, 130, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(62, 240, 140, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(63, 240, 150, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(64, 240, 160, _seqTextColorMap, _seqTextColor[0]);
 
-void KyraEngine_HoF::seq_waitForTextsTimeout() {
-	uint32 longest = seq_activeTextsTimeLeft() + _system->getMillis();
-	uint32 now = _system->getMillis();
+		delayUntil(frameEnd);
+		setCountDown(0);
+		break;
 
-	if (textEnabled()) {
-		if (longest > now)
-			delay(longest - now);
-	} else if (speechEnabled()) {
-		while (snd_voiceIsPlaying())
-			delay(_tickLength);
-	}
+	case 0:
+		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
+		_screen->setTextColorMap(_seqTextColorMap);
+		break;
 
-	seq_resetAllTextEntries();
-}
+	case 2:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 25 : 21);
 
-void KyraEngine_HoF::seq_resetAllTextEntries() {
-	for (int i = 0; i < 10; i++)
-		_activeText[i].duration = -1;
-}
+		if (_vm->gameFlags().lang == Common::FR_FRA) {
+			chatX = 92;
+			chatY = 72;
+		} else {
+			chatX = (_vm->gameFlags().lang == Common::DE_DEU) ? 90 : 98;
+			chatY = 84;
+		}
 
-int KyraEngine_HoF::seq_setTextEntry(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width) {
-	for (int i = 0; i < 10; i++) {
-		if (_activeText[i].duration != -1) {
-			if (i < 9)
-				continue;
-			else
-				return -1;
+		if (_vm->gameFlags().isTalkie) {
+			chatFirstFrame = 8;
+			chatLastFrame = 9;
+			voiceIndex = 39;
+		} else {
+			chatFirstFrame = 2;
+			chatLastFrame = -8;
 		}
+		chatW = 100;
+
+		seq_playWsaSyncDialogue(28, voiceIndex, -1, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		if (_vm->gameFlags().isTalkie)
+			_animCurrentFrame = 4;
+		break;
 
-		_activeText[i].strIndex = strIndex;
-		_activeText[i].x = posX;
-		_activeText[i].y = posY;
-		_activeText[i].duration = duration * _tickLength;
-		_activeText[i].width = width;
-		_activeText[i].startTime = _system->getMillis();
-		_activeText[i].textcolor = -1;
+	case 9:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 24 : 20);
+		_animDuration = 100;
+		break;
 
-		return i;
+	default:
+		break;
 	}
-	return -1;
+
+	_callbackCurrentFrame++;
+	return 0;
 }
 
-void KyraEngine_HoF::seq_loadNestedSequence(int wsaNum, int seqNum) {
-	if (_activeWSA[wsaNum].flags != -1)
-		return;
+int SeqPlayer_HOF::cbHOF_farmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	uint32 frameEnd = 0;
+	int chatX = 0;
+	int chatY = 0;
+	int chatW = 0;
+	uint16 voiceIndex = 0;
+
+	switch (frm) {
+	case -2:
+		_screen->copyPage(12, 2);
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		doTransition(9);
+		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+		seq_printCreditsString(45, 240, 40, _seqTextColorMap, 252);
+		seq_printCreditsString(46, 240, 50, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(47, 240, 60, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(83, 240, 80, _seqTextColorMap, 252);
+		seq_printCreditsString(48, 240, 90, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(65, 240, 110, _seqTextColorMap, 252);
+		seq_printCreditsString(66, 240, 120, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(67, 240, 130, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(68, 240, 140, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(69, 240, 150, _seqTextColorMap, _seqTextColor[0]);
+		if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+			seq_printCreditsString(104, 240, 160, _seqTextColorMap, _seqTextColor[0]);
+		delayUntil(frameEnd);
+		setCountDown(0);
+		break;
 
-	NestedSequence s = _sequences->seqn[seqNum];
+	case 0:
+		_seqTextColor[1] = 1 + (_screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 254) & 0xff);
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColorMap[1] = _seqTextColor[0] = 1 + (_screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 254) & 0xff);
+		_screen->setTextColorMap(_seqTextColorMap);
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 30 : 26);
+		break;
 
-	if (!_activeWSA[wsaNum].movie) {
-		_activeWSA[wsaNum].movie = new WSAMovie_v2(this);
-		assert(_activeWSA[wsaNum].movie);
-	}
+	case 6:
+		if (_vm->gameFlags().isTalkie)
+			seq_playTalkText(18);
+		break;
 
-	_activeWSA[wsaNum].movie->close();
+	case 12:
+		if (!_vm->gameFlags().isTalkie)
+			seq_playTalkText(14);
 
-	_activeWSA[wsaNum].movie->open(s.wsaFile, 0, 0);
+		chatX = 90;
+		chatY = 30;
+		chatW = 100;
 
-	if (!_activeWSA[wsaNum].movie->opened()) {
-		delete _activeWSA[wsaNum].movie;
-		_activeWSA[wsaNum].movie = 0;
-		return;
-	}
+		if (_vm->gameFlags().isTalkie) {
+			if (_vm->gameFlags().lang == Common::FR_FRA || _vm->gameFlags().lang == Common::DE_DEU) {
+				chatX = 75;
+				chatY = 25;
+			}
+			voiceIndex = 40;
+		}
 
-	_activeWSA[wsaNum].endFrame = s.endFrame;
-	_activeWSA[wsaNum].startFrame = _activeWSA[wsaNum].currentFrame = s.startframe;
-	_activeWSA[wsaNum].frameDelay = s.frameDelay;
-	_activeWSA[wsaNum].callback = _callbackN[seqNum];
-	_activeWSA[wsaNum].control = s.wsaControl;
+		seq_playWsaSyncDialogue(29, voiceIndex, 150, chatX, chatY, chatW, wsaObj, 12, -21, x, y);
+		break;
 
-	_activeWSA[wsaNum].flags = s.flags | 1;
-	_activeWSA[wsaNum].x = s.x;
-	_activeWSA[wsaNum].y = s.y;
-	_activeWSA[wsaNum].startupCommand = s.startupCommand;
-	_activeWSA[wsaNum].finalCommand = s.finalCommand;
-	_activeWSA[wsaNum].lastFrame = 0xffff;
+	default:
+		break;
+	}
 
-	seq_nestedSequenceFrame(s.startupCommand, wsaNum);
+	_callbackCurrentFrame++;
+	return 0;
+}
 
-	if (!s.startupCommand)
-		seq_processNextSubFrame(wsaNum);
+int SeqPlayer_HOF::cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	uint32 frameEnd = 0;
+	int chatX = 0;
+	int chatY = 0;
+	int chatW = 0;
+	int chatFirstFrame = 0;
+	int chatLastFrame = 0;
+	//int textCol = 0;
 
-	_activeWSA[wsaNum].nextFrame = _system->getMillis();
-}
+	uint16 voiceIndex = 0;
 
-void KyraEngine_HoF::seq_nestedSequenceFrame(int command, int wsaNum) {
-	int xa = 0, ya = 0;
-	command--;
-	if (!_activeWSA[wsaNum].movie || skipFlag() || shouldQuit() || _abortIntroFlag)
-		return;
+	switch (frm) {
+	case -2:
+		doTransition(9);
+		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+		seq_printCreditsString(70, 240, 20, _seqTextColorMap, 252);
+		seq_printCreditsString(71, 240, 30, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(72, 240, 40, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(73, 240, 50, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(74, 240, 60, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(75, 240, 70, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(101, 240, 80, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(102, 240, 90, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(87, 240, 100, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(88, 240, 110, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(89, 240, 120, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(90, 240, 130, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(91, 240, 140, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(92, 240, 150, _seqTextColorMap, _seqTextColor[0]);
+		delayUntil(frameEnd);
+		setCountDown(0);
+		break;
 
-	switch (command) {
 	case 0:
-		xa = -_activeWSA[wsaNum].movie->xAdd();
-		ya = -_activeWSA[wsaNum].movie->yAdd();
-		_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;
+		for (int i = 0; i < 0x300; i++)
+			_screen->getPalette(0)[i] &= 0x3f;
+		_seqTextColor[1] = 0xCf;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColor[0] = _seqTextColorMap[1] = 0xfe;
 
-	case 1:
-		xa = -_activeWSA[wsaNum].movie->xAdd();
-		ya = -_activeWSA[wsaNum].movie->yAdd();
-		_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);
+		_screen->setTextColorMap(_seqTextColorMap);
 		break;
 
-	case 2:
-		seq_waitForTextsTimeout();
-		xa = -_activeWSA[wsaNum].movie->xAdd();
-		ya = -_activeWSA[wsaNum].movie->yAdd();
-		_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 6:
+		_animDuration = 20;
 
-	case 3:
-		_screen->copyPage(2, 10);
-		_activeWSA[wsaNum].movie->displayFrame(0, 2, 0, 0, 0, 0, 0);
-		_screen->copyPage(2, 12);
-		seq_cmpFadeFrame("scene2.cmp");
+		if (_vm->gameFlags().isTalkie) {
+			chatX = 82;
+			//textCol = 143;
+			chatFirstFrame = 16;
+			chatLastFrame = 21;
+			voiceIndex = 41;
+		} else {
+			chatX = 62;
+			//textCol = 137;
+			chatFirstFrame = 9;
+			chatLastFrame = 13;
+		}
+		chatY = (_vm->gameFlags().lang == Common::FR_FRA || _vm->gameFlags().lang == Common::DE_DEU) ? 88 :100;
+		chatW = 80;
+
+		seq_playWsaSyncDialogue(30, voiceIndex, 137, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		if (_vm->gameFlags().isTalkie)
+			_animCurrentFrame = 8;
 		break;
 
-	case 4:
-		_screen->copyPage(2, 10);
-		_activeWSA[wsaNum].movie->displayFrame(0, 2, 0, 0, 0, 0, 0);
-		_screen->copyPage(2, 12);
-		seq_cmpFadeFrame("scene3.cmp");
+	case 9:
+	case 16:
+		if (_vm->gameFlags().isTalkie) {
+			if (frm == 16)
+				break;
+			chatX = 64;
+			//textCol = 137;
+			chatFirstFrame = 9;
+			chatLastFrame = 13;
+			voiceIndex = 42;
+		} else {
+			if (frm == 9)
+				break;
+			chatX = 80;
+			//textCol = 143;
+			chatFirstFrame = 16;
+			chatLastFrame = 21;
+		}
+		chatY = 100;
+		chatW = 100;
+
+		seq_playWsaSyncDialogue(31, voiceIndex, 143, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		if (_vm->gameFlags().isTalkie)
+			_animCurrentFrame = 21;
 		break;
 
 	default:
 		break;
 	}
+
+	_callbackCurrentFrame++;
+	return 0;
 }
 
-void KyraEngine_HoF::seq_animatedSubFrame(int srcPage, int dstPage, int delaytime, int steps,
-                                         int x, int y, int w, int h, int openClose, int directionFlags) {
-	if (openClose) {
-		for (int i = 1; i < steps; i++) {
-			uint32 endtime = _system->getMillis() + delaytime * _tickLength;
+int SeqPlayer_HOF::cbHOF_firates(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	uint32 frameEnd = 0;
+	int chatX = 0;
+	int chatY = 0;
+	int chatW = 0;
+	uint16 voiceIndex = 0;
 
-			int w2 = (((w * 256) / steps) * i) / 256;
-			int h2 = (((h * 256) / steps) * i) / 256;
+	switch (frm) {
+	case -2:
+		_screen->copyPage(12, 2);
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		doTransition(9);
+		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
+		seq_printCreditsString(76, 240, 40, _seqTextColorMap, 252);
+		seq_printCreditsString(77, 240, 50, _seqTextColorMap, 252);
+		seq_printCreditsString(78, 240, 60, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(79, 240, 70, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(80, 240, 80, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(84, 240, 100, _seqTextColorMap, 252);
+		seq_printCreditsString(85, 240, 110, _seqTextColorMap, _seqTextColor[0]);
+		seq_printCreditsString(99, 240, 130, _seqTextColorMap, 252);
+		seq_printCreditsString(100, 240, 140, _seqTextColorMap, _seqTextColor[0]);
+		delayUntil(frameEnd);
+		setCountDown(0);
+		break;
 
-			int ym = (directionFlags & 2) ? (h - h2) : 0;
-			int xm = (directionFlags & 1) ? (w - w2) : 0;
+	case 0:
+		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_seqTextColorMap, _seqTextColor[1], 16);
+		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
+		_screen->setTextColorMap(_seqTextColorMap);
+		break;
 
-			_screen->wsaFrameAnimationStep(0, 0, x + xm, y + ym, w, h, w2, h2, srcPage, dstPage, 0);
+	case 6:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 31 : 27);
+		break;
 
-			_screen->copyPage(dstPage, 6);
-			_screen->copyPage(dstPage, 0);
-			_screen->updateScreen();
+	case 14:
+	case 15:
+		if (!((frm == 15 && !_vm->gameFlags().isTalkie) || (frm == 14 && _vm->gameFlags().isTalkie)))
+			break;
 
-			_screen->copyPage(12, dstPage);
-			delayUntil(endtime);
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 31 : 27);
+
+		if (_vm->gameFlags().lang == Common::DE_DEU) {
+			chatX = 82;
+			chatY = 84;
+			chatW = 140;
+		} else {
+			chatX = 74;
+			chatY = (_vm->gameFlags().lang == Common::FR_FRA) ? 96: 108;
+			chatW = 80;
 		}
 
-		_screen->wsaFrameAnimationStep(0, 0, x, y, w, h, w, h, srcPage, dstPage, 0);
-		_screen->copyPage(dstPage, 6);
-		_screen->copyPage(dstPage, 0);
-		_screen->updateScreen();
-	} else {
-		_screen->copyPage(12, dstPage);
-		for (int i = steps; i; i--) {
-			uint32 endtime = _system->getMillis() + delaytime * _tickLength;
+		if (_vm->gameFlags().isTalkie)
+			voiceIndex = 43;
 
-			int w2 = (((w * 256) / steps) * i) / 256;
-			int h2 = (((h * 256) / steps) * i) / 256;
+		seq_playWsaSyncDialogue(32, voiceIndex, 137, chatX, chatY, chatW, wsaObj, 14, 16, x, y);
+		break;
 
-			int ym = (directionFlags & 2) ? (h - h2) : 0;
-			int xm = (directionFlags & 1) ? (w - w2) : 0;
+	case 28:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 32 : 28);
+		break;
 
-			_screen->wsaFrameAnimationStep(0, 0, x + xm, y + ym, w, h, w2, h2, srcPage, dstPage, 0);
+	case 29:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 33 : 29);
+		break;
 
-			_screen->copyPage(dstPage, 6);
-			_screen->copyPage(dstPage, 0);
-			_screen->updateScreen();
+	case 31:
+		if (_vm->gameFlags().isTalkie)
+			voiceIndex = 44;
 
-			_screen->copyPage(12, dstPage);
-			delayUntil(endtime);
-		}
-	}
-}
+		chatX = 90;
+		chatY = (_vm->gameFlags().lang == Common::DE_DEU) ? 60 : 76;
+		chatW = 80;
 
-void KyraEngine_HoF::seq_resetActiveWSA(int wsaNum) {
-	if (_activeWSA[wsaNum].flags == -1)
-		return;
+		seq_playWsaSyncDialogue(33, voiceIndex, 143, chatX, chatY, chatW, wsaObj, 31, 34, x, y);
+		break;
 
-	_activeWSA[wsaNum].flags = -1;
-	seq_nestedSequenceFrame(_activeWSA[wsaNum].finalCommand, wsaNum);
-	_activeWSA[wsaNum].movie->close();
-}
+	case 35:
+		_animDuration = 300;
+		break;
 
-void KyraEngine_HoF::seq_unloadWSA(int wsaNum) {
-	if (_activeWSA[wsaNum].movie) {
-		_activeWSA[wsaNum].movie->close();
-		delete _activeWSA[wsaNum].movie;
-		_activeWSA[wsaNum].movie = 0;
+	default:
+		break;
 	}
+
+	_callbackCurrentFrame++;
+	return 0;
 }
 
-bool KyraEngine_HoF::seq_processNextSubFrame(int wsaNum) {
-	uint32 currentFrame = _activeWSA[wsaNum].currentFrame;
-	uint32 currentTime = _system->getMillis();
+int SeqPlayer_HOF::cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	int tmp = 0;
 
-	if (_activeWSA[wsaNum].callback && currentFrame != _activeWSA[wsaNum].lastFrame) {
-		_activeWSA[wsaNum].lastFrame = currentFrame;
-		currentFrame = (this->*_activeWSA[wsaNum].callback)(_activeWSA[wsaNum].movie, _activeWSA[wsaNum].x, _activeWSA[wsaNum].y, currentFrame);
-	}
+	switch (frm) {
+	case -2:
+		_screen->setCurPage(2);
+		_screen->clearCurPage();
+		_screen->copyPage(2, 12);
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		_callbackCurrentFrame = 0;
+		startNestedAnimation(0, kNestedSequenceFiggle);
+		break;
 
-	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, 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, 0, 0);
+	case -1:
+		if (_vm->gameFlags().isTalkie)
+			 seq_finaleActorScreen();
+		_talkieFinaleExtraFlag = _vm->gameFlags().isTalkie;
+		break;
+
+	case 0:
+		if (_callbackCurrentFrame == 1) {
+			_vm->sound()->playTrack(4);
+			_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+			memset(_seqTextColorMap, _seqTextColor[1], 16);
+			_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
+			_screen->setTextColorMap(_seqTextColorMap);
 		}
-	}
+		_animDuration = 10;
+		break;
 
-	if (_activeWSA[wsaNum].flags & 0x10) {
-		currentFrame = (currentTime - _activeWSA[wsaNum].nextFrame) / (_activeWSA[wsaNum].frameDelay * _tickLength);
-	} else {
-		if (((int32)(currentTime - _activeWSA[wsaNum].nextFrame) / (int32)(_activeWSA[wsaNum].frameDelay * _tickLength)) > 0) {
-			currentFrame++;
-			_activeWSA[wsaNum].nextFrame = currentTime;
+	case 1:
+		if (_callbackCurrentFrame < 20 && _talkieFinaleExtraFlag) {
+			_animCurrentFrame = 0;
+		} else {
+			_animDuration = _vm->gameFlags().isTalkie ? 500 : (300 + _vm->_rnd.getRandomNumberRng(1, 300));
+			seq_playTalkText(_vm->gameFlags().isTalkie ? 26 : 22);
+			if (_talkieFinaleExtraFlag) {
+				_callbackCurrentFrame = 3;
+				_talkieFinaleExtraFlag = false;
+			}
 		}
-	}
+		break;
 
-	bool res = false;
+	case 2:
+		_animDuration = 20;
+		break;
 
-	if (currentFrame >= _activeWSA[wsaNum].endFrame) {
-		int sw = ((_activeWSA[wsaNum].flags & 0x1e) - 2);
-		switch (sw) {
-		case 0:
-			res = true;
-			currentFrame = _activeWSA[wsaNum].endFrame;
-			_screen->copyPage(2, 12);
-			break;
+	case 3:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 27 : 23);
+		_animDuration = _vm->gameFlags().isTalkie ? 500 : (300 + _vm->_rnd.getRandomNumberRng(1, 300));
+		break;
 
-		case 6:
-		case 8:
-			currentFrame = _activeWSA[wsaNum].endFrame - 1;
-			break;
+	case 4:
+		_animDuration = 10;
+		break;
+
+	case 5:
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 27 : 23);
+		tmp = _callbackCurrentFrame / 6;
+		if (tmp == 2)
+			_animDuration = _vm->gameFlags().isTalkie ? 7 : (1 + _vm->_rnd.getRandomNumberRng(1, 10));
+		else if (tmp < 2)
+			_animDuration = _vm->gameFlags().isTalkie ? 500 : (300 + _vm->_rnd.getRandomNumberRng(1, 300));
+		break;
+
+	case 6:
+		_animDuration = 10;
+		tmp = _callbackCurrentFrame / 6;
+		if (tmp == 2)
+			_animCurrentFrame = 4;
+		else if (tmp < 2)
+			_animCurrentFrame = 0;
+		break;
+
+	case 7:
+		_callbackCurrentFrame = 0;
+		_animDuration = 5;
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 26 : 22);
+		break;
 
-		case 2:
-		case 10:
-			currentFrame = _activeWSA[wsaNum].startFrame;
-			break;
+	case 11:
+		if (_callbackCurrentFrame < 8)
+			_animCurrentFrame = 8;
+		break;
 
-		default:
-			currentFrame = _activeWSA[wsaNum].endFrame - 1;
-			res = true;
-		}
+	default:
+		break;
 	}
 
-	_activeWSA[wsaNum].currentFrame = currentFrame & 0xffff;
-	return res;
+	_callbackCurrentFrame++;
+	return 0;
 }
 
-void KyraEngine_HoF::seq_printCreditsString(uint16 strIndex, int x, int y, const uint8 *colorMap, uint8 textcolor) {
-	uint8 colormap[16];
-	if (skipFlag() || shouldQuit() || _abortIntroFlag || _menuChoice)
-		return;
-
-	Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
-
-	memset(&_screen->getPalette(0)[0x2fa], 0x3f, 6);
-	_screen->getPalette(0)[0x2f6] = 0x3f;
-	_screen->getPalette(0)[0x2f5] = 0x20;
-	_screen->getPalette(0)[0x2f4] = 0x30;
-	colormap[0] = colorMap[0];
-	colormap[1] = 0xfd;
-	memcpy(&colormap[2], &colorMap[2], 14);
-	uint8 seqTextColor0 = _seqTextColor[0];
-
-	_seqTextColor[0] = 0xfd;
-	_screen->setTextColorMap(colormap);
-	seq_resetAllTextEntries();
-	seq_setTextEntry(strIndex, x, y, 0x80, 0x78);
-	seq_processText();
-	_screen->copyPage(2, 0);
-	_screen->updateScreen();
-	_screen->getPalette(0)[0x2f7] = _screen->getPalette(0)[textcolor * 3];
-	_screen->getPalette(0)[0x2f8] = _screen->getPalette(0)[textcolor * 3 + 1];
-	_screen->getPalette(0)[0x2f9] = _screen->getPalette(0)[textcolor * 3 + 2];
-	_screen->fadePalette(_screen->getPalette(0), 0x18);
+int SeqPlayer_HOF::cbHOF_figgle(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (_callbackCurrentFrame == 10)
+		setCountDown(0);
+	if (_callbackCurrentFrame == 10 || _callbackCurrentFrame == 5 || _callbackCurrentFrame == 7)
+		seq_playTalkText(_vm->gameFlags().isTalkie ? 45 : 30);
 
-	_seqTextColor[0] = textcolor;
-	_screen->setTextColorMap(colorMap);
-	seq_resetAllTextEntries();
-	seq_setTextEntry(strIndex, x, y, 0x80, 0x78);
-	seq_processText();
-	_screen->copyPage(2, 0);
-	_screen->updateScreen();
-	_screen->getPalette(0)[0x2f7] = _screen->getPalette(0)[0x2f8] = _screen->getPalette(0)[0x2f9] = 0;
-	_screen->fadePalette(_screen->getPalette(0), 1);
-	_screen->copyPage(2, 12);
-	seq_resetAllTextEntries();
+	_callbackCurrentFrame++;
+	return frm;
+}
 
-	_seqTextColor[0] = seqTextColor0;
+int SeqPlayer_HOF::cbHOFDEMO_virgin(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (!frm)
+		delayTicks(50);
+	return 0;
+}
 
-	_screen->setFont(of);
+int SeqPlayer_HOF::cbHOFDEMO_westwood(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (!frm)
+		_vm->sound()->playTrack(2);
+	return 0;
 }
 
-void KyraEngine_HoF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, int textColor, int x, int y, int width, WSAMovie_v2 *wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos) {
-	int dur = int(strlen(_sequenceStrings[strIndex])) * (_flags.isTalkie ? 7 : 15);
-	if (textEnabled()) {
-		int entry = seq_setTextEntry(strIndex, x, y, dur, width);
-		_activeText[entry].textcolor = textColor;
+int SeqPlayer_HOF::cbHOFDEMO_title(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (!frm) {
+		_vm->sound()->playTrack(3);
+	} else if (frm == 25) {
+		delayTicks(60);
+		setCountDown(0);
+		doTransition(0);
 	}
-	_seqWsaChatTimeout = _system->getMillis() + dur * _tickLength;
-	int curframe = firstframe;
+	return 0;
+}
 
-	if (vocIndex && speechEnabled()) {
-		while (_sound->voiceIsPlaying() && !skipFlag())
-			delay(4);
-		seq_playTalkText(vocIndex);
+int SeqPlayer_HOF::cbHOFDEMO_hill(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (!frm) {
+		_vm->sound()->playTrack(4);
+	} else if (frm == 25) {
+		startNestedAnimation(0, kNestedSequenceHoFDemoWater);
+		_animDuration--;
+	} else if (frm > 25 && frm < 50) {
+		if (_animDuration > 3)
+			_animDuration--;
+	} else if (frm == 95) {
+		_animDuration = 70;
+	} else if (frm == 96) {
+		_animDuration = 7;
+	} else if (frm == 129) {
+		closeNestedAnimation(0);
 	}
 
-	while (_system->getMillis() < _seqWsaChatTimeout && !(_abortIntroFlag || skipFlag())) {
-		if (lastframe < 0) {
-			int t = ABS(lastframe);
-			if (t < curframe)
-				curframe = t;
-		}
+	return 0;
+}
 
-		if (ABS(lastframe) < curframe)
-			curframe = firstframe;
+int SeqPlayer_HOF::cbHOFDEMO_outhome(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	switch (frm) {
+	case 12:
+		seq_playTalkText(4);
+		break;
 
-		_seqWsaChatFrameTimeout = _seqEndTime = _system->getMillis() + _seqFrameDelay * _tickLength;
-		if (wsa)
-			wsa->displayFrame(curframe % wsa->frames(), 2, wsaXpos, wsaYpos, 0, 0, 0);
+	case 32:
+		seq_playTalkText(7);
+		break;
 
-		_screen->copyPage(2, 12);
+	case 36:
+		seq_playTalkText(10);
+		break;
 
-		seq_processText();
+	case 57:
+		seq_playTalkText(9);
+		break;
 
-		uint32 tm = _system->getMillis();
-		if (_seqWsaChatFrameTimeout > tm && _seqWsaChatTimeout > tm)
-			delay(MIN(_seqWsaChatFrameTimeout - tm, _seqWsaChatTimeout - tm));
+	case 80:
+	case 96:
+	case 149:
+		_animDuration = 70;
+		break;
 
-		if (speechEnabled() && !textEnabled() && !snd_voiceIsPlaying())
-			break;
+	case 81:
+	case 97:
+		_animDuration = 5;
+		break;
 
-		_screen->copyPage(2, 0);
-		_screen->updateScreen();
-		curframe++;
+	case 110:
+		seq_playTalkText(5);
+		break;
+
+	case 137:
+		seq_playTalkText(6);
+		break;
 	}
 
-	if (_abortIntroFlag || skipFlag())
-		_sound->voiceStop();
+	return 0;
+}
 
-	if (ABS(lastframe) < curframe)
-		curframe = ABS(lastframe);
+int SeqPlayer_HOF::cbHOFDEMO_wharf(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (!_callbackCurrentFrame)
+		startNestedAnimation(0, kNestedSequenceHoFDemoWharf2);
 
-	if (curframe == firstframe)
-		curframe++;
+	switch (frm) {
+	case 0:
+		seq_playTalkText(11);
+		break;
 
-	_seqWsaCurrentFrame = curframe;
-}
+	case 5:
+		if ((_callbackCurrentFrame / 8) <= 2 || _animSlots[0].flags != -1)
+			_animCurrentFrame = 0;
+		else
+			closeNestedAnimation(0);
+		break;
 
-void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed,
-	int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData, const char *const *specialData) {
-	if (!data)
-		return;
+	case 6:
+		closeNestedAnimation(0);
+		break;
 
-	static const char mark[] = { 5, 13, 0 };
+	case 8:
+	case 10:
+		seq_playTalkText(2);
+		break;
 
-	_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);
+	case 13:
+		seq_playTalkText(7);
+		break;
 
-	struct ScrollTextData {
-		int16	x;
-		int16	y;
-		uint8	*text;
-		byte	unk1;
-		byte	height;
-		byte	adjust;
+	case 16:
+		seq_playTalkText(12);
+		break;
 
-		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
-		}
-	};
+	default:
+		break;
+	}
 
-	ScrollTextData *textData = new ScrollTextData[36];
-	uint8 *ptr = data;
+	_callbackCurrentFrame++;
+	return 0;
+}
 
-	bool loop = true;
-	int cnt = 0;
+int SeqPlayer_HOF::cbHOFDEMO_dinob(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 0) {
+		if (!(_callbackCurrentFrame/8)) {
+			startNestedAnimation(0, kNestedSequenceHoFDemoDinob2);
+			_animCurrentFrame = 0;
+		}
+	} else if (frm == 3) {
+		if (_animSlots[0].flags != -1) {
+			_animCurrentFrame = 0;
+		} else {
+			closeNestedAnimation(0);
+			_screen->copyPage(2, 12);
+		}
+	} else if (frm == 4) {
+		closeNestedAnimation(0);
+	}
 
-	while (loop) {
-		_seqSubFrameEndTimeInternal = _system->getMillis() + speed * _tickLength;
+	_callbackCurrentFrame++;
+	return 0;
+}
 
-		while (cnt < 35 && *ptr) {
-			uint16 cH;
+int SeqPlayer_HOF::cbHOFDEMO_fisher(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (((_system->getMillis() - _fisherAnimCurTime) / (5 * _vm->tickLength())) > 0) {
+		_fisherAnimCurTime = _system->getMillis();
+		if (!_callbackCurrentFrame) {
+			startNestedAnimation(0, kNestedSequenceHoFDemoBail);
+			startNestedAnimation(1, kNestedSequenceHoFDemoDig);
+		}
 
-			if (cnt)
-				cH = textData[cnt].y + textData[cnt].height + (textData[cnt].height >> 3);
-			else
-				cH = d->h;
+		if (_seqScrollTextCounter >= 0x18f && !_callbackCurrentFrame)
+			return 0;
 
-			char *str = (char *)ptr;
+		if (!_callbackCurrentFrame) {
+			_screen->loadBitmap("adtext.cps", 4, 4, 0);
+			_screen->loadBitmap("adtext2.cps", 6, 6, 0);
+			_screen->copyPageMemory(6, 0, 4, 64000, 1024);
+			_screen->copyPageMemory(6, 1023, 6, 0, 64000);
+			_seqScrollTextCounter = 0;
+		}
 
-			ptr = (uint8 *)strpbrk(str, mark);
-			if (!ptr)
-				ptr = (uint8 *)strchr(str, 0);
+		seq_scrollPage(24, 144);
+		_callbackCurrentFrame++;
+		if (_callbackCurrentFrame < 0x256 || _callbackCurrentFrame > 0x31c) {
+			if (_callbackCurrentFrame < 0x174 || _callbackCurrentFrame > 0x1d7) {
+				if (_callbackCurrentFrame < 0x84 || _callbackCurrentFrame > 0xe7) {
+					_seqScrollTextCounter++;
+				}
+			}
+		}
 
-			textData[cnt + 1].unk1 = *ptr;
-			*ptr = 0;
-			if (textData[cnt + 1].unk1)
-				ptr++;
+		if (_callbackCurrentFrame > 0x31e) {
+			closeNestedAnimation(0);
+			closeNestedAnimation(1);
+			setCountDown(0);
+			_screen->copyPage(2, 12);
+		}
 
-			if (*str == 3 || *str == 4)
-				textData[cnt + 1].adjust = *str++;
-			else
-				textData[cnt + 1].adjust = 0;
+	} else {
+		seq_scrollPage(24, 144);
+	}
+	return 0;
+}
 
-			_screen->setFont(fid1);
+int SeqPlayer_HOF::cbHOFDEMO_wharf2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 69)
+		_animCurrentFrame = 8;
 
-			if (*str == 1) {
-				_screen->setFont(fid2);
-				str++;
-			} else if (*str == 2) {
-				str++;
-			}
+	return frm;
+}
 
-			textData[cnt + 1].height = _screen->getFontHeight();
+int SeqPlayer_HOF::cbHOFDEMO_dinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	switch (frm) {
+	case 19:
+		seq_playTalkText(13);
+		break;
 
-			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;
-			}
+	case 54:
+		seq_playTalkText(15);
+		break;
 
-			if (textData[cnt].unk1 == 5)
-				cH -= (textData[cnt].height + (textData[cnt].height >> 3));
+	case 61:
+		seq_playTalkText(16);
+		break;
 
-			textData[cnt + 1].y = cH;
-			textData[cnt + 1].text = (uint8 *)str;
-			cnt++;
-		}
+	case 69:
+		seq_playTalkText(14);
+		break;
 
-		_screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage1, tempPage2);
+	case 77:
+		seq_playTalkText(13);
+		break;
 
-		int cnt2 = 0;
-		bool palCycle = 0;
+	case 79:
+		_animCurrentFrame = 4;
+		break;
+	}
 
-		while (cnt2 < cnt) {
-			const char *str = (const char *)textData[cnt2 + 1].text;
-			const char *str2 = str;
-			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;
+	return frm;
+}
 
-			if (cH < d->h) {
-				_screen->setCurPage(tempPage2);
-				_screen->setFont(fid1);
-				if (textData[cnt2 + 1].height != _screen->getFontHeight())
-					_screen->setFont(fid2);
+int SeqPlayer_HOF::cbHOFDEMO_water(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (frm == 1)
+		seq_playTalkText(11);
+	return frm;
+}
 
-				if (specialData) {
-					if (!strcmp(str, specialData[0])) {
-						col1 = 112;
-						char cChar[2] = " ";
-						while (*str2) {
-							cChar[0] = *str2;
-							_screen->printText(cChar, x, y, col1++, 0);
-							x += _screen->getCharWidth((uint8)*str2++);
-						}
-						palCycle = true;
-					} else if (!strcmp(str, specialData[1])) {
-						col1 = 133;
-						char cChar[2] = " ";
-						while (*str2) {
-							cChar[0] = *str2;
-							_screen->printText(cChar, x, y, col1--, 0);
-							x += _screen->getCharWidth((uint8)*str2++);
-						}
-						palCycle = true;
-					} else {
-						_screen->printText(str, x, y, col1, 0);
-					}
-				} else {
-					_screen->printText(str, x, y, col1, 0);
-				}
-				_screen->setCurPage(0);
-			}
+int SeqPlayer_HOF::cbHOFDEMO_bail(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	return frm;
+}
 
-			textData[cnt2 + 1].y -= step;
-			cnt2++;
-		}
+int SeqPlayer_HOF::cbHOFDEMO_dig(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	return frm;
+}
 
-		_screen->copyRegion(d->sx << 3, d->sy, d->sx << 3, d->sy, d->w << 3, d->h, tempPage2, 0);
-		_screen->updateScreen();
+#ifdef ENABLE_LOL
+int SeqPlayer_HOF::cbLOLDEMO_scene1(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	Palette &tmpPal = _screen->getPalette(2);
 
-		if (textData[1].y < -10) {
-			textData[1].text += strlen((char *)textData[1].text);
-			textData[1].text[0] = textData[1].unk1;
-			cnt--;
-			memcpy(&textData[1], &textData[2], cnt * sizeof(ScrollTextData));
+	if (!(_callbackCurrentFrame % 100)) {
+		if (_callbackCurrentFrame == 0) {
+			_vm->sound()->haltTrack();
+			_vm->sound()->playTrack(6);
 		}
+		tmpPal.copy(_screen->getPalette(0));
 
-		if (palCycle) {
-			for (int col = 133; col > 112; col--)
-				_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));
+		for (int i = 3; i < 0x300; i++) {
+			tmpPal[i] = ((int)tmpPal[i] * 120) / 64;
+			if (tmpPal[i] > 0x3f)
+				tmpPal[i] = 0x3f;
 		}
 
-		delayUntil(_seqSubFrameEndTimeInternal);
+		seq_playTalkText(_vm->_rnd.getRandomBit());
+		_screen->setScreenPalette(tmpPal);
+		_screen->updateScreen();
+		_vm->delay(8);
+	} else {
+		_screen->setScreenPalette(_screen->getPalette(0));
+		_screen->updateScreen();
+		if (_callbackCurrentFrame == 40)
+			seq_playTalkText(3);
+	}
 
-		if ((cnt < 36) && ((d->sy + d->h) > (textData[cnt].y + textData[cnt].height)) && !skipFlag()) {
-			resetSkipFlag();
-			delay(_tickLength * 500);
-			cnt = 0;
-		}
+	_callbackCurrentFrame++;
+	return frm;
+}
 
-		if (!cnt || skipFlag())
-			loop = false;
+int SeqPlayer_HOF::cbLOLDEMO_scene2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	switch (_callbackCurrentFrame - 17) {
+	case 0:
+		_animDuration = 8;
+		break;
+	case 3:
+	case 6:
+	case 9:
+		seq_playTalkText(8);
+		break;
+	case 15:
+		seq_playTalkText(9);
+		break;
+	case 18:
+		seq_playTalkText(2);
+		break;
+	default:
+		break;
 	}
+	_callbackCurrentFrame++;
+	return frm;
+}
 
-	_sound->beginFadeOut();
-	_screen->fadeToBlack();
-
-	_abortIntroFlag= false;
-	resetSkipFlag();
+int SeqPlayer_HOF::cbLOLDEMO_scene3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (_callbackCurrentFrame == 1)
+		seq_playTalkText(6);
+	else if (frm == 26)
+		seq_playTalkText(7);
 
-	delete[] textData;
+	_callbackCurrentFrame++;
+	return frm;
 }
 
-void KyraEngine_HoF::seq_scrollPage(int bottom, int top) {
-	int dstY, dstH, srcH;
+int SeqPlayer_HOF::cbLOLDEMO_scene4(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	switch (_callbackCurrentFrame) {
+	case 11:
+	case 14:
+	case 17:
+	case 20:
+		seq_playTalkText(8);
+		break;
+	case 22:
+		seq_playTalkText(11);
+		break;
+	case 24:
+		seq_playTalkText(8);
+		break;
+	case 30:
+		seq_playTalkText(15);
+		break;
+	case 34:
+		seq_playTalkText(14);
+		break;
+	case 38:
+		seq_playTalkText(13);
+		break;
+	case 42:
+		seq_playTalkText(12);
+		break;
+	default:
+		break;
+	}
 
-	static const ScreenDim d = { 0x00, 0x00, 0x28, 0x320, 0xFF, 0xFE, 0x00, 0x00 };
+	_callbackCurrentFrame++;
+	return frm;
+}
 
-	if (_seqScrollTextCounter - (top - 1) < 0) {
-		dstY = top - _seqScrollTextCounter;
-		dstH = _seqScrollTextCounter;
-		srcH = 0;
-	} else {
-		dstY = 0;
-		srcH = _seqScrollTextCounter - top;
-		dstH = (400 - srcH <= top) ? 400 - srcH : top;
+int SeqPlayer_HOF::cbLOLDEMO_scene5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	switch (_callbackCurrentFrame++) {
+	case 0:
+	case 4:
+	case 6:
+	case 8:
+	case 10:
+	case 14:
+	case 16:
+	case 18:
+	case 20:
+	case 22:
+	case 24:
+	case 26:
+	case 28:
+	case 30:
+		seq_playTalkText(15);
+		break;
+	case 32:
+		seq_playTalkText(16);
+		break;
+	case 42:
+		seq_playTalkText(6);
+		break;
+	default:
+		break;
 	}
+	return frm;
+}
 
-	if (dstH > 0) {
-		if (_demoAnimData) {
-			for (int i = 0; i < 4; i++) {
-				const ItemAnimData_v1 *def = &_demoAnimData[i];
-				ActiveItemAnim *a = &_activeItemAnim[i];
-
-				_screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4);
-				_screen->drawShape(4, getShapePtr(def->itemIndex + def->frames[a->currentFrame]), 12, def->y - 8, 0, 0);
-				if (_seqFrameCounter % 2 == 0)
-					a->currentFrame = (a->currentFrame + 1) % 20;
+int SeqPlayer_HOF::cbLOLDEMO_text5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	if (_callbackCurrentFrame++ == 100)
+		seq_playTalkText(5);
+	return frm;
+}
+
+int SeqPlayer_HOF::cbLOLDEMO_scene6(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
+	while (_seqScrollTextCounter < 0x122) {
+		setCountDown(6);
+		if (!_callbackCurrentFrame) {
+			_screen->loadBitmap("adtext.cps", 4, 4, 0);
+			_screen->loadBitmap("adtext2.cps", 6, 6, 0);
+			_screen->copyPageMemory(6, 0, 4, 64000, 1024);
+			_screen->copyPageMemory(6, 1023, 6, 0, 64000);
+			_seqScrollTextCounter = 0;
+		}
+
+		if (_callbackCurrentFrame % 175) {
+			_screen->setScreenPalette(_screen->getPalette(0));
+		} else {
+			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(_vm->_rnd.getRandomBit());
+			_screen->setScreenPalette(tmpPal);
+			_screen->updateScreen();
+			_vm->delay(8);
 		}
-		_screen->copyRegionEx(4, 0, srcH, 2, 2, dstY + bottom, 320, dstH, &d);
+
+		if (_callbackCurrentFrame == 40 || _callbackCurrentFrame == 80 || _callbackCurrentFrame == 150 || _callbackCurrentFrame == 300)
+			seq_playTalkText(3);
+
+		_screen->copyPage(12, 2);
+		seq_scrollPage(70, 130);
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		_callbackCurrentFrame++;
+		if (_callbackCurrentFrame < 128 || _callbackCurrentFrame > 207)
+			_seqScrollTextCounter++;
+
+		while (countDownRunning())
+			delayTicks(1);
 	}
+	_screen->copyPage(2, 12);
+
+	return 0;
 }
+#endif // ENABLE_LOL
+
+#undef CASE_ALT
+
+const uint8 SeqPlayer_HOF::_textColorPresets[] = { 0x01, 0x01, 0x00, 0x3f, 0x3f, 0x3f };
 
 void KyraEngine_HoF::seq_showStarcraftLogo() {
 	WSAMovie_v2 *ci = new WSAMovie_v2(this);
 	assert(ci);
 	_screen->clearPage(2);
 	_res->loadPakFile("INTROGEN.PAK");
-	int endframe = ci->open("ci.wsa", 0, &_screen->getPalette(0));
+	int endframe = ci->open("CI.WSA", 0, &_screen->getPalette(0));
 	_res->unloadPakFile("INTROGEN.PAK");
 	if (!ci->opened()) {
 		delete ci;
@@ -2736,20 +3374,28 @@ void KyraEngine_HoF::seq_showStarcraftLogo() {
 	_screen->copyPage(2, 0);
 	_screen->fadeFromBlack();
 	for (int i = 1; i < endframe; i++) {
-		_seqEndTime = _system->getMillis() + 50;
+		uint32 end = _system->getMillis() + 50;
 		if (skipFlag())
 			break;
 		ci->displayFrame(i, 2, 0, 0, 0, 0, 0);
 		_screen->copyPage(2, 0);
 		_screen->updateScreen();
-		delay(_seqEndTime - _system->getMillis());
+		uint32 cur = _system->getMillis();
+		if (end > cur)
+			delay(end - cur);
+		else
+			updateInput();
 	}
 	if (!skipFlag()) {
-		_seqEndTime = _system->getMillis() + 50;
+		uint32 end = _system->getMillis() + 50;
 		ci->displayFrame(0, 2, 0, 0, 0, 0, 0);
 		_screen->copyPage(2, 0);
 		_screen->updateScreen();
-		delay(_seqEndTime - _system->getMillis());
+		uint32 cur = _system->getMillis();
+		if (end > cur)
+			delay(end - cur);
+		else
+			updateInput();
 	}
 	_screen->fadeToBlack();
 	_screen->showMouse();
@@ -2758,67 +3404,39 @@ void KyraEngine_HoF::seq_showStarcraftLogo() {
 	delete ci;
 }
 
-void KyraEngine_HoF::seq_init() {
-	_seqProcessedString = new char[200];
-	_seqWsa = new WSAMovie_v2(this);
-	_activeWSA = new ActiveWSA[8];
-	_activeText = new ActiveText[10];
-
-	_res->unloadAllPakFiles();
-	_res->loadPakFile(StaticResource::staticDataFilename());
-	_res->loadFileList(_sequencePakList, _sequencePakListSize);
-
-	if (_flags.platform == Common::kPlatformPC98)
-		_sound->loadSoundFile("SOUND.DAT");
-
-	_screen->setFont(_flags.lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
-
-	if (_flags.gameID == GI_LOL)
-		return;
-
-	if (_flags.isDemo && !_flags.isTalkie) {
-		_demoAnimData = _staticres->loadShapeAnimData_v1(k2SeqplayShapeAnimData, _itemAnimDefinitionSize);
-		uint8 *shp = _res->fileData("icons.shp", 0);
-		uint32 outsize = READ_LE_UINT16(shp + 4);
-		_animShapeFiledata = new uint8[outsize];
-		Screen::decodeFrame4(shp + 10, _animShapeFiledata, outsize);
-		delete[] shp;
-
-		for (int i = 0; i < 20; i++)
-			addShapeToPool(_screen->getPtrToShape(_animShapeFiledata, i), i);
-	} else {
-		const MainMenu::StaticData data = {
-			{ _sequenceStrings[97], _sequenceStrings[96], _sequenceStrings[95], _sequenceStrings[98], 0 },
-			{ 0x01, 0x04, 0x0C, 0x04, 0x00, 0xd7, 0xd6 },
-			{ 0xd8, 0xda, 0xd9, 0xd8 },
-			(_flags.lang == Common::JA_JPN) ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT, 240
-		};
 
-		_menu = new MainMenu(this);
-		_menu->init(data, MainMenu::Animation());
-	}
+int KyraEngine_HoF::seq_playIntro() {
+	bool startupSaveLoadable = saveFileLoadable(0);
+	return SeqPlayer_HOF(this, _screen, _system, startupSaveLoadable).play(kSequenceVirgin, startupSaveLoadable? kSequenceTitle : kSequenceNoLooping);
 }
 
-void KyraEngine_HoF::seq_uninit() {
-	delete[] _seqProcessedString;
-	_seqProcessedString = NULL;
-
-	delete[] _activeWSA;
-	_activeWSA = NULL;
+int KyraEngine_HoF::seq_playOutro() {
+	return SeqPlayer_HOF(this, _screen, _system).play(kSequenceFunters, kSequenceFrash);
+}
 
-	delete[] _activeText;
-	_activeText = NULL;
+int KyraEngine_HoF::seq_playDemo() {
+	SeqPlayer_HOF(this, _screen, _system).play(kSequenceHoFDemoVirgin, kSequenceHoFDemoVirgin);
+	return 4;
+}
 
-	delete _seqWsa;
-	_seqWsa = NULL;
+void KyraEngine_HoF::seq_pausePlayer(bool toggle) {
+	SeqPlayer_HOF *activePlayer = SeqPlayer_HOF::instance();
+	if (activePlayer)
+		activePlayer->pause(toggle);
+}
 
-	delete[] _animShapeFiledata;
-	_animShapeFiledata = 0;
+#ifdef ENABLE_LOL
+int LoLEngine::playDemo() {
+	SeqPlayer_HOF(this, _screen, _system).play(kSequenceLoLDemoScene1, kSequenceLoLDemoScene1);
+	return -1;
+}
 
-	delete _menu;
-	_menu = 0;
-	_screen->setFont(_flags.lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+void LoLEngine::pauseDemoPlayer(bool toggle) {
+	SeqPlayer_HOF *activePlayer = SeqPlayer_HOF::instance();
+	if (activePlayer)
+		activePlayer->pause(toggle);
 }
+#endif // ENABLE_LOL
 
 #pragma mark -
 #pragma mark - Ingame sequences
diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp
index a06f207..485120a 100644
--- a/engines/kyra/sequences_lol.cpp
+++ b/engines/kyra/sequences_lol.cpp
@@ -36,10 +36,15 @@ namespace Kyra {
 #pragma mark - Intro
 
 int LoLEngine::processPrologue() {
-	setupPrologueData(true);
-
-	if (!saveFileLoadable(0) || _flags.isDemo)
-		showIntro();
+	// There are two non-interactive demos (one which plays the intro and another one) which plays a number of specific scenes.
+	// We try to identify the latter one by looking for a specific file.
+	if (_flags.isDemo && _res->exists("scene1.cps")) {
+		return playDemo();
+	} else {
+		setupPrologueData(true);
+		if (!saveFileLoadable(0) || _flags.isDemo)
+			showIntro();
+	}
 
 	if (_flags.isDemo) {
 		_screen->fadePalette(_screen->getPalette(1), 30, 0);
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 00dc4f9..04e111b 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -31,6 +31,7 @@
 #include "kyra/gui_lok.h"
 #include "kyra/gui_hof.h"
 #include "kyra/gui_mr.h"
+#include "kyra/sequences_hof.h"
 #include "kyra/sound_intern.h"
 
 #include "common/endian.h"
@@ -245,8 +246,8 @@ bool StaticResource::init() {
 		{ kAmigaSfxTable, proc(loadAmigaSfxTable), proc(freeAmigaSfxTable) },
 		{ kRawData, proc(loadRawData), proc(freeRawData) },
 
-		{ k2SeqData, proc(loadHofSequenceData), proc(freeHofSequenceData) },
-		{ k2ShpAnimDataV1, proc(loadShapeAnimData_v1), proc(freeHofShapeAnimDataV1) },
+		{ k2SeqData, proc(loadHoFSequenceData), proc(freeHoFSequenceData) },
+		{ k2SeqItemAnimData, proc(loadHoFSeqItemAnimData), proc(freeHoFSeqItemAnimData) },
 		{ k2ItemAnimDefinition, proc(loadItemAnimDefinition), proc(freeItemAnimDefinition) },
 
 #ifdef ENABLE_LOL
@@ -308,12 +309,12 @@ const Room *StaticResource::loadRoomTable(int id, int &entries) {
 	return (const Room *)getData(id, StaticResource::kRoomList, entries);
 }
 
-const HofSeqData *StaticResource::loadHofSequenceData(int id, int &entries) {
-	return (const HofSeqData *)getData(id, k2SeqData, entries);
+const HoFSeqData *StaticResource::loadHoFSequenceData(int id, int &entries) {
+	return (const HoFSeqData *)getData(id, k2SeqData, entries);
 }
 
-const ItemAnimData_v1 *StaticResource::loadShapeAnimData_v1(int id, int &entries) {
-	return (const ItemAnimData_v1 *)getData(id, k2ShpAnimDataV1, entries);
+const HoFSeqItemAnimData *StaticResource::loadHoFSeqItemAnimData(int id, int &entries) {
+	return (const HoFSeqItemAnimData *)getData(id, k2SeqItemAnimData, entries);
 }
 
 const ItemAnimDefinition *StaticResource::loadItemAnimDefinition(int id, int &entries) {
@@ -513,12 +514,12 @@ bool StaticResource::loadRoomTable(Common::SeekableReadStream &stream, void *&pt
 	return true;
 }
 
-bool StaticResource::loadHofSequenceData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+bool StaticResource::loadHoFSequenceData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
 	int numSeq = stream.readUint16BE();
 	uint32 offset = 2;
-	Sequence *tmp_s = new Sequence[numSeq];
+	HoFSequence *tmp_s = new HoFSequence[numSeq];
 
-	size = sizeof(HofSeqData) + numSeq * (sizeof(Sequence) + 28);
+	size = sizeof(HoFSeqData) + numSeq * (sizeof(HoFSequence) + 28);
 
 	for (int i = 0; i < numSeq; i++) {
 		stream.seek(offset, SEEK_SET); offset += 2;
@@ -529,22 +530,22 @@ bool StaticResource::loadHofSequenceData(Common::SeekableReadStream &stream, voi
 		stream.read(const_cast<char *>(tmp_s[i].wsaFile), 14);
 		tmp_s[i].cpsFile = new char[14];
 		stream.read(const_cast<char *>(tmp_s[i].cpsFile), 14);
-		tmp_s[i].startupCommand = stream.readByte();
-		tmp_s[i].finalCommand = stream.readByte();
+		tmp_s[i].fadeInTransitionType = stream.readByte();
+		tmp_s[i].fadeOutTransitionType = stream.readByte();
 		tmp_s[i].stringIndex1 = stream.readUint16BE();
 		tmp_s[i].stringIndex2 = stream.readUint16BE();
 		tmp_s[i].startFrame = stream.readUint16BE();
 		tmp_s[i].numFrames = stream.readUint16BE();
-		tmp_s[i].frameDelay = stream.readUint16BE();
+		tmp_s[i].duration = stream.readUint16BE();
 		tmp_s[i].xPos = stream.readUint16BE();
 		tmp_s[i].yPos = stream.readUint16BE();
-		tmp_s[i].duration = stream.readUint16BE();
+		tmp_s[i].timeout = stream.readUint16BE();
 	}
 
 	stream.seek(offset, SEEK_SET); offset += 2;
 	int numSeqN = stream.readUint16BE();
-	NestedSequence *tmp_n = new NestedSequence[numSeqN];
-	size += (numSeqN * (sizeof(NestedSequence) + 14));
+	HoFNestedSequence *tmp_n = new HoFNestedSequence[numSeqN];
+	size += (numSeqN * (sizeof(HoFNestedSequence) + 14));
 
 	for (int i = 0; i < numSeqN; i++) {
 		stream.seek(offset, SEEK_SET); offset += 2;
@@ -559,8 +560,8 @@ bool StaticResource::loadHofSequenceData(Common::SeekableReadStream &stream, voi
 		tmp_n[i].x = stream.readUint16BE();
 		tmp_n[i].y = stream.readUint16BE();
 		uint16 ctrlOffs = stream.readUint16BE();
-		tmp_n[i].startupCommand = stream.readUint16BE();
-		tmp_n[i].finalCommand = stream.readUint16BE();
+		tmp_n[i].fadeInTransitionType = stream.readUint16BE();
+		tmp_n[i].fadeOutTransitionType = stream.readUint16BE();
 
 		if (ctrlOffs) {
 			stream.seek(ctrlOffs, SEEK_SET);
@@ -580,21 +581,21 @@ bool StaticResource::loadHofSequenceData(Common::SeekableReadStream &stream, voi
 		}
 	}
 
-	HofSeqData *loadTo = new HofSeqData;
+	HoFSeqData *loadTo = new HoFSeqData;
 	assert(loadTo);
 
 	loadTo->seq = tmp_s;
-	loadTo->seqn = tmp_n;
+	loadTo->nestedSeq = tmp_n;
 	loadTo->numSeq = numSeq;
-	loadTo->numSeqn = numSeqN;
+	loadTo->numNestedSeq = numSeqN;
 
 	ptr = loadTo;
 	return true;
 }
 
-bool StaticResource::loadShapeAnimData_v1(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+bool StaticResource::loadHoFSeqItemAnimData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
 	size = stream.readByte();
-	ItemAnimData_v1 *loadTo = new ItemAnimData_v1[size];
+	HoFSeqItemAnimData *loadTo = new HoFSeqItemAnimData[size];
 	assert(loadTo);
 
 	for (int i = 0; i < size; i++) {
@@ -670,8 +671,8 @@ void StaticResource::freeRoomTable(void *&ptr, int &size) {
 	size = 0;
 }
 
-void StaticResource::freeHofSequenceData(void *&ptr, int &size) {
-	HofSeqData *h = (HofSeqData *)ptr;
+void StaticResource::freeHoFSequenceData(void *&ptr, int &size) {
+	HoFSeqData *h = (HoFSeqData *)ptr;
 
 	for (int i = 0; i < h->numSeq; i++) {
 		delete[] h->seq[i].wsaFile;
@@ -679,19 +680,19 @@ void StaticResource::freeHofSequenceData(void *&ptr, int &size) {
 	}
 	delete[] h->seq;
 
-	for (int i = 0; i < h->numSeqn; i++) {
-		delete[] h->seqn[i].wsaFile;
-		delete[] h->seqn[i].wsaControl;
+	for (int i = 0; i < h->numNestedSeq; i++) {
+		delete[] h->nestedSeq[i].wsaFile;
+		delete[] h->nestedSeq[i].wsaControl;
 	}
-	delete[] h->seqn;
+	delete[] h->nestedSeq;
 
 	delete h;
 	ptr = 0;
 	size = 0;
 }
 
-void StaticResource::freeHofShapeAnimDataV1(void *&ptr, int &size) {
-	ItemAnimData_v1 *d = (ItemAnimData_v1 *)ptr;
+void StaticResource::freeHoFSeqItemAnimData(void *&ptr, int &size) {
+	HoFSeqItemAnimData *d = (HoFSeqItemAnimData *)ptr;
 	for (int i = 0; i < size; i++)
 		delete[] d[i].frames;
 	delete[] d;
@@ -994,9 +995,7 @@ void KyraEngine_LoK::loadMainScreen(int page) {
 void KyraEngine_HoF::initStaticResource() {
 	int tmpSize = 0;
 
-	_sequencePakList = _staticres->loadStrings(k2SeqplayPakFiles, _sequencePakListSize);
 	_ingamePakList = _staticres->loadStrings(k2IngamePakFiles, _ingamePakListSize);
-	_sequenceStrings = _staticres->loadStrings(k2SeqplayStrings, _sequenceStringsSize);
 	_ingameSoundList = _staticres->loadStrings(k2IngameSfxFiles, _ingameSoundListSize);
 	_ingameSoundIndex = (const uint16 *)_staticres->loadRawData(k2IngameSfxIndex, _ingameSoundIndexSize);
 	_musicFileListIntro = _staticres->loadStrings(k2SeqplayIntroTracks, _musicFileListIntroSize);
@@ -1009,33 +1008,6 @@ void KyraEngine_HoF::initStaticResource() {
 	_ingameTimJpStr = _staticres->loadStrings(k2IngameTimJpStrings, _ingameTimJpStrSize);
 	_itemAnimDefinition = _staticres->loadItemAnimDefinition(k2IngameShapeAnimData, _itemAnimDefinitionSize);
 
-	// replace sequence talkie files with localized versions
-	const char *const *seqSoundList = _staticres->loadStrings(k2SeqplaySfxFiles, _sequenceSoundListSize);
-	const char *const *tlkfiles = _staticres->loadStrings(k2SeqplayTlkFiles, tmpSize);
-	char **tmpSndLst = new char *[_sequenceSoundListSize];
-
-	for (int i = 0; i < _sequenceSoundListSize; i++) {
-		const int len = strlen(seqSoundList[i]);
-
-		tmpSndLst[i] = new char[len + 1];
-		tmpSndLst[i][0] = 0;
-
-		if (tlkfiles && len > 1) {
-			for (int ii = 0; ii < tmpSize; ii++) {
-				if (strlen(tlkfiles[ii]) > 1 && !scumm_stricmp(&seqSoundList[i][1], &tlkfiles[ii][1]))
-					strcpy(tmpSndLst[i], tlkfiles[ii]);
-			}
-		}
-
-		if (tmpSndLst[i][0] == 0)
-			strcpy(tmpSndLst[i], seqSoundList[i]);
-	}
-
-	tlkfiles = seqSoundList = 0;
-	_staticres->unloadId(k2SeqplayTlkFiles);
-	_staticres->unloadId(k2SeqplaySfxFiles);
-	_sequenceSoundList = tmpSndLst;
-
 	// assign music data
 	static const char *const fmtMusicFileListIntro[] = { "intro%d.twn" };
 	static const char *const fmtMusicFileListFinale[] = { "finale%d.twn" };
@@ -1074,66 +1046,6 @@ void KyraEngine_HoF::initStaticResource() {
 		_soundData[2].fileList = pc98MusicFileListFinale;
 		_soundData[2].fileListLen = 1;
 	}
-
-	// setup sequence data
-	_sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize);
-
-	static const SeqProc hofSequenceCallbacks[] = {
-		0, &KyraEngine_HoF::seq_introWestwood,
-		&KyraEngine_HoF::seq_introTitle, &KyraEngine_HoF::seq_introOverview,
-		&KyraEngine_HoF::seq_introLibrary, &KyraEngine_HoF::seq_introHand,
-		&KyraEngine_HoF::seq_introPoint, &KyraEngine_HoF::seq_introZanfaun,
-		&KyraEngine_HoF::seq_finaleFunters, &KyraEngine_HoF::seq_finaleFerb,
-		&KyraEngine_HoF::seq_finaleFish, &KyraEngine_HoF::seq_finaleFheep,
-		&KyraEngine_HoF::seq_finaleFarmer, &KyraEngine_HoF::seq_finaleFuards,
-		&KyraEngine_HoF::seq_finaleFirates, &KyraEngine_HoF::seq_finaleFrash
-	};
-
-	static const SeqProc hofNestedSequenceCallbacks[] = {
-		&KyraEngine_HoF::seq_finaleFiggle, &KyraEngine_HoF::seq_introOver1,
-		&KyraEngine_HoF::seq_introOver2, &KyraEngine_HoF::seq_introForest,
-		&KyraEngine_HoF::seq_introDragon, &KyraEngine_HoF::seq_introDarm,
-		&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
-	};
-
-	static const SeqProc hofDemoSequenceCallbacks[] = {
-		&KyraEngine_HoF::seq_demoVirgin, &KyraEngine_HoF::seq_demoWestwood,
-		&KyraEngine_HoF::seq_demoTitle, &KyraEngine_HoF::seq_demoHill,
-		&KyraEngine_HoF::seq_demoOuthome, &KyraEngine_HoF::seq_demoWharf,
-		&KyraEngine_HoF::seq_demoDinob, &KyraEngine_HoF::seq_demoFisher, 0
-	};
-
-	static const SeqProc hofDemoNestedSequenceCallbacks[] = {
-		&KyraEngine_HoF::seq_demoWharf2, &KyraEngine_HoF::seq_demoDinob2,
-		&KyraEngine_HoF::seq_demoWater, &KyraEngine_HoF::seq_demoBail,
-		&KyraEngine_HoF::seq_demoDig, 0
-	};
-
-#ifdef ENABLE_LOL
-	static const SeqProc kLoLDemoSequenceCallbacks[] = {
-		&KyraEngine_HoF::seq_lolDemoScene1, 0, &KyraEngine_HoF::seq_lolDemoScene2, 0,
-		&KyraEngine_HoF::seq_lolDemoScene3, 0, &KyraEngine_HoF::seq_lolDemoScene4, 0,
-		&KyraEngine_HoF::seq_lolDemoScene5, &KyraEngine_HoF::seq_lolDemoText5,
-		&KyraEngine_HoF::seq_lolDemoScene6, 0
-	};
-
-	static const SeqProc kLoLDemoNestedSequenceCallbacks[] = { 0 };
-#endif // ENABLE_LOL
-
-	_callbackS =
-#ifdef ENABLE_LOL
-	    _flags.gameID == GI_LOL ? kLoLDemoSequenceCallbacks :
-#endif // ENABLE_LOL
-	    ((_flags.isDemo && !_flags.isTalkie) ? hofDemoSequenceCallbacks : hofSequenceCallbacks);
-
-	_callbackN =
-#ifdef ENABLE_LOL
-	    _flags.gameID == GI_LOL ? kLoLDemoNestedSequenceCallbacks :
-#endif // ENABLE_LOL
-	    ((_flags.isDemo && !_flags.isTalkie) ? hofDemoNestedSequenceCallbacks : hofNestedSequenceCallbacks);
 }
 
 void KyraEngine_MR::initStaticResource() {
@@ -1412,8 +1324,6 @@ const int GUI_v2::_sliderBarsPosition[] = {
 
 // kyra 2 static res
 
-const uint8 KyraEngine_HoF::_seqTextColorPresets[] = { 0x01, 0x01, 0x00, 0x3f, 0x3f, 0x3f };
-
 const char *const KyraEngine_HoF::_languageExtension[] = {
 	"ENG",
 	"FRE",


Commit: 1bb8f22567e71796bba4f98a6ff4353ec84df197
    https://github.com/scummvm/scummvm/commit/1bb8f22567e71796bba4f98a6ff4353ec84df197
Author: athrxx (athrxx at scummvm.org)
Date: 2012-11-11T10:14:30-08:00

Commit Message:
KYRA: finish implementation of new HOF sequence player code

Changed paths:
  A engines/kyra/sequences_hof.h
    engines/kyra/detection_tables.h
    engines/kyra/kyra_hof.cpp
    engines/kyra/kyra_v1.h
    engines/kyra/screen_hof.cpp
    engines/kyra/screen_hof.h
    engines/kyra/screen_v2.cpp
    engines/kyra/screen_v2.h
    engines/kyra/sequences_hof.cpp
    engines/kyra/sequences_lol.cpp
    engines/kyra/staticres_lol.cpp



diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index e2162f2..5b9d665 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -1495,7 +1495,7 @@ const KYRAGameDescription adGameDescs[] = {
 			ADGF_DEMO,
 			GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
 		},
-		LOL_KYRA2_DEMO_FLAGS
+		LOL_DEMO_FLAGS
 	},
 #endif // ENABLE_LOL
 #ifdef ENABLE_EOB
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 885e3d5..d8d4f69 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -197,8 +197,6 @@ Common::Error KyraEngine_HoF::init() {
 		_screen->loadFont(_screen->FID_8_FNT, "8FAT.FNT");
 		_screen->loadFont(_screen->FID_BOOKFONT_FNT, "BOOKFONT.FNT");
 	}
-	_screen->loadFont(_screen->FID_GOLDFONT_FNT, "GOLDFONT.FNT");
-
 	_screen->setFont(_flags.lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : _screen->FID_8_FNT);
 
 	_screen->setAnimBlockPtr(3504);
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index c83f0a6..d912553 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -188,6 +188,7 @@ friend class GUI;
 friend class GUI_v1;
 friend class GUI_EoB;
 friend class SoundMidiPC;    // For _eventMan
+friend class SeqPlayer_HOF; // For skipFlag()
 friend class TransferPartyWiz; // For save state API
 public:
 	KyraEngine_v1(OSystem *system, const GameFlags &flags);
diff --git a/engines/kyra/screen_hof.cpp b/engines/kyra/screen_hof.cpp
index 7fdbdeb..a8ec2cc 100644
--- a/engines/kyra/screen_hof.cpp
+++ b/engines/kyra/screen_hof.cpp
@@ -93,40 +93,4 @@ void Screen_HoF::cmpFadeFrameStep(int srcPage, int srcW, int srcH, int srcX, int
 	}
 }
 
-void Screen_HoF::copyRegionEx(int srcPage, int srcW, int srcH, int dstPage, int dstX, int dstY, int dstW, int dstH, const ScreenDim *dim, bool flag) {
-	int x0 = dim->sx << 3;
-	int y0 = dim->sy;
-	int w0 = dim->w << 3;
-	int h0 = dim->h;
-
-	int x1 = dstX;
-	int y1 = dstY;
-	int w1 = dstW;
-	int h1 = dstH;
-
-	int x2, y2, w2;
-
-	calcBounds(w0, h0, x1, y1, w1, h1, x2, y2, w2);
-
-	const uint8 *src = getPagePtr(srcPage) + (320 * srcH) + srcW;
-	uint8 *dst = getPagePtr(dstPage) + 320 * (y0 + y1);
-
-	for (int y = 0; y < h1; y++) {
-		const uint8 *s = src + x2;
-		uint8 *d = dst + x0 + x1;
-
-		if (flag)
-			d += (h1 >> 1);
-
-		for (int x = 0; x < w1; x++) {
-			if (*s)
-				*d = *s;
-			s++;
-			d++;
-		}
-		dst += 320;
-		src += 320;
-	}
-}
-
 } // End of namespace Kyra
diff --git a/engines/kyra/screen_hof.h b/engines/kyra/screen_hof.h
index 07fcd96..95f4616 100644
--- a/engines/kyra/screen_hof.h
+++ b/engines/kyra/screen_hof.h
@@ -38,7 +38,6 @@ public:
 	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 copyRegionEx(int srcPage, int srcW, int srcH, int dstPage, int dstX,int dstY, int dstW, int dstH, const ScreenDim *d, bool flag = false);
 private:
 	KyraEngine_HoF *_vm;
 
diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp
index 1131460..407d73a 100644
--- a/engines/kyra/screen_v2.cpp
+++ b/engines/kyra/screen_v2.cpp
@@ -356,6 +356,42 @@ void Screen_v2::copyPageMemory(int srcPage, int srcPos, int dstPage, int dstPos,
 	memcpy(dst, src, numBytes);
 }
 
+void Screen_v2::copyRegionEx(int srcPage, int srcW, int srcH, int dstPage, int dstX, int dstY, int dstW, int dstH, const ScreenDim *dim, bool flag) {
+	int x0 = dim->sx << 3;
+	int y0 = dim->sy;
+	int w0 = dim->w << 3;
+	int h0 = dim->h;
+
+	int x1 = dstX;
+	int y1 = dstY;
+	int w1 = dstW;
+	int h1 = dstH;
+
+	int x2, y2, w2;
+
+	calcBounds(w0, h0, x1, y1, w1, h1, x2, y2, w2);
+
+	const uint8 *src = getPagePtr(srcPage) + (320 * srcH) + srcW;
+	uint8 *dst = getPagePtr(dstPage) + 320 * (y0 + y1);
+
+	for (int y = 0; y < h1; y++) {
+		const uint8 *s = src + x2;
+		uint8 *d = dst + x0 + x1;
+
+		if (flag)
+			d += (h1 >> 1);
+
+		for (int x = 0; x < w1; x++) {
+			if (*s)
+				*d = *s;
+			s++;
+			d++;
+		}
+		dst += 320;
+		src += 320;
+	}
+}
+
 bool Screen_v2::calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, int &x2, int &y2, int &w2) {
 	x2 = 0;
 	y2 = 0;
diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h
index 31c0b9f..6f4d671 100644
--- a/engines/kyra/screen_v2.h
+++ b/engines/kyra/screen_v2.h
@@ -71,6 +71,7 @@ public:
 
 	// used in non-interactive HoF/LoL demos
 	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);
 protected:
 	uint8 *_wsaFrameAnimBuffer;
 };
diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index 26e2fd7..7f105bf 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -138,13 +138,7 @@ private:
 	bool checkPlaybackStatus();
 
 	bool _abortRequested;
-
-	uint32 _seqWsaChatTimeout;
-	uint32 _seqWsaChatFrameTimeout;
-
-	int _seqScrollTextCounter;
-	uint8 _seqTextColor[2];
-	uint8 _seqTextColorMap[16];
+	uint32 _pauseStart;
 
 	// Sequence transitions
 	void doTransition(int type);
@@ -153,6 +147,7 @@ private:
 
 	// Animations
 	void playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int numFrames, int frameRate, int x, int y, const SeqProc callback, Palette *fadePal1, Palette *fadePal2, int fadeRate, bool restoreScreen);
+	void playDialogueAnimation(uint16 strID, uint16 soundID, int textColor, int textPosX, int textPosY, int textWidth, WSAMovie_v2 *wsaObj, int animStartFrame, int animLastFrame, int animPosX, int animPosY);
 
 	void startNestedAnimation(int animSlot, int sequenceID);
 	void closeNestedAnimation(int animSlot);
@@ -185,18 +180,22 @@ private:
 	int _animCurrentFrame;
 	int _callbackCurrentFrame;
 
-	// Subtitles/Dialogue/Sound
-	void seq_playTalkText(uint8 chatNum);
-	void seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, int textColor, int x, int y, int width, WSAMovie_v2 * wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos);
-	void seq_printCreditsString(uint16 strIndex, int x, int y, const uint8 *colorMap, uint8 textcolor);
-	int seq_setTextEntry(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width);
+	// The only reason to declare these here (instead of just locally) is being able to increase them after pausing the Engine
+	uint32 _specialAnimTimeOutTotal;
+	uint32 _specialAnimFrameTimeOut;
 
-	void seq_processText();
-	char *seq_preprocessString(const char *str, int width);
+	// Subtitles/Dialogue/Sound
+	void playSoundEffect(uint16 id, int16 vol);
+	void playSoundAndDisplaySubTitle(uint16 id);
+	void printFadingText(uint16 strID, int x, int y, const uint8 *colorMap, uint8 textcolor);
 
+	int displaySubTitle(uint16 strID, uint16 posX, uint16 posY, int duration, uint16 width);
+	void updateSubTitles();
+	char *preprocessString(const char *str, int width);
 	void waitForSubTitlesTimeout();
 	uint32 ticksTillSubTitlesTimeout();
-	void seq_resetAllTextEntries();
+	void resetAllTextSlots();
+
 	void fadeOutMusic();
 
 	struct TextSlot {
@@ -213,28 +212,31 @@ private:
 
 	char *_tempString;
 
+	uint8 _textColor[2];
+	uint8 _textColorMap[16];
+	int _textDuration[33];
+
 	const char * const *_sequenceStrings;
 	const char * const *_sequenceSoundList;
 	int _sequenceSoundListSize;
 
-	Audio::SoundHandle _speechHandle;
-
-	int _textDuration[33];
 	static const uint8 _textColorPresets[];
 
 	// HOF credits
-	void seq_finaleActorScreen();
-	void seq_displayScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed, int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData = 0, const char *const *specialData = 0);
+	void playHoFTalkieCredits();
+	void displayHoFTalkieScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed, int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData = 0, const char *const *specialData = 0);
 
 	bool _talkieFinaleExtraFlag;
 
-	// HOF demo specific
-	void seq_scrollPage(int bottom, int top);
+	// HOF+LOL demo specific
+	void updateDemoAdText(int bottom, int top);
 
 	ActiveItemAnim _hofDemoActiveItemAnim[5];
+	const HoFSeqItemAnimData *_hofDemoAnimData;
+
 	uint32 _fisherAnimCurTime;
+	int _scrollProgressCounter;
 
-	const HoFSeqItemAnimData *_hofDemoAnimData;
 	uint8 *_hofDemoShapeData;
 	uint8 *_hofDemoItemShapes[20];
 
@@ -266,6 +268,7 @@ private:
 
 	KyraEngine_v1 *_vm;
 	Screen_v2 *_screen;
+	// We might consider getting rid of Screen_HoF, since there are only 2 methods left in that class anyway
 	Screen_HoF *_screenHoF;
 	OSystem *_system;
 
@@ -353,6 +356,7 @@ SeqPlayer_HOF::SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *syst
 	_preventLooping = false;
 	_menu = 0;
 	_abortRequested = false;
+	_pauseStart = 0;
 
 	_updateAnimations = false;
 	_animDuration = 0;
@@ -364,6 +368,7 @@ SeqPlayer_HOF::SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *syst
 	_preventSkipBeforeScene = -1;
 	_lastScene = 0;
 
+	_scrollProgressCounter = 0;
 	_fisherAnimCurTime = 0;
 
 	_tempString = new char[200];
@@ -419,10 +424,10 @@ SeqPlayer_HOF::SeqPlayer_HOF(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *syst
 	_vm->staticres()->unloadId(k2SeqplaySfxFiles);
 	_sequenceSoundList = tmpSndLst;
 
-
 	if (_vm->gameFlags().platform == Common::kPlatformPC98)
 		_vm->sound()->loadSoundFile("SOUND.DAT");
 
+	_screen->loadFont(_screen->FID_GOLDFONT_FNT, "GOLDFONT.FNT");
 	_screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_GOLDFONT_FNT);
 
 	if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) {
@@ -467,7 +472,8 @@ SeqPlayer_HOF::~SeqPlayer_HOF() {
 	delete[] _hofDemoShapeData;
 	delete _menu;
 
-	_screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
+	if (_vm->game() != GI_LOL)
+		_screen->setFont(_vm->gameFlags().lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_8_FNT);
 }
 
 int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
@@ -492,7 +498,7 @@ int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
 		_target = kLoLDemo;
 		_screen->_charWidth = 0;
 	} else if (firstScene >= kSequenceHoFDemoVirgin) {
-		incompatibleData = (_vm->game() != GI_KYRA2 || _vm->gameFlags().isDemo || _vm->gameFlags().isTalkie);
+		incompatibleData = (_vm->game() != GI_KYRA2 || !_vm->gameFlags().isDemo || _vm->gameFlags().isTalkie);
 		_firstScene -= kSequenceHoFDemoVirgin;
 		if (loopStartScene != kSequenceNoLooping)
 			_loopStartScene -= kSequenceHoFDemoVirgin;
@@ -513,7 +519,7 @@ int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
 	}
 
 	if (incompatibleData)
-		error("SeqPlayer_HOF::play(): Requested sequences do not match the available sequence data for this target");
+		error("SeqPlayer_HOF::play(): Specified sequences do not match the available sequence data for this target");
 
 	_vm->sound()->setSoundList(_vm->soundData(soundSet));
 	_vm->sound()->loadSoundFile(0);
@@ -526,35 +532,25 @@ int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
 
 void SeqPlayer_HOF::pause(bool toggle) {
 	if (toggle) {
-
+		_pauseStart = _system->getMillis();
 	} else {
-		//
-		// Timers in KyraEngine_HoF::nestedFrameFadeTransition() and KyraEngine_HoF::nestedFrameAnimTransition()
-		// have been left out for now. I think we don't need them here.
-
-	/*	_fisherAnimCurTime += pausedTime;
-		_seqSubFrameStartTime += pausedTime;
-		_seqEndTime += pausedTime;
-		_seqSubFrameEndTimeInternal += pausedTime;
-		_seqWsaChatTimeout += pausedTime;
-		_seqWsaChatFrameTimeout += pausedTime;
-
-		if (_textSlots) {
-			for (int x = 0; x < 10; x++) {
-				if (_textSlots[x].duration != -1)
-					_textSlots[x].startTime += pausedTime;
-			}
-		}
+		uint32 pausedTime = _system->getMillis() - _pauseStart;
+		_pauseStart = 0;
+		
+		_countDownLastUpdate += pausedTime;
+		_fisherAnimCurTime += pausedTime;
+		_specialAnimTimeOutTotal += pausedTime;
+		_specialAnimFrameTimeOut += pausedTime;
 
-		if (_animSlots) {
-			for (int x = 0; x < 8; x++) {
-				if (_animSlots[x].flags != -1)
-					_animSlots[x].nextFrame += pausedTime;
-			}
+		for (int i = 0; i < 10; i++) {
+			if (_textSlots[i].duration != -1)
+				_textSlots[i].startTime += pausedTime;
 		}
 
-		for (int x = 0; x < _itemAnimDefinitionSize; x++)
-			_activeItemAnim[x].nextFrameTime += pausedTime;*/
+		for (int i = 0; i < 8; i++) {
+			if (_animSlots[i].flags != -1)
+				_animSlots[i].nextFrame += pausedTime;
+		}
 	}
 }
 
@@ -569,7 +565,7 @@ void SeqPlayer_HOF::setupCallbacks() {
 #undef SCB
 #ifdef ENABLE_LOL
 #define SCB(x) &SeqPlayer_HOF::cbLOLDEMO_##x
-	static const SeqProc seqCallbacksLoLDemo[] = { SCB(scene1), SCB(scene2), SCB(scene3), SCB(scene4), SCB(scene5), SCB(text5), SCB(scene6), 0 };
+	static const SeqProc seqCallbacksLoLDemo[] = { SCB(scene1), 0, SCB(scene2), 0, SCB(scene3), 0, SCB(scene4), 0, SCB(scene5), SCB(text5), SCB(scene6), 0 };
 #undef SCB
 #else
 	static const SeqProc seqCallbacksLoLDemo[] = { 0 };
@@ -601,13 +597,13 @@ void SeqPlayer_HOF::runLoop() {
 
 	_updateAnimations = false;
 	_animCurrentFrame = 0;
-	_seqTextColor[0] = _seqTextColor[1] = 0;
+	_textColor[0] = _textColor[1] = 0;
 	_curScene = _firstScene;
 
 	do {
 		playScenes();
 		doTransition(0);
-		seq_resetAllTextEntries();
+		resetAllTextSlots();
 		fadeOutMusic();
 		_firstScene = ((!_startupSaveLoadable || _preventLooping) && _curScene >= _loopStartScene) ? kSequenceNoLooping : _loopStartScene;
 	} while (!_vm->shouldQuit() && _firstScene != kSequenceNoLooping);
@@ -636,6 +632,8 @@ void SeqPlayer_HOF::playScenes() {
 	WSAMovie_v2 anim(_vm);
 	_abortRequested = false;
 
+	_scrollProgressCounter = 0;
+
 	while (!_vm->shouldQuit()) {
 		if (checkAbortPlayback())
 			if (checkPlaybackStatus())
@@ -704,25 +702,16 @@ void SeqPlayer_HOF::playScenes() {
 			while (!checkAbortPlayback() && !_vm->shouldQuit() && (countDownRunning() || _updateAnimations)) {
 				uint32 endFrame = (_system->getMillis() + _vm->tickLength()) & ~(_vm->tickLength() - 1);
 				updateAllNestedAnimations();
-				// Due to bugged coding / sequence data in the FM-Towns and PC-98 versions these animations will only play correctly on slow hardware.
-				// If the hardware is too fast the animations will not finish. This bug was probably irrelevant for original FM-Towns or PC-98 machines.
-				// We compensate this with a small extra delay.
-				if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
-					delayTicks(1);
 				
 				if (_config->seqProc[_curScene])
 					(this->*_config->seqProc[_curScene])(0, 0, 0, 0);
 
-				seq_processText();
+				updateSubTitles();
 
 				_screen->copyPage(2, 0);
 				_screen->updateScreen();
 				_screen->copyPage(12, 2);
 
-				// See comment above.
-				if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
-					delayTicks(1);
-
 				do {
 					if (checkAbortPlayback())
 						if (checkPlaybackStatus())
@@ -748,16 +737,22 @@ void SeqPlayer_HOF::playScenes() {
 		_curScene++;
 	}
 
-	if (checkAbortPlayback() || _vm->shouldQuit()) {
-		seq_resetAllTextEntries();
-		_vm->sound()->haltTrack();
-		_vm->sound()->voiceStop();
-	}
+	resetAllTextSlots();
+	_vm->sound()->haltTrack();
+	_vm->sound()->voiceStop();
+
+	if ((!checkAbortPlayback() || _vm->shouldQuit()) && _vm->gameFlags().isDemo)
+		_curScene = -1;
 }
 
 bool SeqPlayer_HOF::checkAbortPlayback() {
 	Common::Event event;
 
+	if (_vm->skipFlag()) {
+		_abortRequested = true;
+		_vm->resetSkipFlag();
+	}
+
 	if (_abortRequested)
 		return true;
 
@@ -785,7 +780,7 @@ bool SeqPlayer_HOF::checkAbortPlayback() {
 bool SeqPlayer_HOF::checkPlaybackStatus() {
 	_updateAnimations = false;
 
-	if (_curScene <= _preventSkipBeforeScene || _curScene == _loopStartScene) {
+	if (_curScene <= _preventSkipBeforeScene || (_curScene == _loopStartScene && !_isFinale)) {
 		_abortRequested = false;
 		return false;
 	}
@@ -813,7 +808,7 @@ void SeqPlayer_HOF::doTransition(int type) {
 		break;
 
 	case 1:
-		seq_playTalkText(_vm->_rnd.getRandomBit());
+		playSoundAndDisplaySubTitle(_vm->_rnd.getRandomBit());
 
 		_screen->getPalette(0).fill(0, 256, 0x3F);
 		_screen->fadePalette(_screen->getPalette(0), 16);
@@ -857,14 +852,9 @@ void SeqPlayer_HOF::doTransition(int type) {
 
 	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;
-		}
-
-		//int a = 0x100;
-		//int d = (0x800 << 5) - 0x100;
-		//pal[3 * i] = pal[3 * i + 1] = pal[3 * i + 2] = 0x3f;
+		for (int i = 0; i < 255; i++)
+			pal.fill(i, 1, (pal[3 * i] + pal[3 * i + 1] + pal[3 * i + 2]) / 3);
+		pal.fill(255, 1, 0x3F);
 
 		_screen->fadePalette(pal, 64);
 		_screen->copyPalette(1, 0);
@@ -978,7 +968,7 @@ void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastF
 	}
 
 	int8 frameStep = (startFrame > lastFrame) ? -1 : 1;
-	_animCurrentFrame = startFrame;
+	_animCurrentFrame = startFrame;	
 
 	while (!_vm->shouldQuit() && !finished) {
 		if (checkAbortPlayback())
@@ -1003,7 +993,7 @@ void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastF
 		_screen->copyPage(2, 12);
 
 		updateAllNestedAnimations();
-		seq_processText();
+		updateSubTitles();
 
 		if (wsaObj || callback && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
 			_screen->copyPage(2, 0);
@@ -1025,7 +1015,7 @@ void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastF
 				_screen->updateScreen();
 			}
 
-			seq_processText();
+			updateSubTitles();
 
 			if (!countDownRunning())
 				break;
@@ -1033,7 +1023,7 @@ void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastF
 
 		if (wsaObj) {
 			_animCurrentFrame += frameStep;
-			if (_animCurrentFrame == lastFrame)
+			if ((frameStep > 0 && _animCurrentFrame >= lastFrame) || (frameStep < 0 && _animCurrentFrame < lastFrame))
 				finished = true;
 		}
 
@@ -1045,10 +1035,76 @@ void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastF
 	}
 }
 
+void SeqPlayer_HOF::playDialogueAnimation(uint16 strID, uint16 soundID, int textColor, int textPosX, int textPosY, int textWidth, WSAMovie_v2 *wsaObj, int animStartFrame, int animLastFrame, int animPosX, int animPosY) {
+	int dur = int(strlen(_sequenceStrings[strID])) * (_vm->gameFlags().isTalkie ? 7 : 15);
+	if (_vm->textEnabled()) {
+		int slot = displaySubTitle(strID, textPosX, textPosY, dur, textWidth);
+		_textSlots[slot].textcolor = textColor;
+	}
+	_specialAnimTimeOutTotal = _system->getMillis() + dur * _vm->tickLength();
+	int curframe = animStartFrame;
+
+	if (soundID && _vm->speechEnabled()) {
+		while (_vm->sound()->voiceIsPlaying() && !_abortPlayback)
+			delayTicks(1);
+		playSoundAndDisplaySubTitle(soundID);
+	}
+
+	while (_system->getMillis() < _specialAnimTimeOutTotal && !_abortPlayback) {
+		if (animLastFrame < 0) {
+			int t = ABS(animLastFrame);
+			if (t < curframe)
+				curframe = t;
+		}
+
+		if (ABS(animLastFrame) < curframe)
+			curframe = animStartFrame;
+
+		_specialAnimFrameTimeOut = _system->getMillis() + _animDuration * _vm->tickLength();
+		setCountDown(_animDuration);
+
+		if (wsaObj)
+			wsaObj->displayFrame(curframe % wsaObj->frames(), 2, animPosX, animPosY, 0, 0, 0);
+
+		_screen->copyPage(2, 12);
+		updateSubTitles();
+		delayUntil(MIN(_specialAnimFrameTimeOut, _specialAnimTimeOutTotal));
+
+		if (_vm->speechEnabled() && !_vm->textEnabled() && !_vm->snd_voiceIsPlaying())
+			break;
+
+		if (checkAbortPlayback())
+			if (checkPlaybackStatus())
+				break;
+
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		curframe++;
+	}
+
+	if (_abortPlayback)
+		_vm->sound()->voiceStop();
+
+	if (ABS(animLastFrame) < curframe)
+		curframe = ABS(animLastFrame);
+
+	if (curframe == animStartFrame)
+		curframe++;
+
+	_animCurrentFrame = curframe;
+}
+
 void SeqPlayer_HOF::startNestedAnimation(int animSlot, int sequenceID) {
 	if (_animSlots[animSlot].flags != -1)
 		return;
 
+	if (_target == kLoLDemo) {
+		 return;
+	} else if (_target == kHoFDemo) {
+		assert(sequenceID >= kNestedSequenceHoFDemoWharf2);
+		sequenceID -= kNestedSequenceHoFDemoWharf2;
+	}
+
 	HoFNestedSequence s = _config->nestedSeq[sequenceID];
 
 	if (!_animSlots[animSlot].movie) {
@@ -1167,7 +1223,7 @@ void SeqPlayer_HOF::updateAllNestedAnimations() {
 bool SeqPlayer_HOF::updateNestedAnimation(int animSlot) {
 	uint16 currentFrame = _animSlots[animSlot].currentFrame;
 	uint32 curTick = _system->getMillis() & ~(_vm->tickLength() - 1);
-	
+
 	if (_animSlots[animSlot].callback && currentFrame != _animSlots[animSlot].lastFrame) {
 		_animSlots[animSlot].lastFrame = currentFrame;
 		currentFrame = (this->*_animSlots[animSlot].callback)(_animSlots[animSlot].movie, _animSlots[animSlot].x, _animSlots[animSlot].y, currentFrame);
@@ -1188,7 +1244,10 @@ bool SeqPlayer_HOF::updateNestedAnimation(int animSlot) {
 		int diff = (curTick - _animSlots[animSlot].nextFrame) / (_animSlots[animSlot].frameDelay * _vm->tickLength());
 		if (diff > 0) {
 			currentFrame++;
-			_animSlots[animSlot].nextFrame = curTick;
+			if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+				_animSlots[animSlot].nextFrame += ((curTick - _animSlots[animSlot].nextFrame) * 2 / 3);
+			else
+				_animSlots[animSlot].nextFrame = curTick;
 		}
 	}
 
@@ -1223,120 +1282,66 @@ bool SeqPlayer_HOF::updateNestedAnimation(int animSlot) {
 	return res;
 }
 
-void SeqPlayer_HOF::seq_playTalkText(uint8 chatNum) {
-	assert(chatNum < _sequenceSoundListSize);
-
-	if (chatNum < 12 && !_vm->gameFlags().isDemo && _vm->textEnabled())
-		seq_setTextEntry(chatNum, 160, 168, _textDuration[chatNum], 160);
-
-	_vm->sound()->voicePlay(_sequenceSoundList[chatNum], &_speechHandle);
+void SeqPlayer_HOF::playSoundEffect(uint16 id, int16 vol) {
+	assert(id < _sequenceSoundListSize);
+	_vm->sound()->voicePlay(_sequenceSoundList[id], 0, vol);
 }
 
-void SeqPlayer_HOF::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, int textColor, int x, int y, int width, WSAMovie_v2 *wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos) {
-	int dur = int(strlen(_sequenceStrings[strIndex])) * (_vm->gameFlags().isTalkie ? 7 : 15);
-	if (_vm->textEnabled()) {
-		int entry = seq_setTextEntry(strIndex, x, y, dur, width);
-		_textSlots[entry].textcolor = textColor;
-	}
-	_seqWsaChatTimeout = _system->getMillis() + dur * _vm->tickLength();
-	int curframe = firstframe;
-
-	if (vocIndex && _vm->speechEnabled()) {
-		while (_vm->sound()->voiceIsPlaying() && !_abortPlayback)
-			delayTicks(1);
-		seq_playTalkText(vocIndex);
-	}
-
-	while (_system->getMillis() < _seqWsaChatTimeout && !_abortPlayback) {
-		if (lastframe < 0) {
-			int t = ABS(lastframe);
-			if (t < curframe)
-				curframe = t;
-		}
-
-		if (ABS(lastframe) < curframe)
-			curframe = firstframe;
-
-		_seqWsaChatFrameTimeout = _system->getMillis() + _animDuration * _vm->tickLength();
-		setCountDown(_animDuration);
-
-		if (wsa)
-			wsa->displayFrame(curframe % wsa->frames(), 2, wsaXpos, wsaYpos, 0, 0, 0);
-
-		_screen->copyPage(2, 12);
-
-		seq_processText();
-
-		uint32 tm = _system->getMillis();
-		if (_seqWsaChatFrameTimeout > tm && _seqWsaChatTimeout > tm)
-			_vm->delay(MIN(_seqWsaChatFrameTimeout - tm, _seqWsaChatTimeout - tm));
-
-		if (_vm->speechEnabled() && !_vm->textEnabled() && !_vm->snd_voiceIsPlaying())
-			break;
-
-		_screen->copyPage(2, 0);
-		_screen->updateScreen();
-		curframe++;
-	}
+void SeqPlayer_HOF::playSoundAndDisplaySubTitle(uint16 id) {
+	assert(id < _sequenceSoundListSize);
 
-	if (_abortPlayback)
-		_vm->sound()->voiceStop();
+	if (id < 12 && !_vm->gameFlags().isDemo && _vm->textEnabled())
+		displaySubTitle(id, 160, 168, _textDuration[id], 160);
 
-	if (ABS(lastframe) < curframe)
-		curframe = ABS(lastframe);
+	_vm->sound()->voicePlay(_sequenceSoundList[id], 0);
+}
 
-	if (curframe == firstframe)
-		curframe++;
+void SeqPlayer_HOF::printFadingText(uint16 strID, int x, int y, const uint8 *colorMap, uint8 textcolor) {
+	uint8 cmap[16];
 
-	_animCurrentFrame = curframe;
-}
+	if (checkAbortPlayback())
+		checkPlaybackStatus();
 
-void SeqPlayer_HOF::seq_printCreditsString(uint16 strIndex, int x, int y, const uint8 *colorMap, uint8 textcolor) {
-	uint8 colormap[16];
-	if (_abortPlayback || _vm->shouldQuit() || _result)
+	if (_abortPlayback || _abortRequested || _vm->shouldQuit() || _result)
 		return;
 
 	Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
-
-	memset(&_screen->getPalette(0)[0x2fa], 0x3f, 6);
-	_screen->getPalette(0)[0x2f6] = 0x3f;
-	_screen->getPalette(0)[0x2f5] = 0x20;
-	_screen->getPalette(0)[0x2f4] = 0x30;
-	colormap[0] = colorMap[0];
-	colormap[1] = 0xfd;
-	memcpy(&colormap[2], &colorMap[2], 14);
-	uint8 seqTextColor0 = _seqTextColor[0];
-
-	_seqTextColor[0] = 253;
-	_screen->setTextColorMap(colormap);
-	seq_resetAllTextEntries();
-	seq_setTextEntry(strIndex, x, y, 0x80, 0x78);
-	seq_processText();
+	_screen->getPalette(0).fill(254, 2, 63);
+	_screen->setPaletteIndex(252, 63, 32, 48);
+	cmap[0] = colorMap[0];
+	cmap[1] = 253;
+	memcpy(&cmap[2], &colorMap[2], 14);
+	uint8 col0 = _textColor[0];
+
+	_textColor[0] = 253;
+	_screen->setTextColorMap(cmap);
+	resetAllTextSlots();
+	displaySubTitle(strID, x, y, 128, 120);
+	updateSubTitles();
 	_screen->copyPage(2, 0);
 	_screen->updateScreen();
-	_screen->getPalette(0)[0x2f7] = _screen->getPalette(0)[textcolor * 3];
-	_screen->getPalette(0)[0x2f8] = _screen->getPalette(0)[textcolor * 3 + 1];
-	_screen->getPalette(0)[0x2f9] = _screen->getPalette(0)[textcolor * 3 + 2];
-	_screen->fadePalette(_screen->getPalette(0), 0x18);
+	_screen->getPalette(0).copy(_screen->getPalette(0), textcolor, 1, 253);
+	_screen->fadePalette(_screen->getPalette(0), 24);
 
-	_seqTextColor[0] = textcolor;
+	_textColor[0] = textcolor;
 	_screen->setTextColorMap(colorMap);
-	seq_resetAllTextEntries();
-	seq_setTextEntry(strIndex, x, y, 0x80, 0x78);
-	seq_processText();
+	resetAllTextSlots();
+	displaySubTitle(strID, x, y, 128, 120);
+	updateSubTitles();
 	_screen->copyPage(2, 0);
 	_screen->updateScreen();
-	_screen->getPalette(0)[0x2f7] = _screen->getPalette(0)[0x2f8] = _screen->getPalette(0)[0x2f9] = 0;
+	_screen->getPalette(0).fill(253, 1, 0);
 	_screen->fadePalette(_screen->getPalette(0), 1);
+
 	_screen->copyPage(2, 12);
-	seq_resetAllTextEntries();
+	resetAllTextSlots();
 
-	_seqTextColor[0] = seqTextColor0;
+	_textColor[0] = col0;
 
 	_screen->setFont(of);
 }
 
-int SeqPlayer_HOF::seq_setTextEntry(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width) {
+int SeqPlayer_HOF::displaySubTitle(uint16 strIndex, uint16 posX, uint16 posY, int duration, uint16 width) {
 	for (int i = 0; i < 10; i++) {
 		if (_textSlots[i].duration != -1) {
 			if (i < 9)
@@ -1358,14 +1363,14 @@ int SeqPlayer_HOF::seq_setTextEntry(uint16 strIndex, uint16 posX, uint16 posY, i
 	return -1;
 }
 
-void SeqPlayer_HOF::seq_processText() {
+void SeqPlayer_HOF::updateSubTitles() {
 	int curPage = _screen->setCurPage(2);
 	char outputStr[70];
 
 	for (int i = 0; i < 10; i++) {
 		if (_textSlots[i].startTime + _textSlots[i].duration > _system->getMillis() && _textSlots[i].duration != -1) {
 
-			char *srcStr = seq_preprocessString(_sequenceStrings[_textSlots[i].strIndex], _textSlots[i].width);
+			char *srcStr = preprocessString(_sequenceStrings[_textSlots[i].strIndex], _textSlots[i].width);
 			int yPos = _textSlots[i].y;
 
 			while (*srcStr) {
@@ -1380,7 +1385,7 @@ void SeqPlayer_HOF::seq_processText() {
 				if (*srcStr == '\r')
 					srcStr++;
 
-				uint8 textColor = (_textSlots[i].textcolor >= 0) ? _textSlots[i].textcolor : _seqTextColor[0];
+				uint8 textColor = (_textSlots[i].textcolor >= 0) ? _textSlots[i].textcolor : _textColor[0];
 				_screen->printText(outputStr, _textSlots[i].x - (_screen->getTextWidth(outputStr) / 2), yPos, textColor, 0);
 				yPos += 10;
 			}
@@ -1392,7 +1397,7 @@ void SeqPlayer_HOF::seq_processText() {
 	_screen->setCurPage(curPage);
 }
 
-char *SeqPlayer_HOF::seq_preprocessString(const char *srcStr, int width) {
+char *SeqPlayer_HOF::preprocessString(const char *srcStr, int width) {
 	char *dstStr = _tempString;
 	int lineStart = 0;
 	int linePos = 0;
@@ -1428,7 +1433,7 @@ void SeqPlayer_HOF::waitForSubTitlesTimeout() {
 			delayTicks(1);
 	}
 
-	seq_resetAllTextEntries();
+	resetAllTextSlots();
 }
 
 uint32 SeqPlayer_HOF::ticksTillSubTitlesTimeout() {
@@ -1448,7 +1453,7 @@ uint32 SeqPlayer_HOF::ticksTillSubTitlesTimeout() {
 	return (longest + (tl - 1)) / tl;
 }
 
-void SeqPlayer_HOF::seq_resetAllTextEntries() {
+void SeqPlayer_HOF::resetAllTextSlots() {
 	for (int i = 0; i < 10; i++)
 		_textSlots[i].duration = -1;
 }
@@ -1458,7 +1463,7 @@ void SeqPlayer_HOF::fadeOutMusic() {
 	delayTicks(80);
 }
 
-void SeqPlayer_HOF::seq_finaleActorScreen() {
+void SeqPlayer_HOF::playHoFTalkieCredits() {
 	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 };
 
@@ -1483,7 +1488,7 @@ void SeqPlayer_HOF::seq_finaleActorScreen() {
 	memcpy(dataPtr, talkieCredits, talkieCreditsSize);
 	_vm->staticres()->unloadId(k2SeqplayCredits);
 
-	seq_displayScrollText(dataPtr, &d, 2, 6, 5, 1, Screen::FID_GOLDFONT_FNT, Screen::FID_GOLDFONT_FNT, 0, talkieCreditsSpecial);
+	displayHoFTalkieScrollText(dataPtr, &d, 2, 6, 5, 1, Screen::FID_GOLDFONT_FNT, Screen::FID_GOLDFONT_FNT, 0, talkieCreditsSpecial);
 	delayTicks(8);
 
 	delete[] dataPtr;
@@ -1492,7 +1497,7 @@ void SeqPlayer_HOF::seq_finaleActorScreen() {
 	_vm->sound()->loadSoundFile(0);
 }
 
-void SeqPlayer_HOF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed,
+void SeqPlayer_HOF::displayHoFTalkieScrollText(uint8 *data, const ScreenDim *d, int tempPage1, int tempPage2, int speed,
 	int step, Screen::FontId fid1, Screen::FontId fid2, const uint8 *shapeData, const char *const *specialData) {
 	if (!data)
 		return;
@@ -1660,6 +1665,10 @@ void SeqPlayer_HOF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int t
 			cnt = 0;
 		}
 
+		if (checkAbortPlayback())
+			if (checkPlaybackStatus())
+				loop = false;
+
 		if (!cnt || _abortPlayback)
 			loop = false;
 	}
@@ -1667,39 +1676,39 @@ void SeqPlayer_HOF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int t
 	_vm->sound()->beginFadeOut();
 	_screen->fadeToBlack();
 
-	_abortPlayback = false;
+	_abortPlayback = _abortRequested = false;
 
 	delete[] textData;
 }
 
-void SeqPlayer_HOF::seq_scrollPage(int bottom, int top) {
+void SeqPlayer_HOF::updateDemoAdText(int bottom, int top) {
 	int dstY, dstH, srcH;
 
 	static const ScreenDim d = { 0x00, 0x00, 0x28, 0x320, 0xFF, 0xFE, 0x00, 0x00 };
 
-	if (_seqScrollTextCounter - (top - 1) < 0) {
-		dstY = top - _seqScrollTextCounter;
-		dstH = _seqScrollTextCounter;
+	if (_scrollProgressCounter - (top - 1) < 0) {
+		dstY = top - _scrollProgressCounter;
+		dstH = _scrollProgressCounter;
 		srcH = 0;
 	} else {
 		dstY = 0;
-		srcH = _seqScrollTextCounter - top;
+		srcH = _scrollProgressCounter - top;
 		dstH = (400 - srcH <= top) ? 400 - srcH : top;
 	}
 
 	if (dstH > 0) {
-		assert(_hofDemoAnimData);
-		for (int i = 0; i < 4; i++) {
-			const HoFSeqItemAnimData *def = &_hofDemoAnimData[i];
-			ActiveItemAnim *a = &_hofDemoActiveItemAnim[i];
-
-			_screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4);
-			_screen->drawShape(4, _hofDemoItemShapes[def->itemIndex + def->frames[a->currentFrame]], 12, def->y - 8, 0, 0);
-			if (_animCurrentFrame % 2 == 0)
-				a->currentFrame = (a->currentFrame + 1) % 20;
+		if (_hofDemoAnimData) {
+			for (int i = 0; i < 4; i++) {
+				const HoFSeqItemAnimData *def = &_hofDemoAnimData[i];
+				ActiveItemAnim *a = &_hofDemoActiveItemAnim[i];
+
+				_screen->fillRect(12, def->y - 8, 28, def->y + 8, 0, 4);
+				_screen->drawShape(4, _hofDemoItemShapes[def->itemIndex + def->frames[a->currentFrame]], 12, def->y - 8, 0, 0);
+				if (_callbackCurrentFrame % 2 == 0)
+					a->currentFrame = (a->currentFrame + 1) % 20;
+			}
 		}
-		assert(_screenHoF);
-		_screenHoF->copyRegionEx(4, 0, srcH, 2, 2, dstY + bottom, 320, dstH, &d);
+		_screen->copyRegionEx(4, 0, srcH, 2, 2, dstY + bottom, 320, dstH, &d);
 	}
 }
 
@@ -1722,6 +1731,8 @@ void SeqPlayer_HOF::delayUntil(uint32 dest) {
 
 void SeqPlayer_HOF::setCountDown(uint32 ticks) {
 	_countDownRemainder = ticks * _vm->tickLength();
+	if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
+		_countDownRemainder = _countDownRemainder * 2 / 3;
 	_countDownLastUpdate = _system->getMillis() & ~(_vm->tickLength() - 1);
 }
 	
@@ -1790,10 +1801,10 @@ int SeqPlayer_HOF::cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		_vm->sound()->playTrack(4);
 		frameEnd = _system->getMillis() + 60 * _vm->tickLength();
 
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
+		_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+		_screen->setTextColorMap(_textColorMap);
 
 		delayUntil(frameEnd);
 		break;
@@ -1822,7 +1833,7 @@ int SeqPlayer_HOF::cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		break;
 
 	case 120:
-		seq_playTalkText(0);
+		playSoundAndDisplaySubTitle(0);
 		break;
 
 	case 200:
@@ -1844,25 +1855,15 @@ int SeqPlayer_HOF::cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 	case 282:
 		startNestedAnimation(0, kNestedSequenceForest);
-		seq_playTalkText(1);
+		playSoundAndDisplaySubTitle(1);
 		break;
 
 	CASE_ALT(434, 354)
-	/*case 354:
-	case 434:
-		if (!((_callbackCurrentFrame == 354 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 434 && _vm->gameFlags().platform == Common::kPlatformPC)))
-			break;*/
-
 		closeNestedAnimation(0);
 		startNestedAnimation(0, kNestedSequenceDragon);
 		break;
 
 	CASE_ALT(540, 400)
-	/*case 400:
-	case 540:
-		if (!((_callbackCurrentFrame == 400 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 540 && _vm->gameFlags().platform == Common::kPlatformPC)))
-			break;*/
-
 		waitForSubTitlesTimeout();
 		closeNestedAnimation(0);
 		setCountDown(0);
@@ -1885,16 +1886,16 @@ int SeqPlayer_HOF::cbHOF_library(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 		assert(_screenHoF);
 		_screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+		_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
 
-		_screen->setTextColorMap(_seqTextColorMap);
+		_screen->setTextColorMap(_textColorMap);
 		break;
 
 	case 1:
 		startNestedAnimation(0, kNestedSequenceLibrary3);
-		seq_playTalkText(4);
+		playSoundAndDisplaySubTitle(4);
 		break;
 
 	case 100:
@@ -1911,7 +1912,7 @@ int SeqPlayer_HOF::cbHOF_library(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		break;
 
 	case 104:
-		seq_playTalkText(5);
+		playSoundAndDisplaySubTitle(5);
 		break;
 
 	case 240:
@@ -1928,15 +1929,10 @@ int SeqPlayer_HOF::cbHOF_library(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		_screen->updateScreen();
 
 		startNestedAnimation(0, kNestedSequenceMarco);
-		seq_playTalkText(6);
+		playSoundAndDisplaySubTitle(6);
 		break;
 
 	CASE_ALT(660, 480)
-	/*case 480:
-	case 660:
-		if (!((_callbackCurrentFrame == 480 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 660 && _vm->gameFlags().platform == Common::kPlatformPC)))
-			break;*/
-
 		_screen->copyPage(2, 12);
 		waitForSubTitlesTimeout();
 		closeNestedAnimation(0);
@@ -1960,18 +1956,18 @@ int SeqPlayer_HOF::cbHOF_hand(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 		assert(_screenHoF);
 		_screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+		_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
 
-		_screen->setTextColorMap(_seqTextColorMap);
+		_screen->setTextColorMap(_textColorMap);
 		break;
 
 	case 1:
 		startNestedAnimation(0, kNestedSequenceHand1a);
 		startNestedAnimation(1, kNestedSequenceHand1b);
 		startNestedAnimation(2, kNestedSequenceHand1c);
-		seq_playTalkText(7);
+		playSoundAndDisplaySubTitle(7);
 		break;
 
 	case 201:
@@ -1984,47 +1980,27 @@ int SeqPlayer_HOF::cbHOF_hand(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		closeNestedAnimation(1);
 		closeNestedAnimation(2);
 		startNestedAnimation(0, kNestedSequenceHand2);
-		seq_playTalkText(8);
+		playSoundAndDisplaySubTitle(8);
 		break;
 
 	CASE_ALT(395, 260)
-	/*case 260:
-	case 395:
-		if (!((_callbackCurrentFrame == 260 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 395 && _vm->gameFlags().platform == Common::kPlatformPC)))
-			break;*/
-
 		waitForSubTitlesTimeout();
 		closeNestedAnimation(0);
 		startNestedAnimation(1, kNestedSequenceHand3);
-		seq_playTalkText(9);
+		playSoundAndDisplaySubTitle(9);
 		break;
 
 	CASE_ALT(500, 365)
-	/*case 365:
-	case 500:
-		if (!((_callbackCurrentFrame == 365 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 500 && _vm->gameFlags().platform == Common::kPlatformPC)))
-			break;*/
-
 		waitForSubTitlesTimeout();
 		closeNestedAnimation(1);
 		startNestedAnimation(0, kNestedSequenceHand4);
 		break;
 
 	CASE_ALT(540, 405)
-	/*case 405:
-	case 540:
-		if (!((_callbackCurrentFrame == 405 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 540 && _vm->gameFlags().platform == Common::kPlatformPC)))
-			break;*/
-
-		seq_playTalkText(10);
+		playSoundAndDisplaySubTitle(10);
 		break;
 
 	CASE_ALT(630, 484)
-	/*case 484:
-	case 630:
-		if (!((_callbackCurrentFrame == 484 && (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)) || (_callbackCurrentFrame == 630 && _vm->gameFlags().platform == Common::kPlatformPC)))
-			break;*/
-
 		waitForSubTitlesTimeout();
 		closeNestedAnimation(0);
 		setCountDown(0);
@@ -2053,16 +2029,16 @@ int SeqPlayer_HOF::cbHOF_point(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	case 0:
 		_vm->sound()->playTrack(7);
 
-		_seqTextColor[1] = 0xf7;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
+		_textColor[1] = 0xf7;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+		_screen->setTextColorMap(_textColorMap);
 		assert(_screenHoF);
 		_screenHoF->generateGrayOverlay(_screen->getPalette(0), _screen->getPalette(3).getData(), 0x24, 0, 0, 0, 0x100, false);
 		break;
 
 	case 1:
-		seq_playTalkText(11);
+		playSoundAndDisplaySubTitle(11);
 		break;
 
 	default:
@@ -2084,17 +2060,17 @@ int SeqPlayer_HOF::cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	case 0:
 		_vm->sound()->playTrack(8);
 
-		_seqTextColor[1] = 0xfd;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColorMap[1] = _seqTextColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
+		_textColor[1] = 0xfd;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColorMap[1] = _textColor[0] = _screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 255) & 0xff;
+		_screen->setTextColorMap(_textColorMap);
 		break;
 
 	case 1:
 		if (_vm->gameFlags().isTalkie) {
-			seq_playWsaSyncDialogue(21, 13, -1, 140, 70, 160, wsaObj, 0, 8, x, y);
+			playDialogueAnimation(21, 13, -1, 140, 70, 160, wsaObj, 0, 8, x, y);
 		} else {
-			seq_setTextEntry(21, 140, 70, 200, 160);
+			displaySubTitle(21, 140, 70, 200, 160);
 			_animDuration = 200;
 		}
 		break;
@@ -2108,21 +2084,21 @@ int SeqPlayer_HOF::cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 	case 9:
 		if (_vm->gameFlags().isTalkie)
-			seq_playWsaSyncDialogue(13, 14, -1, 140, (_vm->gameFlags().lang == Common::FR_FRA
+			playDialogueAnimation(13, 14, -1, 140, (_vm->gameFlags().lang == Common::FR_FRA
 				|| _vm->gameFlags().lang == Common::DE_DEU) ? 50 : 70, 160, wsaObj, 9, 15, x, y);
 		break;
 
 	case 10:
 		if (!_vm->gameFlags().isTalkie) {
 			waitForSubTitlesTimeout();
-			seq_setTextEntry(13, 140, 50, _textDuration[13], 160);
+			displaySubTitle(13, 140, 50, _textDuration[13], 160);
 			_animDuration = 300;
 		}
 		break;
 
 	case 16:
 		if (_vm->gameFlags().isTalkie)
-			seq_playWsaSyncDialogue(18, 15, -1, 140, (_vm->gameFlags().lang == Common::FR_FRA) ? 50 :
+			playDialogueAnimation(18, 15, -1, 140, (_vm->gameFlags().lang == Common::FR_FRA) ? 50 :
 				(_vm->gameFlags().lang == Common::DE_DEU ? 40 : 70), 160, wsaObj, 10, 16, x, y);
 		break;
 
@@ -2134,7 +2110,7 @@ int SeqPlayer_HOF::cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	case 20:
 		if (!_vm->gameFlags().isTalkie) {
 			waitForSubTitlesTimeout();
-			seq_setTextEntry(18, 160, 50, _textDuration[18], 160);
+			displaySubTitle(18, 160, 50, _textDuration[18], 160);
 			_animDuration = 200;
 		}
 		break;
@@ -2145,10 +2121,10 @@ int SeqPlayer_HOF::cbHOF_zanfaun(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 	case 46:
 		if (_vm->gameFlags().isTalkie) {
-			seq_playWsaSyncDialogue(16, 16, -1, 200, 50, 120, wsaObj, 46, 46, x, y);
+			playDialogueAnimation(16, 16, -1, 200, 50, 120, wsaObj, 46, 46, x, y);
 		} else {
 			waitForSubTitlesTimeout();
-			seq_setTextEntry(16, 200, 50, _textDuration[16], 120);
+			displaySubTitle(16, 200, 50, _textDuration[16], 120);
 		}
 
 		setCountDown(120);
@@ -2166,13 +2142,13 @@ int SeqPlayer_HOF::cbHOF_over1(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	if (frm == 2)
 		waitForSubTitlesTimeout();
 	else if (frm == 3)
-		seq_playTalkText(12);
+		playSoundAndDisplaySubTitle(12);
 	return frm;
 }
 
 int SeqPlayer_HOF::cbHOF_over2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	if (frm == 1)
-		seq_playTalkText(12);
+		playSoundAndDisplaySubTitle(12);
 	return frm;
 }
 
@@ -2180,7 +2156,7 @@ int SeqPlayer_HOF::cbHOF_forest(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	if (frm == 11)
 		waitForSubTitlesTimeout();
 	else if (frm == 12)
-		seq_playTalkText(2);
+		playSoundAndDisplaySubTitle(2);
 
 	return frm;
 }
@@ -2189,17 +2165,15 @@ int SeqPlayer_HOF::cbHOF_dragon(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	if (frm == 11)
 		waitForSubTitlesTimeout();
 	else if (frm == 3)
-		seq_playTalkText(3);
+		playSoundAndDisplaySubTitle(3);
 	return frm;
 }
 
 int SeqPlayer_HOF::cbHOF_darm(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
 int SeqPlayer_HOF::cbHOF_library2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
@@ -2212,7 +2186,6 @@ int SeqPlayer_HOF::cbHOF_marco(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 }
 
 int SeqPlayer_HOF::cbHOF_hand1a(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
@@ -2229,22 +2202,20 @@ int SeqPlayer_HOF::cbHOF_hand1c(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 }
 
 int SeqPlayer_HOF::cbHOF_hand2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
 int SeqPlayer_HOF::cbHOF_hand3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	//NULLSUB (at least in FM-TOWNS version)
 	return frm;
 }
 
 int SeqPlayer_HOF::cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	uint32 frameEnd = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	int chatFirstFrame = 0;
-	int chatLastFrame = 0;
+	int subTitleX = 0;
+	int subTitleY = 0;
+	int subTitleW = 0;
+	int subTitleFirstFrame = 0;
+	int subTitleLastFrame = 0;
 	uint16 voiceIndex = 0;
 
 	switch (frm) {
@@ -2255,33 +2226,33 @@ int SeqPlayer_HOF::cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	case 0:
 		_vm->sound()->playTrack(3);
 
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
+		_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColor[0] = _textColorMap[1] = 0xff;
+		_screen->setTextColorMap(_textColorMap);
 
 		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
-		seq_printCreditsString(81, 240, 70, _seqTextColorMap, 252);
-		seq_printCreditsString(82, 240, 90, _seqTextColorMap, _seqTextColor[0]);
+		printFadingText(81, 240, 70, _textColorMap, 252);
+		printFadingText(82, 240, 90, _textColorMap, _textColor[0]);
 		_screen->copyPage(2, 12);
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 28 : 24);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 28 : 24);
 		delayUntil(frameEnd);
-		_seqTextColor[0] = 1;
+		_textColor[0] = 1;
 
 		if (_vm->gameFlags().isTalkie) {
-			chatY = (_vm->gameFlags().lang == Common::FR_FRA) ? 70 : 78;
-			chatFirstFrame = 9;
-			chatLastFrame = 15;
+			subTitleY = (_vm->gameFlags().lang == Common::FR_FRA) ? 70 : 78;
+			subTitleFirstFrame = 9;
+			subTitleLastFrame = 15;
 			voiceIndex = 34;
 		} else {
-			chatY = (_vm->gameFlags().lang == Common::FR_FRA) ? 78 : 70;
-			chatFirstFrame = 0;
-			chatLastFrame = 8;
+			subTitleY = (_vm->gameFlags().lang == Common::FR_FRA) ? 78 : 70;
+			subTitleFirstFrame = 0;
+			subTitleLastFrame = 8;
 		}
-		chatX = (_vm->gameFlags().lang == Common::FR_FRA) ? 84 : 88;
-		chatW = 100;
+		subTitleX = (_vm->gameFlags().lang == Common::FR_FRA) ? 84 : 88;
+		subTitleW = 100;
 
-		seq_playWsaSyncDialogue(22, voiceIndex, 187, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		playDialogueAnimation(22, voiceIndex, 187, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
 		break;
 
 	case 9:
@@ -2292,24 +2263,24 @@ int SeqPlayer_HOF::cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		_animDuration = 12;
 
 		if (_vm->gameFlags().lang == Common::FR_FRA) {
-			chatX = 80;
-			chatW = 112;
+			subTitleX = 80;
+			subTitleW = 112;
 		} else {
-			chatX = (_vm->gameFlags().lang == Common::DE_DEU) ? 84 : 96;
-			chatW = 100;
+			subTitleX = (_vm->gameFlags().lang == Common::DE_DEU) ? 84 : 96;
+			subTitleW = 100;
 		}
 
 		if (_vm->gameFlags().isTalkie) {
-			chatFirstFrame = 0;
-			chatLastFrame = 8;
+			subTitleFirstFrame = 0;
+			subTitleLastFrame = 8;
 			voiceIndex = 35;
 		} else {
-			chatFirstFrame = 9;
-			chatLastFrame = 15;
+			subTitleFirstFrame = 9;
+			subTitleLastFrame = 15;
 		}
-		chatY = 70;
+		subTitleY = 70;
 
-		seq_playWsaSyncDialogue(23, voiceIndex, 137, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		playDialogueAnimation(23, voiceIndex, 137, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
 		if (_vm->gameFlags().isTalkie)
 			_animCurrentFrame = 17;
 		break;
@@ -2324,77 +2295,77 @@ int SeqPlayer_HOF::cbHOF_funters(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 int SeqPlayer_HOF::cbHOF_ferb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	uint32 frameEnd = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	int chatFirstFrame = 0;
-	int chatLastFrame = 0;
+	int subTitleX = 0;
+	int subTitleY = 0;
+	int subTitleW = 0;
+	int subTitleFirstFrame = 0;
+	int subTitleLastFrame = 0;
 	uint16 voiceIndex = 0;
 
 	switch (frm) {
 	case -2:
 		doTransition(9);
 		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
-		seq_printCreditsString(34, 240, _vm->gameFlags().isTalkie ? 60 : 40, _seqTextColorMap, 252);
-		seq_printCreditsString(35, 240, _vm->gameFlags().isTalkie ? 70 : 50, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(36, 240, _vm->gameFlags().isTalkie ? 90 : 70, _seqTextColorMap, 252);
-		seq_printCreditsString(37, 240, _vm->gameFlags().isTalkie ? 100 : 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(38, 240, _vm->gameFlags().isTalkie ? 120 : 110, _seqTextColorMap, 252);
-		seq_printCreditsString(39, 240, _vm->gameFlags().isTalkie ? 130 : 120, _seqTextColorMap, _seqTextColor[0]);
+		printFadingText(34, 240, _vm->gameFlags().isTalkie ? 60 : 40, _textColorMap, 252);
+		printFadingText(35, 240, _vm->gameFlags().isTalkie ? 70 : 50, _textColorMap, _textColor[0]);
+		printFadingText(36, 240, _vm->gameFlags().isTalkie ? 90 : 70, _textColorMap, 252);
+		printFadingText(37, 240, _vm->gameFlags().isTalkie ? 100 : 90, _textColorMap, _textColor[0]);
+		printFadingText(38, 240, _vm->gameFlags().isTalkie ? 120 : 110, _textColorMap, 252);
+		printFadingText(39, 240, _vm->gameFlags().isTalkie ? 130 : 120, _textColorMap, _textColor[0]);
 		if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
-			seq_printCreditsString(103, 240, 130, _seqTextColorMap, _seqTextColor[0]);
+			printFadingText(103, 240, 130, _textColorMap, _textColor[0]);
 		delayUntil(frameEnd);
 		setCountDown(0);
 		break;
 
 	case 0:
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 255;
-		_screen->setTextColorMap(_seqTextColorMap);
+		_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColor[0] = _textColorMap[1] = 255;
+		_screen->setTextColorMap(_textColorMap);
 		break;
 
 	case 5:
 		if (!_vm->gameFlags().isTalkie)
-			seq_playTalkText(18);
+			playSoundAndDisplaySubTitle(18);
 		_animDuration = 16;
 
 		if (_vm->gameFlags().isTalkie) {
-			chatFirstFrame = 5;
-			chatLastFrame = 8;
+			subTitleFirstFrame = 5;
+			subTitleLastFrame = 8;
 			voiceIndex = 22;
 		} else {
-			chatLastFrame = 14;
+			subTitleLastFrame = 14;
 		}
-		chatX = 116;
-		chatY = 90;
-		chatW = 60;
+		subTitleX = 116;
+		subTitleY = 90;
+		subTitleW = 60;
 
-		seq_playWsaSyncDialogue(24, voiceIndex, 149, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		playDialogueAnimation(24, voiceIndex, 149, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
 		break;
 
 	case 11:
 		if (_vm->gameFlags().isTalkie)
-			seq_playWsaSyncDialogue(24, 22, 149, 116, 90, 60, wsaObj, 11, 14, x, y);
+			playDialogueAnimation(24, 22, 149, 116, 90, 60, wsaObj, 11, 14, x, y);
 		break;
 
 	case 16:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 23 : 19);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 23 : 19);
 		_animDuration = _vm->gameFlags().isTalkie ? 20 : 16;
 
 		if (_vm->gameFlags().lang == Common::FR_FRA) {
-			chatY = 48;
-			chatW = 88;
+			subTitleY = 48;
+			subTitleW = 88;
 		} else {
-			chatY = 60;
-			chatW = 100;
+			subTitleY = 60;
+			subTitleW = 100;
 		}
-		chatX = 60;
+		subTitleX = 60;
 
 		if (_vm->gameFlags().isTalkie)
 			voiceIndex = 36;
 
-		seq_playWsaSyncDialogue(25, voiceIndex, 143, chatX, chatY, chatW, wsaObj, 16, 25, x, y);
+		playDialogueAnimation(25, voiceIndex, 143, subTitleX, subTitleY, subTitleW, wsaObj, 16, 25, x, y);
 		_animDuration = 16;
 		break;
 
@@ -2408,9 +2379,9 @@ int SeqPlayer_HOF::cbHOF_ferb(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 int SeqPlayer_HOF::cbHOF_fish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	uint32 frameEnd = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
+	int subTitleX = 0;
+	int subTitleY = 0;
+	int subTitleW = 0;
 	uint16 voiceIndex = 0;
 
 	switch (frm) {
@@ -2418,61 +2389,61 @@ int SeqPlayer_HOF::cbHOF_fish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		doTransition(9);
 		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
 
-		seq_printCreditsString(40, 240, _vm->gameFlags().isTalkie ? 55 : 40, _seqTextColorMap, 252);
-		seq_printCreditsString(41, 240, _vm->gameFlags().isTalkie ? 65 : 50, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(42, 240, _vm->gameFlags().isTalkie ? 75 : 60, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(43, 240, _vm->gameFlags().isTalkie ? 95 : 80, _seqTextColorMap, 252);
-		seq_printCreditsString(44, 240, _vm->gameFlags().isTalkie ? 105 : 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(93, 240, _vm->gameFlags().isTalkie ? 125 : 110, _seqTextColorMap, 252);
-		seq_printCreditsString(94, 240, _vm->gameFlags().isTalkie ? 135 : 120, _seqTextColorMap, _seqTextColor[0]);
+		printFadingText(40, 240, _vm->gameFlags().isTalkie ? 55 : 40, _textColorMap, 252);
+		printFadingText(41, 240, _vm->gameFlags().isTalkie ? 65 : 50, _textColorMap, _textColor[0]);
+		printFadingText(42, 240, _vm->gameFlags().isTalkie ? 75 : 60, _textColorMap, _textColor[0]);
+		printFadingText(43, 240, _vm->gameFlags().isTalkie ? 95 : 80, _textColorMap, 252);
+		printFadingText(44, 240, _vm->gameFlags().isTalkie ? 105 : 90, _textColorMap, _textColor[0]);
+		printFadingText(93, 240, _vm->gameFlags().isTalkie ? 125 : 110, _textColorMap, 252);
+		printFadingText(94, 240, _vm->gameFlags().isTalkie ? 135 : 120, _textColorMap, _textColor[0]);
 		delayUntil(frameEnd);
 		setCountDown(0);
 		break;
 
 	case 0:
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
+		_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColor[0] = _textColorMap[1] = 0xff;
+		_screen->setTextColorMap(_textColorMap);
 		break;
 
 	case 4:
-		chatX = 94;
-		chatY = 42;
-		chatW = 100;
+		subTitleX = 94;
+		subTitleY = 42;
+		subTitleW = 100;
 		if (_vm->gameFlags().isTalkie)
 			voiceIndex = 37;
-		seq_playWsaSyncDialogue(26, voiceIndex, 149, chatX, chatY, chatW, wsaObj, 3, 12, x, y);
+		playDialogueAnimation(26, voiceIndex, 149, subTitleX, subTitleY, subTitleW, wsaObj, 3, 12, x, y);
 		break;
 
 	case 14:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 19 : 15);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 19 : 15);
 		break;
 
 	case 23:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 20 : 16);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 20 : 16);
 		break;
 
 	case 29:
-		chatX = (_vm->gameFlags().lang == Common::DE_DEU) ? 82 : ((_vm->gameFlags().lang == Common::FR_FRA) ? 92 : 88);
-		chatY = 40;
-		chatW = 100;
+		subTitleX = (_vm->gameFlags().lang == Common::DE_DEU) ? 82 : ((_vm->gameFlags().lang == Common::FR_FRA) ? 92 : 88);
+		subTitleY = 40;
+		subTitleW = 100;
 
 		if (_vm->gameFlags().isTalkie) {
 			if (_vm->gameFlags().lang == Common::DE_DEU)
-				chatY = 35;
+				subTitleY = 35;
 			voiceIndex = 38;
 		}
 
-		seq_playWsaSyncDialogue(27, voiceIndex, 187, chatX, chatY, chatW, wsaObj, 28, 34, x, y);
+		playDialogueAnimation(27, voiceIndex, 187, subTitleX, subTitleY, subTitleW, wsaObj, 28, 34, x, y);
 		break;
 
 	case 45:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 21 : 17);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 21 : 17);
 		break;
 
 	case 50:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 29 : 25);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 29 : 25);
 		break;
 
 	default:
@@ -2485,11 +2456,11 @@ int SeqPlayer_HOF::cbHOF_fish(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 int SeqPlayer_HOF::cbHOF_fheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	uint32 frameEnd = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	int chatFirstFrame = 0;
-	int chatLastFrame = 0;
+	int subTitleX = 0;
+	int subTitleY = 0;
+	int subTitleW = 0;
+	int subTitleFirstFrame = 0;
+	int subTitleLastFrame = 0;
 	uint16 voiceIndex = 0;
 
 	switch (frm) {
@@ -2499,61 +2470,61 @@ int SeqPlayer_HOF::cbHOF_fheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		_screen->updateScreen();
 		doTransition(9);
 		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
-		seq_printCreditsString(49, 240, 20, _seqTextColorMap, 252);
-		seq_printCreditsString(50, 240, 30, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(51, 240, 40, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(52, 240, 50, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(53, 240, 60, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(54, 240, 70, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(55, 240, 80, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(56, 240, 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(57, 240, 100, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(58, 240, 110, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(60, 240, 120, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(61, 240, 130, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(62, 240, 140, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(63, 240, 150, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(64, 240, 160, _seqTextColorMap, _seqTextColor[0]);
+		printFadingText(49, 240, 20, _textColorMap, 252);
+		printFadingText(50, 240, 30, _textColorMap, _textColor[0]);
+		printFadingText(51, 240, 40, _textColorMap, _textColor[0]);
+		printFadingText(52, 240, 50, _textColorMap, _textColor[0]);
+		printFadingText(53, 240, 60, _textColorMap, _textColor[0]);
+		printFadingText(54, 240, 70, _textColorMap, _textColor[0]);
+		printFadingText(55, 240, 80, _textColorMap, _textColor[0]);
+		printFadingText(56, 240, 90, _textColorMap, _textColor[0]);
+		printFadingText(57, 240, 100, _textColorMap, _textColor[0]);
+		printFadingText(58, 240, 110, _textColorMap, _textColor[0]);
+		printFadingText(60, 240, 120, _textColorMap, _textColor[0]);
+		printFadingText(61, 240, 130, _textColorMap, _textColor[0]);
+		printFadingText(62, 240, 140, _textColorMap, _textColor[0]);
+		printFadingText(63, 240, 150, _textColorMap, _textColor[0]);
+		printFadingText(64, 240, 160, _textColorMap, _textColor[0]);
 
 		delayUntil(frameEnd);
 		setCountDown(0);
 		break;
 
 	case 0:
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
+		_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColor[0] = _textColorMap[1] = 0xff;
+		_screen->setTextColorMap(_textColorMap);
 		break;
 
 	case 2:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 25 : 21);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 25 : 21);
 
 		if (_vm->gameFlags().lang == Common::FR_FRA) {
-			chatX = 92;
-			chatY = 72;
+			subTitleX = 92;
+			subTitleY = 72;
 		} else {
-			chatX = (_vm->gameFlags().lang == Common::DE_DEU) ? 90 : 98;
-			chatY = 84;
+			subTitleX = (_vm->gameFlags().lang == Common::DE_DEU) ? 90 : 98;
+			subTitleY = 84;
 		}
 
 		if (_vm->gameFlags().isTalkie) {
-			chatFirstFrame = 8;
-			chatLastFrame = 9;
+			subTitleFirstFrame = 8;
+			subTitleLastFrame = 9;
 			voiceIndex = 39;
 		} else {
-			chatFirstFrame = 2;
-			chatLastFrame = -8;
+			subTitleFirstFrame = 2;
+			subTitleLastFrame = -8;
 		}
-		chatW = 100;
+		subTitleW = 100;
 
-		seq_playWsaSyncDialogue(28, voiceIndex, -1, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		playDialogueAnimation(28, voiceIndex, -1, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
 		if (_vm->gameFlags().isTalkie)
 			_animCurrentFrame = 4;
 		break;
 
 	case 9:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 24 : 20);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 24 : 20);
 		_animDuration = 100;
 		break;
 
@@ -2567,9 +2538,9 @@ int SeqPlayer_HOF::cbHOF_fheep(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 int SeqPlayer_HOF::cbHOF_farmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	uint32 frameEnd = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
+	int subTitleX = 0;
+	int subTitleY = 0;
+	int subTitleW = 0;
 	uint16 voiceIndex = 0;
 
 	switch (frm) {
@@ -2579,52 +2550,52 @@ int SeqPlayer_HOF::cbHOF_farmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		_screen->updateScreen();
 		doTransition(9);
 		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
-		seq_printCreditsString(45, 240, 40, _seqTextColorMap, 252);
-		seq_printCreditsString(46, 240, 50, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(47, 240, 60, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(83, 240, 80, _seqTextColorMap, 252);
-		seq_printCreditsString(48, 240, 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(65, 240, 110, _seqTextColorMap, 252);
-		seq_printCreditsString(66, 240, 120, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(67, 240, 130, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(68, 240, 140, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(69, 240, 150, _seqTextColorMap, _seqTextColor[0]);
+		printFadingText(45, 240, 40, _textColorMap, 252);
+		printFadingText(46, 240, 50, _textColorMap, _textColor[0]);
+		printFadingText(47, 240, 60, _textColorMap, _textColor[0]);
+		printFadingText(83, 240, 80, _textColorMap, 252);
+		printFadingText(48, 240, 90, _textColorMap, _textColor[0]);
+		printFadingText(65, 240, 110, _textColorMap, 252);
+		printFadingText(66, 240, 120, _textColorMap, _textColor[0]);
+		printFadingText(67, 240, 130, _textColorMap, _textColor[0]);
+		printFadingText(68, 240, 140, _textColorMap, _textColor[0]);
+		printFadingText(69, 240, 150, _textColorMap, _textColor[0]);
 		if (_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98)
-			seq_printCreditsString(104, 240, 160, _seqTextColorMap, _seqTextColor[0]);
+			printFadingText(104, 240, 160, _textColorMap, _textColor[0]);
 		delayUntil(frameEnd);
 		setCountDown(0);
 		break;
 
 	case 0:
-		_seqTextColor[1] = 1 + (_screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 254) & 0xff);
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColorMap[1] = _seqTextColor[0] = 1 + (_screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 254) & 0xff);
-		_screen->setTextColorMap(_seqTextColorMap);
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 30 : 26);
+		_textColor[1] = 1 + (_screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 254) & 0xff);
+		memset(_textColorMap, _textColor[1], 16);
+		_textColorMap[1] = _textColor[0] = 1 + (_screen->findLeastDifferentColor(_textColorPresets + 3, _screen->getPalette(0), 1, 254) & 0xff);
+		_screen->setTextColorMap(_textColorMap);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 30 : 26);
 		break;
 
 	case 6:
 		if (_vm->gameFlags().isTalkie)
-			seq_playTalkText(18);
+			playSoundAndDisplaySubTitle(18);
 		break;
 
 	case 12:
 		if (!_vm->gameFlags().isTalkie)
-			seq_playTalkText(14);
+			playSoundAndDisplaySubTitle(14);
 
-		chatX = 90;
-		chatY = 30;
-		chatW = 100;
+		subTitleX = 90;
+		subTitleY = 30;
+		subTitleW = 100;
 
 		if (_vm->gameFlags().isTalkie) {
 			if (_vm->gameFlags().lang == Common::FR_FRA || _vm->gameFlags().lang == Common::DE_DEU) {
-				chatX = 75;
-				chatY = 25;
+				subTitleX = 75;
+				subTitleY = 25;
 			}
 			voiceIndex = 40;
 		}
 
-		seq_playWsaSyncDialogue(29, voiceIndex, 150, chatX, chatY, chatW, wsaObj, 12, -21, x, y);
+		playDialogueAnimation(29, voiceIndex, 150, subTitleX, subTitleY, subTitleW, wsaObj, 12, -21, x, y);
 		break;
 
 	default:
@@ -2637,12 +2608,11 @@ int SeqPlayer_HOF::cbHOF_farmer(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 int SeqPlayer_HOF::cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	uint32 frameEnd = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
-	int chatFirstFrame = 0;
-	int chatLastFrame = 0;
-	//int textCol = 0;
+	int subTitleX = 0;
+	int subTitleY = 0;
+	int subTitleW = 0;
+	int subTitleFirstFrame = 0;
+	int subTitleLastFrame = 0;
 
 	uint16 voiceIndex = 0;
 
@@ -2650,20 +2620,20 @@ int SeqPlayer_HOF::cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	case -2:
 		doTransition(9);
 		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
-		seq_printCreditsString(70, 240, 20, _seqTextColorMap, 252);
-		seq_printCreditsString(71, 240, 30, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(72, 240, 40, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(73, 240, 50, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(74, 240, 60, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(75, 240, 70, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(101, 240, 80, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(102, 240, 90, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(87, 240, 100, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(88, 240, 110, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(89, 240, 120, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(90, 240, 130, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(91, 240, 140, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(92, 240, 150, _seqTextColorMap, _seqTextColor[0]);
+		printFadingText(70, 240, 20, _textColorMap, 252);
+		printFadingText(71, 240, 30, _textColorMap, _textColor[0]);
+		printFadingText(72, 240, 40, _textColorMap, _textColor[0]);
+		printFadingText(73, 240, 50, _textColorMap, _textColor[0]);
+		printFadingText(74, 240, 60, _textColorMap, _textColor[0]);
+		printFadingText(75, 240, 70, _textColorMap, _textColor[0]);
+		printFadingText(101, 240, 80, _textColorMap, _textColor[0]);
+		printFadingText(102, 240, 90, _textColorMap, _textColor[0]);
+		printFadingText(87, 240, 100, _textColorMap, _textColor[0]);
+		printFadingText(88, 240, 110, _textColorMap, _textColor[0]);
+		printFadingText(89, 240, 120, _textColorMap, _textColor[0]);
+		printFadingText(90, 240, 130, _textColorMap, _textColor[0]);
+		printFadingText(91, 240, 140, _textColorMap, _textColor[0]);
+		printFadingText(92, 240, 150, _textColorMap, _textColor[0]);
 		delayUntil(frameEnd);
 		setCountDown(0);
 		break;
@@ -2671,32 +2641,30 @@ int SeqPlayer_HOF::cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	case 0:
 		for (int i = 0; i < 0x300; i++)
 			_screen->getPalette(0)[i] &= 0x3f;
-		_seqTextColor[1] = 0xCf;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xfe;
+		_textColor[1] = 0xCf;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColor[0] = _textColorMap[1] = 0xfe;
 
-		_screen->setTextColorMap(_seqTextColorMap);
+		_screen->setTextColorMap(_textColorMap);
 		break;
 
 	case 6:
 		_animDuration = 20;
 
 		if (_vm->gameFlags().isTalkie) {
-			chatX = 82;
-			//textCol = 143;
-			chatFirstFrame = 16;
-			chatLastFrame = 21;
+			subTitleX = 82;
+			subTitleFirstFrame = 16;
+			subTitleLastFrame = 21;
 			voiceIndex = 41;
 		} else {
-			chatX = 62;
-			//textCol = 137;
-			chatFirstFrame = 9;
-			chatLastFrame = 13;
+			subTitleX = 62;
+			subTitleFirstFrame = 9;
+			subTitleLastFrame = 13;
 		}
-		chatY = (_vm->gameFlags().lang == Common::FR_FRA || _vm->gameFlags().lang == Common::DE_DEU) ? 88 :100;
-		chatW = 80;
+		subTitleY = (_vm->gameFlags().lang == Common::FR_FRA || _vm->gameFlags().lang == Common::DE_DEU) ? 88 :100;
+		subTitleW = 80;
 
-		seq_playWsaSyncDialogue(30, voiceIndex, 137, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		playDialogueAnimation(30, voiceIndex, 137, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
 		if (_vm->gameFlags().isTalkie)
 			_animCurrentFrame = 8;
 		break;
@@ -2706,23 +2674,21 @@ int SeqPlayer_HOF::cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		if (_vm->gameFlags().isTalkie) {
 			if (frm == 16)
 				break;
-			chatX = 64;
-			//textCol = 137;
-			chatFirstFrame = 9;
-			chatLastFrame = 13;
+			subTitleX = 64;
+			subTitleFirstFrame = 9;
+			subTitleLastFrame = 13;
 			voiceIndex = 42;
 		} else {
 			if (frm == 9)
 				break;
-			chatX = 80;
-			//textCol = 143;
-			chatFirstFrame = 16;
-			chatLastFrame = 21;
+			subTitleX = 80;
+			subTitleFirstFrame = 16;
+			subTitleLastFrame = 21;
 		}
-		chatY = 100;
-		chatW = 100;
+		subTitleY = 100;
+		subTitleW = 100;
 
-		seq_playWsaSyncDialogue(31, voiceIndex, 143, chatX, chatY, chatW, wsaObj, chatFirstFrame, chatLastFrame, x, y);
+		playDialogueAnimation(31, voiceIndex, 143, subTitleX, subTitleY, subTitleW, wsaObj, subTitleFirstFrame, subTitleLastFrame, x, y);
 		if (_vm->gameFlags().isTalkie)
 			_animCurrentFrame = 21;
 		break;
@@ -2737,9 +2703,9 @@ int SeqPlayer_HOF::cbHOF_fuards(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 int SeqPlayer_HOF::cbHOF_firates(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	uint32 frameEnd = 0;
-	int chatX = 0;
-	int chatY = 0;
-	int chatW = 0;
+	int subTitleX = 0;
+	int subTitleY = 0;
+	int subTitleW = 0;
 	uint16 voiceIndex = 0;
 
 	switch (frm) {
@@ -2749,28 +2715,28 @@ int SeqPlayer_HOF::cbHOF_firates(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		_screen->updateScreen();
 		doTransition(9);
 		frameEnd = _system->getMillis() + 480 * _vm->tickLength();
-		seq_printCreditsString(76, 240, 40, _seqTextColorMap, 252);
-		seq_printCreditsString(77, 240, 50, _seqTextColorMap, 252);
-		seq_printCreditsString(78, 240, 60, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(79, 240, 70, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(80, 240, 80, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(84, 240, 100, _seqTextColorMap, 252);
-		seq_printCreditsString(85, 240, 110, _seqTextColorMap, _seqTextColor[0]);
-		seq_printCreditsString(99, 240, 130, _seqTextColorMap, 252);
-		seq_printCreditsString(100, 240, 140, _seqTextColorMap, _seqTextColor[0]);
+		printFadingText(76, 240, 40, _textColorMap, 252);
+		printFadingText(77, 240, 50, _textColorMap, 252);
+		printFadingText(78, 240, 60, _textColorMap, _textColor[0]);
+		printFadingText(79, 240, 70, _textColorMap, _textColor[0]);
+		printFadingText(80, 240, 80, _textColorMap, _textColor[0]);
+		printFadingText(84, 240, 100, _textColorMap, 252);
+		printFadingText(85, 240, 110, _textColorMap, _textColor[0]);
+		printFadingText(99, 240, 130, _textColorMap, 252);
+		printFadingText(100, 240, 140, _textColorMap, _textColor[0]);
 		delayUntil(frameEnd);
 		setCountDown(0);
 		break;
 
 	case 0:
-		_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-		memset(_seqTextColorMap, _seqTextColor[1], 16);
-		_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-		_screen->setTextColorMap(_seqTextColorMap);
+		_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+		memset(_textColorMap, _textColor[1], 16);
+		_textColor[0] = _textColorMap[1] = 0xff;
+		_screen->setTextColorMap(_textColorMap);
 		break;
 
 	case 6:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 31 : 27);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 31 : 27);
 		break;
 
 	case 14:
@@ -2778,41 +2744,41 @@ int SeqPlayer_HOF::cbHOF_firates(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		if (!((frm == 15 && !_vm->gameFlags().isTalkie) || (frm == 14 && _vm->gameFlags().isTalkie)))
 			break;
 
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 31 : 27);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 31 : 27);
 
 		if (_vm->gameFlags().lang == Common::DE_DEU) {
-			chatX = 82;
-			chatY = 84;
-			chatW = 140;
+			subTitleX = 82;
+			subTitleY = 84;
+			subTitleW = 140;
 		} else {
-			chatX = 74;
-			chatY = (_vm->gameFlags().lang == Common::FR_FRA) ? 96: 108;
-			chatW = 80;
+			subTitleX = 74;
+			subTitleY = (_vm->gameFlags().lang == Common::FR_FRA) ? 96: 108;
+			subTitleW = 80;
 		}
 
 		if (_vm->gameFlags().isTalkie)
 			voiceIndex = 43;
 
-		seq_playWsaSyncDialogue(32, voiceIndex, 137, chatX, chatY, chatW, wsaObj, 14, 16, x, y);
+		playDialogueAnimation(32, voiceIndex, 137, subTitleX, subTitleY, subTitleW, wsaObj, 14, 16, x, y);
 		break;
 
 	case 28:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 32 : 28);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 32 : 28);
 		break;
 
 	case 29:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 33 : 29);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 33 : 29);
 		break;
 
 	case 31:
 		if (_vm->gameFlags().isTalkie)
 			voiceIndex = 44;
 
-		chatX = 90;
-		chatY = (_vm->gameFlags().lang == Common::DE_DEU) ? 60 : 76;
-		chatW = 80;
+		subTitleX = 90;
+		subTitleY = (_vm->gameFlags().lang == Common::DE_DEU) ? 60 : 76;
+		subTitleW = 80;
 
-		seq_playWsaSyncDialogue(33, voiceIndex, 143, chatX, chatY, chatW, wsaObj, 31, 34, x, y);
+		playDialogueAnimation(33, voiceIndex, 143, subTitleX, subTitleY, subTitleW, wsaObj, 31, 34, x, y);
 		break;
 
 	case 35:
@@ -2843,17 +2809,17 @@ int SeqPlayer_HOF::cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 	case -1:
 		if (_vm->gameFlags().isTalkie)
-			 seq_finaleActorScreen();
+			 playHoFTalkieCredits();
 		_talkieFinaleExtraFlag = _vm->gameFlags().isTalkie;
 		break;
 
 	case 0:
 		if (_callbackCurrentFrame == 1) {
 			_vm->sound()->playTrack(4);
-			_seqTextColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
-			memset(_seqTextColorMap, _seqTextColor[1], 16);
-			_seqTextColor[0] = _seqTextColorMap[1] = 0xff;
-			_screen->setTextColorMap(_seqTextColorMap);
+			_textColor[1] = _screen->findLeastDifferentColor(_textColorPresets, _screen->getPalette(0), 1, 255) & 0xff;
+			memset(_textColorMap, _textColor[1], 16);
+			_textColor[0] = _textColorMap[1] = 0xff;
+			_screen->setTextColorMap(_textColorMap);
 		}
 		_animDuration = 10;
 		break;
@@ -2863,7 +2829,7 @@ int SeqPlayer_HOF::cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 			_animCurrentFrame = 0;
 		} else {
 			_animDuration = _vm->gameFlags().isTalkie ? 500 : (300 + _vm->_rnd.getRandomNumberRng(1, 300));
-			seq_playTalkText(_vm->gameFlags().isTalkie ? 26 : 22);
+			playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 26 : 22);
 			if (_talkieFinaleExtraFlag) {
 				_callbackCurrentFrame = 3;
 				_talkieFinaleExtraFlag = false;
@@ -2876,7 +2842,7 @@ int SeqPlayer_HOF::cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		break;
 
 	case 3:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 27 : 23);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 27 : 23);
 		_animDuration = _vm->gameFlags().isTalkie ? 500 : (300 + _vm->_rnd.getRandomNumberRng(1, 300));
 		break;
 
@@ -2885,7 +2851,7 @@ int SeqPlayer_HOF::cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		break;
 
 	case 5:
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 27 : 23);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 27 : 23);
 		tmp = _callbackCurrentFrame / 6;
 		if (tmp == 2)
 			_animDuration = _vm->gameFlags().isTalkie ? 7 : (1 + _vm->_rnd.getRandomNumberRng(1, 10));
@@ -2905,7 +2871,7 @@ int SeqPlayer_HOF::cbHOF_frash(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	case 7:
 		_callbackCurrentFrame = 0;
 		_animDuration = 5;
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 26 : 22);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 26 : 22);
 		break;
 
 	case 11:
@@ -2925,7 +2891,7 @@ int SeqPlayer_HOF::cbHOF_figgle(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	if (_callbackCurrentFrame == 10)
 		setCountDown(0);
 	if (_callbackCurrentFrame == 10 || _callbackCurrentFrame == 5 || _callbackCurrentFrame == 7)
-		seq_playTalkText(_vm->gameFlags().isTalkie ? 45 : 30);
+		playSoundAndDisplaySubTitle(_vm->gameFlags().isTalkie ? 45 : 30);
 
 	_callbackCurrentFrame++;
 	return frm;
@@ -2977,19 +2943,19 @@ int SeqPlayer_HOF::cbHOFDEMO_hill(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 int SeqPlayer_HOF::cbHOFDEMO_outhome(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	switch (frm) {
 	case 12:
-		seq_playTalkText(4);
+		playSoundAndDisplaySubTitle(4);
 		break;
 
 	case 32:
-		seq_playTalkText(7);
+		playSoundAndDisplaySubTitle(7);
 		break;
 
 	case 36:
-		seq_playTalkText(10);
+		playSoundAndDisplaySubTitle(10);
 		break;
 
 	case 57:
-		seq_playTalkText(9);
+		playSoundAndDisplaySubTitle(9);
 		break;
 
 	case 80:
@@ -3004,11 +2970,11 @@ int SeqPlayer_HOF::cbHOFDEMO_outhome(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 		break;
 
 	case 110:
-		seq_playTalkText(5);
+		playSoundAndDisplaySubTitle(5);
 		break;
 
 	case 137:
-		seq_playTalkText(6);
+		playSoundAndDisplaySubTitle(6);
 		break;
 	}
 
@@ -3021,7 +2987,7 @@ int SeqPlayer_HOF::cbHOFDEMO_wharf(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 	switch (frm) {
 	case 0:
-		seq_playTalkText(11);
+		playSoundAndDisplaySubTitle(11);
 		break;
 
 	case 5:
@@ -3037,15 +3003,15 @@ int SeqPlayer_HOF::cbHOFDEMO_wharf(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 
 	case 8:
 	case 10:
-		seq_playTalkText(2);
+		playSoundAndDisplaySubTitle(2);
 		break;
 
 	case 13:
-		seq_playTalkText(7);
+		playSoundAndDisplaySubTitle(7);
 		break;
 
 	case 16:
-		seq_playTalkText(12);
+		playSoundAndDisplaySubTitle(12);
 		break;
 
 	default:
@@ -3085,7 +3051,7 @@ int SeqPlayer_HOF::cbHOFDEMO_fisher(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 			startNestedAnimation(1, kNestedSequenceHoFDemoDig);
 		}
 
-		if (_seqScrollTextCounter >= 0x18f && !_callbackCurrentFrame)
+		if (_scrollProgressCounter >= 0x18f && !_callbackCurrentFrame)
 			return 0;
 
 		if (!_callbackCurrentFrame) {
@@ -3093,15 +3059,15 @@ int SeqPlayer_HOF::cbHOFDEMO_fisher(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 			_screen->loadBitmap("adtext2.cps", 6, 6, 0);
 			_screen->copyPageMemory(6, 0, 4, 64000, 1024);
 			_screen->copyPageMemory(6, 1023, 6, 0, 64000);
-			_seqScrollTextCounter = 0;
+			_scrollProgressCounter = 0;
 		}
 
-		seq_scrollPage(24, 144);
+		updateDemoAdText(24, 144);
 		_callbackCurrentFrame++;
 		if (_callbackCurrentFrame < 0x256 || _callbackCurrentFrame > 0x31c) {
 			if (_callbackCurrentFrame < 0x174 || _callbackCurrentFrame > 0x1d7) {
 				if (_callbackCurrentFrame < 0x84 || _callbackCurrentFrame > 0xe7) {
-					_seqScrollTextCounter++;
+					_scrollProgressCounter++;
 				}
 			}
 		}
@@ -3114,7 +3080,7 @@ int SeqPlayer_HOF::cbHOFDEMO_fisher(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 		}
 
 	} else {
-		seq_scrollPage(24, 144);
+		updateDemoAdText(24, 144);
 	}
 	return 0;
 }
@@ -3129,23 +3095,23 @@ int SeqPlayer_HOF::cbHOFDEMO_wharf2(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 int SeqPlayer_HOF::cbHOFDEMO_dinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	switch (frm) {
 	case 19:
-		seq_playTalkText(13);
+		playSoundAndDisplaySubTitle(13);
 		break;
 
 	case 54:
-		seq_playTalkText(15);
+		playSoundAndDisplaySubTitle(15);
 		break;
 
 	case 61:
-		seq_playTalkText(16);
+		playSoundAndDisplaySubTitle(16);
 		break;
 
 	case 69:
-		seq_playTalkText(14);
+		playSoundAndDisplaySubTitle(14);
 		break;
 
 	case 77:
-		seq_playTalkText(13);
+		playSoundAndDisplaySubTitle(13);
 		break;
 
 	case 79:
@@ -3158,7 +3124,7 @@ int SeqPlayer_HOF::cbHOFDEMO_dinob2(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 
 int SeqPlayer_HOF::cbHOFDEMO_water(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	if (frm == 1)
-		seq_playTalkText(11);
+		playSoundAndDisplaySubTitle(11);
 	return frm;
 }
 
@@ -3181,13 +3147,13 @@ int SeqPlayer_HOF::cbLOLDEMO_scene1(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 		}
 		tmpPal.copy(_screen->getPalette(0));
 
-		for (int i = 3; i < 0x300; i++) {
+		for (int i = 3; i < 768; i++) {
 			tmpPal[i] = ((int)tmpPal[i] * 120) / 64;
 			if (tmpPal[i] > 0x3f)
 				tmpPal[i] = 0x3f;
 		}
 
-		seq_playTalkText(_vm->_rnd.getRandomBit());
+		playSoundAndDisplaySubTitle(_vm->_rnd.getRandomBit());
 		_screen->setScreenPalette(tmpPal);
 		_screen->updateScreen();
 		_vm->delay(8);
@@ -3195,7 +3161,7 @@ int SeqPlayer_HOF::cbLOLDEMO_scene1(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 		_screen->setScreenPalette(_screen->getPalette(0));
 		_screen->updateScreen();
 		if (_callbackCurrentFrame == 40)
-			seq_playTalkText(3);
+			playSoundAndDisplaySubTitle(3);
 	}
 
 	_callbackCurrentFrame++;
@@ -3203,20 +3169,20 @@ int SeqPlayer_HOF::cbLOLDEMO_scene1(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 }
 
 int SeqPlayer_HOF::cbLOLDEMO_scene2(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (_callbackCurrentFrame - 17) {
+	switch (frm - 17) {
 	case 0:
 		_animDuration = 8;
 		break;
 	case 3:
 	case 6:
 	case 9:
-		seq_playTalkText(8);
+		playSoundEffect(8, 255 - ((26 - frm) << 3));
 		break;
 	case 15:
-		seq_playTalkText(9);
+		playSoundAndDisplaySubTitle(9);
 		break;
 	case 18:
-		seq_playTalkText(2);
+		playSoundAndDisplaySubTitle(2);
 		break;
 	default:
 		break;
@@ -3226,40 +3192,40 @@ int SeqPlayer_HOF::cbLOLDEMO_scene2(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 }
 
 int SeqPlayer_HOF::cbLOLDEMO_scene3(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	if (_callbackCurrentFrame == 1)
-		seq_playTalkText(6);
-	else if (frm == 26)
-		seq_playTalkText(7);
+	if (frm == 1)
+		playSoundAndDisplaySubTitle(6);
+	else if (frm == 24)
+		playSoundAndDisplaySubTitle(7);
 
 	_callbackCurrentFrame++;
 	return frm;
 }
 
 int SeqPlayer_HOF::cbLOLDEMO_scene4(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	switch (_callbackCurrentFrame) {
+	switch (frm) {
 	case 11:
 	case 14:
 	case 17:
 	case 20:
-		seq_playTalkText(8);
+		playSoundEffect(8, 255 - ((22 - frm) << 3));
 		break;
 	case 22:
-		seq_playTalkText(11);
+		playSoundAndDisplaySubTitle(11);
 		break;
 	case 24:
-		seq_playTalkText(8);
+		playSoundAndDisplaySubTitle(8);
 		break;
 	case 30:
-		seq_playTalkText(15);
+		playSoundAndDisplaySubTitle(15);
 		break;
 	case 34:
-		seq_playTalkText(14);
+		playSoundAndDisplaySubTitle(14);
 		break;
 	case 38:
-		seq_playTalkText(13);
+		playSoundAndDisplaySubTitle(13);
 		break;
 	case 42:
-		seq_playTalkText(12);
+		playSoundAndDisplaySubTitle(12);
 		break;
 	default:
 		break;
@@ -3285,13 +3251,13 @@ int SeqPlayer_HOF::cbLOLDEMO_scene5(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 	case 26:
 	case 28:
 	case 30:
-		seq_playTalkText(15);
+		playSoundEffect(15, 255 - ((31 - frm) << 3));
 		break;
 	case 32:
-		seq_playTalkText(16);
+		playSoundAndDisplaySubTitle(16);
 		break;
 	case 42:
-		seq_playTalkText(6);
+		playSoundAndDisplaySubTitle(6);
 		break;
 	default:
 		break;
@@ -3301,19 +3267,19 @@ int SeqPlayer_HOF::cbLOLDEMO_scene5(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 
 int SeqPlayer_HOF::cbLOLDEMO_text5(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	if (_callbackCurrentFrame++ == 100)
-		seq_playTalkText(5);
+		playSoundAndDisplaySubTitle(5);
 	return frm;
 }
 
 int SeqPlayer_HOF::cbLOLDEMO_scene6(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
-	while (_seqScrollTextCounter < 0x122) {
+	while (_scrollProgressCounter < 290) {
 		setCountDown(6);
 		if (!_callbackCurrentFrame) {
 			_screen->loadBitmap("adtext.cps", 4, 4, 0);
 			_screen->loadBitmap("adtext2.cps", 6, 6, 0);
 			_screen->copyPageMemory(6, 0, 4, 64000, 1024);
 			_screen->copyPageMemory(6, 1023, 6, 0, 64000);
-			_seqScrollTextCounter = 0;
+			_scrollProgressCounter = 0;
 		}
 
 		if (_callbackCurrentFrame % 175) {
@@ -3328,22 +3294,22 @@ int SeqPlayer_HOF::cbLOLDEMO_scene6(WSAMovie_v2 *wsaObj, int x, int y, int frm)
 					tmpPal[i] = 0x3f;
 			}
 
-			seq_playTalkText(_vm->_rnd.getRandomBit());
+			playSoundAndDisplaySubTitle(_vm->_rnd.getRandomBit());
 			_screen->setScreenPalette(tmpPal);
 			_screen->updateScreen();
 			_vm->delay(8);
 		}
 
 		if (_callbackCurrentFrame == 40 || _callbackCurrentFrame == 80 || _callbackCurrentFrame == 150 || _callbackCurrentFrame == 300)
-			seq_playTalkText(3);
+			playSoundAndDisplaySubTitle(3);
 
 		_screen->copyPage(12, 2);
-		seq_scrollPage(70, 130);
+		updateDemoAdText(70, 130);
 		_screen->copyPage(2, 0);
 		_screen->updateScreen();
 		_callbackCurrentFrame++;
 		if (_callbackCurrentFrame < 128 || _callbackCurrentFrame > 207)
-			_seqScrollTextCounter++;
+			_scrollProgressCounter++;
 
 		while (countDownRunning())
 			delayTicks(1);
@@ -3404,7 +3370,6 @@ void KyraEngine_HoF::seq_showStarcraftLogo() {
 	delete ci;
 }
 
-
 int KyraEngine_HoF::seq_playIntro() {
 	bool startupSaveLoadable = saveFileLoadable(0);
 	return SeqPlayer_HOF(this, _screen, _system, startupSaveLoadable).play(kSequenceVirgin, startupSaveLoadable? kSequenceTitle : kSequenceNoLooping);
diff --git a/engines/kyra/sequences_hof.h b/engines/kyra/sequences_hof.h
new file mode 100644
index 0000000..2558a68
--- /dev/null
+++ b/engines/kyra/sequences_hof.h
@@ -0,0 +1,74 @@
+/* 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.
+ *
+ */
+
+#ifndef KYRA_SEQUENCES_HOF_H
+#define KYRA_SEQUENCES_HOF_H
+
+#include "kyra/kyra_v2.h"
+
+namespace Kyra {
+
+struct HoFSequence {
+	const char *wsaFile;
+	const char *cpsFile;
+	uint16 flags;
+	uint8 fadeInTransitionType;
+	uint8 fadeOutTransitionType;
+	int16 stringIndex1;
+	int16 stringIndex2;
+	uint16 startFrame;
+	uint16 numFrames;
+	uint16 duration;
+	uint16 xPos;
+	uint16 yPos;
+	uint16 timeout;
+};
+
+struct HoFNestedSequence {
+	const char *wsaFile;
+	const FrameControl *wsaControl;
+	uint16 flags;
+	uint16 startframe;
+	uint16 endFrame;
+	uint16 frameDelay;
+	uint16 x;
+	uint16 y;
+	uint16 fadeInTransitionType;
+	uint16 fadeOutTransitionType;
+};
+
+struct HoFSeqData {
+	const HoFSequence *seq;
+	int numSeq;
+	const HoFNestedSequence *nestedSeq;
+	int numNestedSeq;
+};
+
+struct HoFSeqItemAnimData {
+	int16 itemIndex;
+	uint16 y;
+	const uint16 *frames;
+};
+
+} // End of namespace Kyra
+
+#endif
diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp
index 485120a..44f97f3 100644
--- a/engines/kyra/sequences_lol.cpp
+++ b/engines/kyra/sequences_lol.cpp
@@ -38,6 +38,7 @@ namespace Kyra {
 int LoLEngine::processPrologue() {
 	// There are two non-interactive demos (one which plays the intro and another one) which plays a number of specific scenes.
 	// We try to identify the latter one by looking for a specific file.
+	_res->loadPakFile("GENERAL.PAK");
 	if (_flags.isDemo && _res->exists("scene1.cps")) {
 		return playDemo();
 	} else {
diff --git a/engines/kyra/staticres_lol.cpp b/engines/kyra/staticres_lol.cpp
index 63bc7fa..4934aeb 100644
--- a/engines/kyra/staticres_lol.cpp
+++ b/engines/kyra/staticres_lol.cpp
@@ -213,17 +213,22 @@ void StaticResource::freeButtonDefs(void *&ptr, int &size) {
 }
 
 void LoLEngine::initStaticResource() {
-	// assign music data
+	// assign music resource data
 	static const char *const pcMusicFileListIntro[] = { "LOREINTR" };
 	static const char *const pcMusicFileListFinale[] = { "LOREFINL" };
 	static const char *const pcMusicFileListIngame[] = { "LORE%02d%c" };
+	static const char *const pcMusicFileListDemo[] = { "LOREDEMO" };
 
 	static const char *const pc98MusicFileListIntro[] = { 0, "lore84.86", "lore82.86", 0, 0, 0, "lore83.86", "lore81.86" };
 	static const char *const pc98MusicFileListFinale[] = { 0, 0, "lore85.86", "lore86.86", "lore87.86" };
 	static const char *const pc98MusicFileListIngame[] = { "lore%02d.86" };
 
 	memset(_soundData, 0, sizeof(_soundData));
-	if (_flags.platform == Common::kPlatformPC) {
+
+	if (_flags.isDemo) {
+		_soundData[0].fileList = pcMusicFileListDemo;
+		_soundData[0].fileListLen = ARRAYSIZE(pcMusicFileListDemo);
+	} else if (_flags.platform == Common::kPlatformPC) {
 		_soundData[0].fileList = pcMusicFileListIntro;
 		_soundData[0].fileListLen = ARRAYSIZE(pcMusicFileListIntro);
 		_soundData[1].fileList = pcMusicFileListIngame;


Commit: 93e69aa4da0558b05fc235684355ed38eed9863d
    https://github.com/scummvm/scummvm/commit/93e69aa4da0558b05fc235684355ed38eed9863d
Author: athrxx (athrxx at scummvm.org)
Date: 2012-11-11T10:14:31-08:00

Commit Message:
KYRA: clean up audio resource handling

(this was really ugly, now it's somewhat less ugly)

Changed paths:
    engines/kyra/kyra_hof.cpp
    engines/kyra/kyra_hof.h
    engines/kyra/kyra_lok.cpp
    engines/kyra/kyra_lok.h
    engines/kyra/kyra_v1.h
    engines/kyra/lol.cpp
    engines/kyra/lol.h
    engines/kyra/saveload_lok.cpp
    engines/kyra/sequences_hof.cpp
    engines/kyra/sequences_lol.cpp
    engines/kyra/sound.cpp
    engines/kyra/sound.h
    engines/kyra/sound_adlib.cpp
    engines/kyra/sound_adlib.h
    engines/kyra/sound_amiga.cpp
    engines/kyra/sound_intern.h
    engines/kyra/sound_midi.cpp
    engines/kyra/sound_towns.cpp
    engines/kyra/staticres.cpp
    engines/kyra/staticres_lol.cpp



diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index d8d4f69..c53731e 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -274,7 +274,7 @@ Common::Error KyraEngine_HoF::go() {
 }
 
 void KyraEngine_HoF::startup() {
-	_sound->setSoundList(&_soundData[kMusicIngame]);
+	_sound->selectAudioResourceSet(kMusicIngame);
 	// The track map is exactly the same
 	// for FM-TOWNS and DOS
 	_trackMap = _dosTrackMap;
diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h
index 3ee6446..a9831d0 100644
--- a/engines/kyra/kyra_hof.h
+++ b/engines/kyra/kyra_hof.h
@@ -57,7 +57,6 @@ public:
 	GUI *gui() const { return _gui; }
 	virtual TextDisplayer *text() { return _text; }
 	int language() const { return _lang; }
-	const AudioDataStruct *soundData(int index) { return &_soundData[index]; }
 
 protected:
 	static const EngineDesc _hofEngineDesc;
@@ -87,8 +86,6 @@ protected:
 	static const int8 _pcSpkSfxMap[];
 	static const int _pcSpkSfxMapSize;
 
-	AudioDataStruct _soundData[3];
-
 protected:
 	// game initialization
 	void startup();
diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp
index 27bc2ad..7d4e350 100644
--- a/engines/kyra/kyra_lok.cpp
+++ b/engines/kyra/kyra_lok.cpp
@@ -98,8 +98,6 @@ KyraEngine_LoK::KyraEngine_LoK(OSystem *system, const GameFlags &flags)
 
 	_malcolmFrame = 0;
 	_malcolmTimer1 = _malcolmTimer2 = 0;
-
-	_soundFiles = 0;
 }
 
 KyraEngine_LoK::~KyraEngine_LoK() {
@@ -123,8 +121,6 @@ KyraEngine_LoK::~KyraEngine_LoK() {
 	delete _animator;
 	delete _seq;
 
-	delete[] _soundFiles;
-
 	delete[] _characterList;
 
 	delete[] _roomTable;
@@ -194,7 +190,7 @@ Common::Error KyraEngine_LoK::init() {
 
 	initStaticResource();
 
-	_sound->setSoundList(&_soundData[kMusicIntro]);
+	_sound->selectAudioResourceSet(kMusicIntro);
 
 	if (_flags.platform == Common::kPlatformAmiga) {
 		_trackMap = _amigaTrackMap;
@@ -349,7 +345,7 @@ void KyraEngine_LoK::startup() {
 	static const uint8 colorMap[] = { 0, 0, 0, 0, 12, 12, 12, 0, 0, 0, 0, 0 };
 	_screen->setTextColorMap(colorMap);
 
-	_sound->setSoundList(&_soundData[kMusicIngame]);
+	_sound->selectAudioResourceSet(kMusicIngame);
 	if (_flags.platform == Common::kPlatformPC98)
 		_sound->loadSoundFile("SE.DAT");
 	else
diff --git a/engines/kyra/kyra_lok.h b/engines/kyra/kyra_lok.h
index 71177f5..7470dd8 100644
--- a/engines/kyra/kyra_lok.h
+++ b/engines/kyra/kyra_lok.h
@@ -134,8 +134,6 @@ public:
 	const uint8 * const *palTable1() { return &_specialPalettes[0]; }
 	const uint8 * const *palTable2() { return &_specialPalettes[29]; }
 
-	const AudioDataStruct *soundData(int index) { return &_soundData[index]; }
-
 protected:
 	virtual Common::Error go();
 	virtual Common::Error init();
@@ -645,14 +643,6 @@ protected:
 
 	const uint8 * const *_specialPalettes;
 
-	const char * const *_soundFiles;
-	int _soundFilesSize;
-	const char * const *_soundFilesIntro;
-	int _soundFilesIntroSize;
-	const int32 *_cdaTrackTable;
-	int _cdaTrackTableSize;
-	AudioDataStruct _soundData[3];
-
 	// positions of the inventory
 	static const uint16 _itemPosX[];
 	static const uint8 _itemPosY[];
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index d912553..79903e6 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -140,14 +140,6 @@ enum {
 	GI_EOB2 = 6
 };
 
-struct AudioDataStruct {
-	const char *const *fileList;
-	int fileListLen;
-	const void *cdaTracks;
-	int cdaNumTracks;
-	int extraOffset;
-};
-
 // TODO: this is just the start of makeing the debug output of the kyra engine a bit more useable
 // in the future we maybe merge some flags  and/or create new ones
 enum DebugLevels {
@@ -164,7 +156,7 @@ enum DebugLevels {
 	kDebugLevelTimer       = 1 << 10  ///< debug level for "TimerManager" functions
 };
 
-enum MusicDataID {
+enum AudioResourceSet {
 	kMusicIntro = 0,
 	kMusicIngame,
 	kMusicFinale
@@ -243,8 +235,6 @@ public:
 	virtual bool snd_voiceIsPlaying();
 	virtual void snd_stopVoice();
 
-	virtual const AudioDataStruct *soundData(int index) { return 0; }
-
 	// delay functionallity
 	virtual void delayUntil(uint32 timestamp, bool updateGameTimers = false, bool update = false, bool isMainLoop = false);
 	virtual void delay(uint32 millis, bool update = false, bool isMainLoop = false);
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index ed7fe52..dcfd2b7 100644
--- a/engines/kyra/lol.cpp
+++ b/engines/kyra/lol.cpp
@@ -534,7 +534,7 @@ Common::Error LoLEngine::go() {
 	if (_flags.platform == Common::kPlatformPC98)
 		_sound->loadSoundFile("sound.dat");
 
-	_sound->setSoundList(&_soundData[kMusicIngame]);
+	_sound->selectAudioResourceSet(kMusicIngame);
 	if (_flags.platform != Common::kPlatformPC)
 		_sound->loadSoundFile(0);
 
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
index 06f9e32..be2d833 100644
--- a/engines/kyra/lol.h
+++ b/engines/kyra/lol.h
@@ -275,8 +275,6 @@ public:
 	Screen *screen();
 	GUI *gui() const;
 
-	const AudioDataStruct *soundData(int index) { return &_soundData[index]; }
-
 private:
 	Screen_LoL *_screen;
 	GUI_LoL *_gui;
@@ -472,8 +470,6 @@ private:
 	const uint8 *_ingamePCSpeakerSoundIndex;
 	int _ingamePCSpeakerSoundIndexSize;
 
-	AudioDataStruct _soundData[3];
-
 	// gui
 	void gui_drawPlayField();
 	void gui_drawScene(int pageNum);
diff --git a/engines/kyra/saveload_lok.cpp b/engines/kyra/saveload_lok.cpp
index b76d1da..f8cca1a 100644
--- a/engines/kyra/saveload_lok.cpp
+++ b/engines/kyra/saveload_lok.cpp
@@ -150,7 +150,7 @@ Common::Error KyraEngine_LoK::loadGameState(int slot) {
 		// it wasn't made sure that _curSfxFile was initialized
 		// so if it's out of bounds we just set it to 0.
 		if (_flags.platform == Common::kPlatformFMTowns) {
-			if (_curSfxFile >= _soundData->fileListLen || _curSfxFile < 0)
+			if (!_sound->hasSoundFile(_curSfxFile))
 				_curSfxFile = 0;
 			_sound->loadSoundFile(_curSfxFile);
 		}
diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index 7f105bf..7b9e91d 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -153,7 +153,7 @@ private:
 	void closeNestedAnimation(int animSlot);
 	void unloadNestedAnimation(int animSlot);
 	void doNestedFrameTransition(int transitionType, int animSlot);
-	void updateAllNestedAnimations();	
+	void updateAllNestedAnimations();
 	bool updateNestedAnimation(int animSlot);
 
 	struct AnimSlot {
@@ -478,7 +478,7 @@ SeqPlayer_HOF::~SeqPlayer_HOF() {
 
 int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
 	bool incompatibleData = false;
-	MusicDataID soundSet = kMusicIntro;
+	AudioResourceSet soundSet = kMusicIntro;
 	_firstScene = firstScene;
 	_loopStartScene = loopStartScene;
 	_preventLooping = false;
@@ -521,7 +521,7 @@ int SeqPlayer_HOF::play(SequenceID firstScene, SequenceID loopStartScene) {
 	if (incompatibleData)
 		error("SeqPlayer_HOF::play(): Specified sequences do not match the available sequence data for this target");
 
-	_vm->sound()->setSoundList(_vm->soundData(soundSet));
+	_vm->sound()->selectAudioResourceSet(soundSet);
 	_vm->sound()->loadSoundFile(0);
 
 	setupCallbacks();
@@ -536,7 +536,7 @@ void SeqPlayer_HOF::pause(bool toggle) {
 	} else {
 		uint32 pausedTime = _system->getMillis() - _pauseStart;
 		_pauseStart = 0;
-		
+
 		_countDownLastUpdate += pausedTime;
 		_fisherAnimCurTime += pausedTime;
 		_specialAnimTimeOutTotal += pausedTime;
@@ -702,7 +702,7 @@ void SeqPlayer_HOF::playScenes() {
 			while (!checkAbortPlayback() && !_vm->shouldQuit() && (countDownRunning() || _updateAnimations)) {
 				uint32 endFrame = (_system->getMillis() + _vm->tickLength()) & ~(_vm->tickLength() - 1);
 				updateAllNestedAnimations();
-				
+
 				if (_config->seqProc[_curScene])
 					(this->*_config->seqProc[_curScene])(0, 0, 0, 0);
 
@@ -715,7 +715,7 @@ void SeqPlayer_HOF::playScenes() {
 				do {
 					if (checkAbortPlayback())
 						if (checkPlaybackStatus())
-							break;				
+							break;
 				} while (_system->getMillis() < endFrame);
 			}
 		}
@@ -968,7 +968,7 @@ void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastF
 	}
 
 	int8 frameStep = (startFrame > lastFrame) ? -1 : 1;
-	_animCurrentFrame = startFrame;	
+	_animCurrentFrame = startFrame;
 
 	while (!_vm->shouldQuit() && !finished) {
 		if (checkAbortPlayback())
@@ -1474,7 +1474,7 @@ void SeqPlayer_HOF::playHoFTalkieCredits() {
 	const uint8 *talkieCredits = _vm->staticres()->loadRawData(k2SeqplayCredits, talkieCreditsSize);
 	const char * const *talkieCreditsSpecial = _vm->staticres()->loadStrings(k2SeqplayCreditsSpecial, talkieCreditsSpecialSize);
 
-	_vm->sound()->setSoundList(_vm->soundData(kMusicIngame));
+	_vm->sound()->selectAudioResourceSet(kMusicIngame);
 	_vm->sound()->loadSoundFile(3);
 	_vm->sound()->playTrack(3);
 
@@ -1493,7 +1493,7 @@ void SeqPlayer_HOF::playHoFTalkieCredits() {
 
 	delete[] dataPtr;
 	_vm->staticres()->unloadId(k2SeqplayCreditsSpecial);
-	_vm->sound()->setSoundList(_vm->soundData(kMusicFinale));
+	_vm->sound()->selectAudioResourceSet(kMusicFinale);
 	_vm->sound()->loadSoundFile(0);
 }
 
@@ -1735,7 +1735,7 @@ void SeqPlayer_HOF::setCountDown(uint32 ticks) {
 		_countDownRemainder = _countDownRemainder * 2 / 3;
 	_countDownLastUpdate = _system->getMillis() & ~(_vm->tickLength() - 1);
 }
-	
+
 bool SeqPlayer_HOF::countDownRunning() {
 	uint32 cur = _system->getMillis();
 	uint32 step = cur - _countDownLastUpdate;
@@ -1770,7 +1770,7 @@ int SeqPlayer_HOF::cbHOF_title(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 		_system->updateScreen();
 		_result = _menu->handle(11) + 1;
 		_updateAnimations = false;
-		
+
 		if (_result == 1) {
 			_curScene = _lastScene;
 			_preventLooping = true;
diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp
index 44f97f3..8300536 100644
--- a/engines/kyra/sequences_lol.cpp
+++ b/engines/kyra/sequences_lol.cpp
@@ -182,7 +182,7 @@ void LoLEngine::setupPrologueData(bool load) {
 		memset(_selectionAnimTimers, 0, sizeof(_selectionAnimTimers));
 		_screen->getPalette(1).clear();
 
-		_sound->setSoundList(&_soundData[kMusicIntro]);
+		_sound->selectAudioResourceSet(kMusicIntro);
 
 		// We have three sound.dat files, one for the intro, one for the
 		// end sequence and one for ingame, each contained in a different
@@ -203,7 +203,7 @@ void LoLEngine::setupPrologueData(bool load) {
 			return;
 
 		_eventList.clear();
-		_sound->setSoundList(0);
+		_sound->selectAudioResourceSet(kMusicIntro);
 	}
 }
 
@@ -1041,7 +1041,7 @@ void LoLEngine::setupEpilogueData(bool load) {
 	_screen->clearPage(3);
 
 	if (load) {
-		_sound->setSoundList(&_soundData[kMusicFinale]);
+		_sound->selectAudioResourceSet(kMusicFinale);
 
 		// We have three sound.dat files, one for the intro, one for the
 		// end sequence and one for ingame, each contained in a different
@@ -1057,7 +1057,7 @@ void LoLEngine::setupEpilogueData(bool load) {
 			return;
 
 		_eventList.clear();
-		_sound->setSoundList(0);
+		_sound->selectAudioResourceSet(kMusicIntro);
 	}
 }
 
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index 9d3e5f6..7b1b4d8 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -37,7 +37,7 @@ namespace Kyra {
 
 Sound::Sound(KyraEngine_v1 *vm, Audio::Mixer *mixer)
 	: _vm(vm), _mixer(mixer), _soundChannels(), _musicEnabled(1),
-	_sfxEnabled(true), _soundDataList(0) {
+	_sfxEnabled(true) {
 }
 
 Sound::~Sound() {
@@ -47,14 +47,6 @@ Sound::kType Sound::getSfxType() const {
 	return getMusicType();
 }
 
-void Sound::setSoundList(const AudioDataStruct *list) {
-	_soundDataList = list;
-}
-
-bool Sound::hasSoundFile(uint file) const {
-	return (fileListEntry(file) != 0);
-}
-
 bool Sound::isPlaying() const {
 	return false;
 }
@@ -203,12 +195,17 @@ void MixedSoundDriver::updateVolumeSettings() {
 	_sfx->updateVolumeSettings();
 }
 
-void MixedSoundDriver::setSoundList(const AudioDataStruct *list) {
-	_music->setSoundList(list);
-	_sfx->setSoundList(list);
+void MixedSoundDriver::initAudioResourceInfo(int set, void *info) {
+	_music->initAudioResourceInfo(set, info);
+	_sfx->initAudioResourceInfo(set, info);
+}
+
+void MixedSoundDriver::selectAudioResourceSet(int set) {
+	_music->selectAudioResourceSet(set);
+	_sfx->selectAudioResourceSet(set);
 }
 
-bool MixedSoundDriver::hasSoundFile(uint file) const {
+bool MixedSoundDriver::hasSoundFile(uint file) {
 	return _music->hasSoundFile(file) && _sfx->hasSoundFile(file);
 }
 
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index 384aeb4..48d9b60 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -37,6 +37,35 @@ class SeekableAudioStream;
 
 namespace Kyra {
 
+// Helper structs to format the data passed to the various initAudioResourceInfo() implementations
+struct SoundResourceInfo_PC {
+	SoundResourceInfo_PC(const char *const *files, int numFiles) : fileList(files), fileListSize(numFiles) {}
+	const char *const *fileList;
+	int fileListSize;
+};
+
+struct SoundResourceInfo_Towns {
+	SoundResourceInfo_Towns(const char *const *files, int numFiles, const int32 *cdaTbl, int cdaTblSize) : fileList(files), fileListSize(numFiles), cdaTable(cdaTbl), cdaTableSize(cdaTblSize) {}
+	const char *const *fileList;
+	int fileListSize;
+	const int32 *cdaTable;
+	int cdaTableSize;
+};
+
+struct SoundResourceInfo_PC98 {
+	SoundResourceInfo_PC98(const char *fileNamePattern) : pattern(fileNamePattern) {}
+	const char *pattern;
+};
+
+struct SoundResourceInfo_TownsPC98V2 {
+	SoundResourceInfo_TownsPC98V2(const char *const *files, int numFiles, const char *fileNamePattern, const uint16 *cdaTbl, int cdaTblSize) : fileList(files), fileListSize(numFiles), pattern(fileNamePattern), cdaTable(cdaTbl), cdaTableSize(cdaTblSize) {}
+	const char *const *fileList;
+	int fileListSize;
+	const char *pattern;
+	const uint16 *cdaTable;
+	int cdaTableSize;
+};
+
 /**
  * Analog audio output device API for Kyrandia games.
  * It contains functionality to play music tracks,
@@ -78,12 +107,20 @@ public:
 	virtual void updateVolumeSettings() {}
 
 	/**
-	 * Sets the soundfiles the output device will use
-	 * when playing a track and/or sound effect.
+	 * Assigns static resource data with information on how to load
+	 * audio resources to
 	 *
-	 * @param list soundfile list
+	 * @param	set				value defined in AudioResourceSet enum
+	 *			info			various types of resource info data (file list, file name pattern, struct, etc. - depending on the inheriting driver type)
 	 */
-	virtual void setSoundList(const AudioDataStruct *list);
+	virtual void initAudioResourceInfo(int set, void *info) = 0;
+
+	/**
+	 * Select audio resource set.
+	 *
+	 * @param	set				value defined in AudioResourceSet enum
+	 */
+	virtual void selectAudioResourceSet(int set) = 0;
 
 	/**
 	 * Checks if a given sound file is present.
@@ -91,7 +128,7 @@ public:
 	 * @param track track number
 	 * @return true if available, false otherwise
 	 */
-	virtual bool hasSoundFile(uint file) const;
+	virtual bool hasSoundFile(uint file) = 0;
 
 	/**
 	 * Load a specifc sound file for use of
@@ -228,12 +265,6 @@ public:
 	 */
 	virtual void resetTrigger() {}
 protected:
-	const char *fileListEntry(int file) const { return (_soundDataList != 0 && file >= 0 && file < _soundDataList->fileListLen) ? _soundDataList->fileList[file] : ""; }
-	int fileListLen() const { return _soundDataList->fileListLen; }
-	const void *cdaData() const { return _soundDataList != 0 ? _soundDataList->cdaTracks : 0; }
-	int cdaTrackNum() const { return _soundDataList != 0 ? _soundDataList->cdaNumTracks : 0; }
-	int extraOffset() const { return _soundDataList != 0 ? _soundDataList->extraOffset : 0; }
-
 	enum {
 		kNumChannelHandles = 4
 	};
@@ -243,7 +274,7 @@ protected:
 		Audio::SoundHandle handle;
 		int priority;
 	};
-	
+
 	SoundChannel _soundChannels[kNumChannelHandles];
 
 	int _musicEnabled;
@@ -253,8 +284,6 @@ protected:
 	Audio::Mixer *_mixer;
 
 private:
-	const AudioDataStruct *_soundDataList;
-
 	struct SpeechCodecs {
 		const char *fileext;
 		Audio::SeekableAudioStream *(*streamFunc)(
@@ -278,8 +307,9 @@ public:
 
 	virtual void updateVolumeSettings();
 
-	virtual void setSoundList(const AudioDataStruct *list);
-	virtual bool hasSoundFile(uint file) const;
+	virtual void initAudioResourceInfo(int set, void *info);
+	virtual void selectAudioResourceSet(int set);
+	virtual bool hasSoundFile(uint file);
 	virtual void loadSoundFile(uint file);
 	virtual void loadSoundFile(Common::String file);
 
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index 668e662..3d4ad1f 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -2292,6 +2292,8 @@ SoundAdLibPC::SoundAdLibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer)
 	_numSoundTriggers = 0;
 	_sfxPlayingSound = -1;
 	_soundFileLoaded.clear();
+	_currentResourceSet = 0;
+	memset(&_resInfo, 0, sizeof(_resInfo));
 
 	switch (vm->game()) {
 	case GI_LOL:
@@ -2322,6 +2324,8 @@ SoundAdLibPC::SoundAdLibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer)
 SoundAdLibPC::~SoundAdLibPC() {
 	delete _driver;
 	delete[] _soundDataPtr;
+	for (int i = 0; i < 3; i++)
+		initAudioResourceInfo(i, 0);
 }
 
 bool SoundAdLibPC::init() {
@@ -2416,8 +2420,29 @@ void SoundAdLibPC::resetTrigger() {
 	_driver->resetSoundTrigger();
 }
 
+void SoundAdLibPC::initAudioResourceInfo(int set, void *info) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		delete _resInfo[set];
+		_resInfo[set] = info ? new SoundResourceInfo_PC(*(SoundResourceInfo_PC*)info) : 0;
+	}
+}
+
+void SoundAdLibPC::selectAudioResourceSet(int set) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		if (_resInfo[set])
+			_currentResourceSet = set;
+	}
+}
+
+bool SoundAdLibPC::hasSoundFile(uint file) {
+	if (file < res()->fileListSize)
+		return (res()->fileList[file] != 0);
+	return false;
+}
+
 void SoundAdLibPC::loadSoundFile(uint file) {
-	internalLoadFile(fileListEntry(file));
+	if (file < res()->fileListSize)
+		internalLoadFile(res()->fileList[file]);
 }
 
 void SoundAdLibPC::loadSoundFile(Common::String file) {
diff --git a/engines/kyra/sound_adlib.h b/engines/kyra/sound_adlib.h
index 8492f3b..99e1f15 100644
--- a/engines/kyra/sound_adlib.h
+++ b/engines/kyra/sound_adlib.h
@@ -69,6 +69,9 @@ public:
 
 	virtual void updateVolumeSettings();
 
+	virtual void initAudioResourceInfo(int set, void *info);
+	virtual void selectAudioResourceSet(int set);
+	virtual bool hasSoundFile(uint file);
 	virtual void loadSoundFile(uint file);
 	virtual void loadSoundFile(Common::String file);
 
@@ -87,6 +90,10 @@ private:
 
 	void play(uint8 track, uint8 volume);
 
+	const SoundResourceInfo_PC *res() {return _resInfo[_currentResourceSet]; }
+	SoundResourceInfo_PC *_resInfo[3];
+	int _currentResourceSet;
+
 	AdLibDriver *_driver;
 
 	int _version;
diff --git a/engines/kyra/sound_amiga.cpp b/engines/kyra/sound_amiga.cpp
index ec2748d..5962d6f 100644
--- a/engines/kyra/sound_amiga.cpp
+++ b/engines/kyra/sound_amiga.cpp
@@ -53,6 +53,22 @@ bool SoundAmiga::init() {
 	return _driver != 0 && _tableSfxIntro && _tableSfxGame;
 }
 
+void SoundAmiga::initAudioResourceInfo(int set, void *info) {
+	// See comment below
+}
+
+void SoundAmiga::selectAudioResourceSet(int set) {
+	// It seems that loadSoundFile() is doing what would normally be done in here.
+	// As long as this driver is only required for one single target (Kyra 1 Amiga)
+	// this doesn't matter much.
+}
+
+bool SoundAmiga::hasSoundFile(uint file) {
+	if (file < 3)
+		return true;
+	return false;
+}
+
 void SoundAmiga::loadSoundFile(uint file) {
 	debugC(5, kDebugLevelSound, "SoundAmiga::loadSoundFile(%d)", file);
 
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index e09fe7e..94f596f 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -23,6 +23,8 @@
 #ifndef KYRA_SOUND_INTERN_H
 #define KYRA_SOUND_INTERN_H
 
+
+
 #include "kyra/sound.h"
 #include "kyra/sound_adlib.h"
 
@@ -40,6 +42,7 @@ class MaxTrax;
 } // End of namespace Audio
 
 namespace Kyra {
+
 class MidiOutput;
 
 /**
@@ -59,6 +62,9 @@ public:
 
 	void updateVolumeSettings();
 
+	void initAudioResourceInfo(int set, void *info);
+	void selectAudioResourceSet(int set);
+	bool hasSoundFile(uint file);
 	void loadSoundFile(uint file);
 	void loadSoundFile(Common::String file);
 	void loadSfxFile(Common::String file);
@@ -89,6 +95,10 @@ private:
 	MidiParser *_music;
 	MidiParser *_sfx[3];
 
+	const SoundResourceInfo_PC *res() {return _resInfo[_currentResourceSet]; }
+	SoundResourceInfo_PC *_resInfo[3];
+	int _currentResourceSet;
+
 	// misc
 	kType _type;
 	Common::String getFileName(const Common::String &str);
@@ -110,6 +120,9 @@ public:
 	bool init();
 	void process();
 
+	void initAudioResourceInfo(int set, void *info);
+	void selectAudioResourceSet(int set);
+	bool hasSoundFile(uint file);
 	void loadSoundFile(uint file);
 	void loadSoundFile(Common::String) {}
 
@@ -142,6 +155,10 @@ private:
 
 	bool _cdaPlaying;
 
+	const SoundResourceInfo_Towns *res() {return _resInfo[_currentResourceSet]; }
+	SoundResourceInfo_Towns *_resInfo[3];
+	int _currentResourceSet;
+
 	const uint8 *_musicFadeTable;
 	const uint8 *_sfxBTTable;
 	const uint8 *_sfxWDTable;
@@ -157,6 +174,9 @@ public:
 	bool init();
 
 	void process() {}
+	void initAudioResourceInfo(int set, void *info);
+	void selectAudioResourceSet(int set);
+	bool hasSoundFile(uint file);
 	void loadSoundFile(uint file);
 	void loadSoundFile(Common::String file);
 
@@ -169,11 +189,15 @@ public:
 
 	void updateVolumeSettings();
 
-protected:
+private:
 	int _lastTrack;
 	uint8 *_musicTrackData;
 	uint8 *_sfxTrackData;
 	TownsPC98_AudioDriver *_driver;
+
+	const char *resPattern() {return _resInfo[_currentResourceSet]->c_str(); }
+	Common::String *_resInfo[3];
+	int _currentResourceSet;
 };
 
 class SoundTownsPC98_v2 : public Sound {
@@ -186,6 +210,9 @@ public:
 	bool init();
 	void process();
 
+	void initAudioResourceInfo(int set, void *info);
+	void selectAudioResourceSet(int set);
+	bool hasSoundFile(uint file);
 	void loadSoundFile(uint file) {}
 	void loadSoundFile(Common::String file);
 
@@ -198,7 +225,7 @@ public:
 
 	void updateVolumeSettings();
 
-protected:
+private:
 	Audio::AudioStream *_currentSFX;
 	int _lastTrack;
 	bool _useFmSfx;
@@ -206,6 +233,10 @@ protected:
 	uint8 *_musicTrackData;
 	uint8 *_sfxTrackData;
 	TownsPC98_AudioDriver *_driver;
+
+	const SoundResourceInfo_TownsPC98V2 *res() {return _resInfo[_currentResourceSet]; }
+	SoundResourceInfo_TownsPC98V2 *_resInfo[3];
+	int _currentResourceSet;
 };
 
 // PC Speaker MIDI driver
@@ -295,6 +326,10 @@ public:
 	bool init();
 
 	void process() {}
+
+	void initAudioResourceInfo(int set, void *info);
+	void selectAudioResourceSet(int set);
+	bool hasSoundFile(uint file);
 	void loadSoundFile(uint file);
 	void loadSoundFile(Common::String) {}
 
diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp
index 70cc304..fe40cb1 100644
--- a/engines/kyra/sound_midi.cpp
+++ b/engines/kyra/sound_midi.cpp
@@ -442,6 +442,8 @@ SoundMidiPC::SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *dri
 	_output = 0;
 
 	_musicFile = _sfxFile = 0;
+	_currentResourceSet = 0;
+	memset(&_resInfo, 0, sizeof(_resInfo));
 
 	_music = MidiParser::createParser_XMIDI();
 	assert(_music);
@@ -495,6 +497,9 @@ SoundMidiPC::~SoundMidiPC() {
 		delete[] _sfxFile;
 
 	delete[] _musicFile;
+
+	for (int i = 0; i < 3; i++)
+		initAudioResourceInfo(i, 0);
 }
 
 bool SoundMidiPC::init() {
@@ -586,8 +591,29 @@ void SoundMidiPC::updateVolumeSettings() {
 		_output->setSourceVolume(i, _sfxVolume, false);
 }
 
+void SoundMidiPC::initAudioResourceInfo(int set, void *info) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		delete _resInfo[set];
+		_resInfo[set] = info ? new SoundResourceInfo_PC(*(SoundResourceInfo_PC*)info) : 0;
+	}
+}
+
+void SoundMidiPC::selectAudioResourceSet(int set) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		if (_resInfo[set])
+			_currentResourceSet = set;
+	}
+}
+
+bool SoundMidiPC::hasSoundFile(uint file) {
+	if (file < res()->fileListSize)
+		return (res()->fileList[file] != 0);
+	return false;
+}
+
 void SoundMidiPC::loadSoundFile(uint file) {
-	loadSoundFile(fileListEntry(file));
+	if (file < res()->fileListSize)
+		loadSoundFile(res()->fileList[file]);
 }
 
 void SoundMidiPC::loadSoundFile(Common::String file) {
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 01624d5..c9a4e20 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -35,8 +35,8 @@ namespace Kyra {
 
 SoundTowns::SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer)
 	: Sound(vm, mixer), _lastTrack(-1), _musicTrackData(0), _sfxFileData(0), _cdaPlaying(0),
-	_sfxFileIndex((uint)-1), _musicFadeTable(0), _sfxWDTable(0), _sfxBTTable(0), _sfxChannel(0x46) {
-
+	_sfxFileIndex((uint)-1), _musicFadeTable(0), _sfxWDTable(0), _sfxBTTable(0), _sfxChannel(0x46), _currentResourceSet(0) {
+	memset(&_resInfo, 0, sizeof(_resInfo));
 	_driver = new TownsEuphonyDriver(_mixer);
 }
 
@@ -46,6 +46,8 @@ SoundTowns::~SoundTowns() {
 	delete _driver;
 	delete[] _musicTrackData;
 	delete[] _sfxFileData;
+	for (int i = 0; i < 3; i++)
+		initAudioResourceInfo(i, 0);
 }
 
 bool SoundTowns::init() {
@@ -78,11 +80,12 @@ void SoundTowns::playTrack(uint8 track) {
 		return;
 	track -= 2;
 
-	const int32 *const tTable = (const int32 *)cdaData();
 	int tTableIndex = 3 * track;
 
-	int trackNum = (int)READ_LE_UINT32(&tTable[tTableIndex + 2]);
-	int32 loop = (int32)READ_LE_UINT32(&tTable[tTableIndex + 1]);
+	assert(tTableIndex + 2 < res()->cdaTableSize);
+
+	int trackNum = (int)READ_LE_UINT32(&res()->cdaTable[tTableIndex + 2]);
+	int32 loop = (int32)READ_LE_UINT32(&res()->cdaTable[tTableIndex + 1]);
 
 	if (track == _lastTrack && _musicEnabled)
 		return;
@@ -95,7 +98,7 @@ void SoundTowns::playTrack(uint8 track) {
 		g_system->getAudioCDManager()->updateCD();
 		_cdaPlaying = true;
 	} else if (_musicEnabled) {
-		playEuphonyTrack(READ_LE_UINT32(&tTable[tTableIndex]), loop);
+		playEuphonyTrack(READ_LE_UINT32(&res()->cdaTable[tTableIndex]), loop);
 		_cdaPlaying = false;
 	}
 
@@ -117,12 +120,31 @@ void SoundTowns::haltTrack() {
 	_driver->stopParser();
 }
 
+void SoundTowns::initAudioResourceInfo(int set, void *info) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		delete _resInfo[set];
+		_resInfo[set] = info ? new SoundResourceInfo_Towns(*(SoundResourceInfo_Towns*)info) : 0;
+	}
+}
+
+void SoundTowns::selectAudioResourceSet(int set) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		if (_resInfo[set])
+			_currentResourceSet = set;
+	}
+}
+
+bool SoundTowns::hasSoundFile(uint file) {
+	if (file < res()->fileListSize)
+		return (res()->fileList[file] != 0);
+}
+
 void SoundTowns::loadSoundFile(uint file) {
-	if (_sfxFileIndex == file)
+	if (_sfxFileIndex == file || file >= res()->fileListSize)
 		return;
 	_sfxFileIndex = file;
 	delete[] _sfxFileData;
-	_sfxFileData = _vm->resource()->fileData(fileListEntry(file), 0);
+	_sfxFileData = _vm->resource()->fileData(res()->fileList[file], 0);
 }
 
 void SoundTowns::playSoundEffect(uint8 track, uint8) {
@@ -367,13 +389,16 @@ void SoundTowns::fadeOutSoundEffects() {
 }
 
 SoundPC98::SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer) :
-	Sound(vm, mixer), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0) {
+	Sound(vm, mixer), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0), _currentResourceSet(0) {
+	memset(&_resInfo, 0, sizeof(_resInfo));
 }
 
 SoundPC98::~SoundPC98() {
 	delete[] _musicTrackData;
 	delete[] _sfxTrackData;
 	delete _driver;
+	for (int i = 0; i < 3; i++)
+		initAudioResourceInfo(i, 0);
 }
 
 bool SoundPC98::init() {
@@ -383,8 +408,26 @@ bool SoundPC98::init() {
 	return reslt;
 }
 
-void SoundPC98::loadSoundFile(uint file) {
-	if (!scumm_strnicmp(fileListEntry(0), "INTRO", 5)) {
+void SoundPC98::initAudioResourceInfo(int set, void *info) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		delete _resInfo[set];
+		_resInfo[set] = info ? new Common::String(((SoundResourceInfo_PC98*)info)->pattern) : 0;
+	}
+}
+
+void SoundPC98::selectAudioResourceSet(int set) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		if (_resInfo[set])
+			_currentResourceSet = set;
+	}
+}
+
+bool SoundPC98::hasSoundFile(uint file) {
+	return true;
+}
+
+void SoundPC98::loadSoundFile(uint) {
+	if (_currentResourceSet == kMusicIntro) {
 		delete[] _sfxTrackData;
 		_sfxTrackData = 0;
 
@@ -407,14 +450,14 @@ void SoundPC98::loadSoundFile(Common::String file) {
 }
 
 void SoundPC98::playTrack(uint8 track) {
-	track += extraOffset();
+	track -= 1;
 
 	if (track == _lastTrack && _musicEnabled)
 		return;
 
 	beginFadeOut();
 
-	Common::String musicFile = fileListLen() == 1 ? Common::String::format(fileListEntry(0), track) : fileListEntry(track);
+	Common::String musicFile = Common::String::format(resPattern(), track);
 	delete[] _musicTrackData;
 	_musicTrackData = _vm->resource()->fileData(musicFile.c_str(), 0);
 	if (_musicEnabled)
@@ -464,13 +507,16 @@ void SoundPC98::updateVolumeSettings() {
 //	KYRA 2
 
 SoundTownsPC98_v2::SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer) :
-	Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false) {
+	Sound(vm, mixer), _currentSFX(0), _musicTrackData(0), _sfxTrackData(0), _lastTrack(-1), _driver(0), _useFmSfx(false), _currentResourceSet(0) {
+	memset(&_resInfo, 0, sizeof(_resInfo));
 }
 
 SoundTownsPC98_v2::~SoundTownsPC98_v2() {
 	delete[] _musicTrackData;
 	delete[] _sfxTrackData;
 	delete _driver;
+	for (int i = 0; i < 3; i++)
+		initAudioResourceInfo(i, 0);
 }
 
 bool SoundTownsPC98_v2::init() {
@@ -503,6 +549,25 @@ bool SoundTownsPC98_v2::init() {
 	return reslt;
 }
 
+void SoundTownsPC98_v2::initAudioResourceInfo(int set, void *info) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		delete _resInfo[set];
+		_resInfo[set] = info ? new SoundResourceInfo_TownsPC98V2(*(SoundResourceInfo_TownsPC98V2*)info) : 0;
+	}
+}
+
+void SoundTownsPC98_v2::selectAudioResourceSet(int set) {
+	if (set >= kMusicIntro && set <= kMusicFinale) {
+		if (_resInfo[set])
+			_currentResourceSet = set;
+	}
+}
+
+bool SoundTownsPC98_v2::hasSoundFile(uint file) {
+	if (file < res()->fileListSize)
+		return (res()->fileList[file] != 0);
+}
+
 void SoundTownsPC98_v2::loadSoundFile(Common::String file) {
 	delete[] _sfxTrackData;
 	_sfxTrackData = _vm->resource()->fileData(file.c_str(), 0);
@@ -513,18 +578,14 @@ void SoundTownsPC98_v2::process() {
 }
 
 void SoundTownsPC98_v2::playTrack(uint8 track) {
-	track += extraOffset();
-
 	if (track == _lastTrack && _musicEnabled)
 		return;
 
-	const uint16 *const cdaTracks = (const uint16 *)cdaData();
-
 	int trackNum = -1;
 	if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
-		for (int i = 0; i < cdaTrackNum(); i++) {
-			if (track == (uint8) READ_LE_UINT16(&cdaTracks[i * 2])) {
-				trackNum = (int) READ_LE_UINT16(&cdaTracks[i * 2 + 1]) - 1;
+		for (int i = 0; i < res()->cdaTableSize; i++) {
+			if (track == (uint8) READ_LE_UINT16(&res()->cdaTable[i * 2])) {
+				trackNum = (int) READ_LE_UINT16(&res()->cdaTable[i * 2 + 1]) - 1;
 				break;
 			}
 		}
@@ -532,9 +593,10 @@ void SoundTownsPC98_v2::playTrack(uint8 track) {
 
 	beginFadeOut();
 
-	Common::String musicFile = fileListLen() == 1 ? Common::String::format(fileListEntry(0), track) : fileListEntry(track);
+	Common::String musicFile = res()->pattern ? Common::String::format(res()->pattern, track) : (res()->fileList ? res()->fileList[track] : 0);
 	if (musicFile.empty())
 		return;
+
 	delete[] _musicTrackData;
 
 	_musicTrackData = _vm->resource()->fileData(musicFile.c_str(), 0);
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 04e111b..5909931 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -778,22 +778,6 @@ void KyraEngine_LoK::initStaticResource() {
 
 	_storyStrings = _staticres->loadStrings(k1PC98StoryStrings, _storyStringsSize);
 
-	int size1, size2;
-	const char *const *soundfiles1 = _staticres->loadStrings(k1AudioTracks, size1);
-	const char *const *soundfiles2 = _staticres->loadStrings(k1AudioTracks2, size2);
-	_soundFilesSize = size1 + size2;
-	if (_soundFilesSize) {
-		delete[] _soundFiles;
-		const char **soundfiles = new const char*[_soundFilesSize];
-		for (int i = 0; i < _soundFilesSize; i++)
-			soundfiles[i] = (i < size1) ? soundfiles1[i] : soundfiles2[i - size1];
-		_soundFiles = soundfiles;
-	}
-	_soundFilesIntro = _staticres->loadStrings(k1AudioTracksIntro, _soundFilesIntroSize);
-	_cdaTrackTable = (const int32 *)_staticres->loadRawData(k1TownsCDATable, _cdaTrackTableSize);
-
-	// copied static res
-
 	// room list
 	const Room *tempRoomList = _staticres->loadRoomTable(k1RoomList, _roomTableSize);
 
@@ -820,34 +804,34 @@ void KyraEngine_LoK::initStaticResource() {
 		_staticres->unloadId(k1DefaultShapes);
 	}
 
-	// audio data tables
-	static const char *const tIntro98[] = { "INTRO%d.DAT" };
-	static const char *const tIngame98[] = { "KYRAM%d.DAT" };
+	// audio resource assignment
+	int size1, size2;
+	const char *const *soundfiles1 = _staticres->loadStrings(k1AudioTracks, size1);
+	const char *const *soundfiles2 = _staticres->loadStrings(k1AudioTracks2, size2);
+	int soundFilesSize = size1 + size2;
+	int soundFilesIntroSize = 0;
+	int cdaTableSize = 0;
+	const char **soundFiles = 0;
+
+	if (soundFilesSize) {
+		soundFiles = new const char*[soundFilesSize];
+		for (int i = 0; i < soundFilesSize; i++)
+			soundFiles[i] = (i < size1) ? soundfiles1[i] : soundfiles2[i - size1];
+	}
+	const char *const *soundFilesIntro = _staticres->loadStrings(k1AudioTracksIntro, temp);
+	const int32 *cdaTable = (const int32 *)_staticres->loadRawData(k1TownsCDATable, cdaTableSize);
 
 	// FIXME: It seems Kyra1 MAC CD includes AdLib and MIDI music and sfx, thus we enable
 	// support for those for now. (Based on patch #2767489 "Support for Mac Kyrandia 1 CD" by satz).
-	memset(_soundData, 0, sizeof(_soundData));
 	if (_flags.platform == Common::kPlatformPC || _flags.platform == Common::kPlatformMacintosh) {
-		_soundData[0].fileList = _soundFilesIntro;
-		_soundData[0].fileListLen = _soundFilesIntroSize;
-		_soundData[1].fileList = _soundFiles;
-		_soundData[1].fileListLen = _soundFilesSize;
+		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_PC(soundFilesIntro, soundFilesIntroSize));
+		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_PC(soundFiles, soundFilesSize));
 	} else if (_flags.platform == Common::kPlatformFMTowns) {
-		_soundData[0].fileList = _soundFiles;
-		_soundData[0].fileListLen = _soundFilesSize;
-		_soundData[0].cdaTracks = _cdaTrackTable;
-		_soundData[0].cdaNumTracks = _cdaTrackTableSize;
-		_soundData[1].fileList = _soundFiles;
-		_soundData[1].fileListLen = _soundFilesSize;
-		_soundData[1].cdaTracks = _cdaTrackTable;
-		_soundData[1].cdaNumTracks = _cdaTrackTableSize;
+		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_Towns(soundFiles, soundFilesSize, cdaTable, cdaTableSize));
+		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_Towns(soundFiles, soundFilesSize, cdaTable, cdaTableSize));
 	} else if (_flags.platform == Common::kPlatformPC98) {
-		_soundData[0].fileList = tIntro98;
-		_soundData[0].fileListLen = 1;
-		_soundData[0].extraOffset = -1;
-		_soundData[1].fileList = tIngame98;
-		_soundData[1].fileListLen = 1;
-		_soundData[1].extraOffset = -1;
+		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_PC98("INTRO%d.DAT"));
+		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_PC98("KYRAM%d.DAT"));
 	}
 }
 
@@ -1009,42 +993,18 @@ void KyraEngine_HoF::initStaticResource() {
 	_itemAnimDefinition = _staticres->loadItemAnimDefinition(k2IngameShapeAnimData, _itemAnimDefinitionSize);
 
 	// assign music data
-	static const char *const fmtMusicFileListIntro[] = { "intro%d.twn" };
-	static const char *const fmtMusicFileListFinale[] = { "finale%d.twn" };
-	static const char *const fmtMusicFileListIngame[] = { "km%02d.twn" };
-
-	static const char *const pc98MusicFileListIntro[] = { "intro%d.86" };
-	static const char *const pc98MusicFileListFinale[] = { "finale%d.86" };
-	static const char *const pc98MusicFileListIngame[] = { "km%02d.86" };
-
-	memset(_soundData, 0, sizeof(_soundData));
 	if (_flags.platform == Common::kPlatformPC) {
-		_soundData[0].fileList = _musicFileListIntro;
-		_soundData[0].fileListLen = _musicFileListIntroSize;
-		_soundData[1].fileList = _musicFileListIngame;
-		_soundData[1].fileListLen = _musicFileListIngameSize;
-		_soundData[2].fileList = _musicFileListFinale;
-		_soundData[2].fileListLen = _musicFileListIntroSize;
+		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_PC(_musicFileListIntro, _musicFileListIntroSize));
+		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_PC(_musicFileListIngame, _musicFileListIngameSize));
+		_sound->initAudioResourceInfo(kMusicFinale, &SoundResourceInfo_PC(_musicFileListFinale, _musicFileListFinaleSize));
 	} else if (_flags.platform == Common::kPlatformFMTowns) {
-		_soundData[0].fileList = fmtMusicFileListIntro;
-		_soundData[0].fileListLen = 1;
-		_soundData[0].cdaTracks = _cdaTrackTableIntro;
-		_soundData[0].cdaNumTracks = _cdaTrackTableIntroSize >> 1;
-		_soundData[1].fileList = fmtMusicFileListIngame;
-		_soundData[1].fileListLen = 1;
-		_soundData[1].cdaTracks = _cdaTrackTableIngame;
-		_soundData[1].cdaNumTracks = _cdaTrackTableIngameSize >> 1;
-		_soundData[2].fileList = fmtMusicFileListFinale;
-		_soundData[2].fileListLen = 1;
-		_soundData[2].cdaTracks = _cdaTrackTableFinale;
-		_soundData[2].cdaNumTracks = _cdaTrackTableFinaleSize >> 1;
+		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_TownsPC98V2(0, 0, "intro%d.twn", (const uint16*)_cdaTrackTableIntro, _cdaTrackTableIntroSize >> 1));
+		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_TownsPC98V2(0, 0, "km%02d.twn", (const uint16*)_cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1));
+		_sound->initAudioResourceInfo(kMusicFinale, &SoundResourceInfo_TownsPC98V2(0, 0, "finale%d.twn", (const uint16*)_cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1));
 	} else if (_flags.platform == Common::kPlatformPC98) {
-		_soundData[0].fileList = pc98MusicFileListIntro;
-		_soundData[0].fileListLen = 1;
-		_soundData[1].fileList = pc98MusicFileListIngame;
-		_soundData[1].fileListLen = 1;
-		_soundData[2].fileList = pc98MusicFileListFinale;
-		_soundData[2].fileListLen = 1;
+		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_TownsPC98V2(0, 0, "intro%d.86", 0, 0));
+		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_TownsPC98V2(0, 0, "km%02d.86", 0, 0));
+		_sound->initAudioResourceInfo(kMusicFinale, &SoundResourceInfo_TownsPC98V2(0, 0, "finale%d.86", 0, 0));
 	}
 }
 
diff --git a/engines/kyra/staticres_lol.cpp b/engines/kyra/staticres_lol.cpp
index 4934aeb..af32fb9 100644
--- a/engines/kyra/staticres_lol.cpp
+++ b/engines/kyra/staticres_lol.cpp
@@ -24,6 +24,7 @@
 #include "kyra/lol.h"
 #include "kyra/screen_lol.h"
 #include "kyra/gui_lol.h"
+#include "kyra/sound_intern.h"
 
 #ifdef ENABLE_LOL
 
@@ -213,35 +214,16 @@ void StaticResource::freeButtonDefs(void *&ptr, int &size) {
 }
 
 void LoLEngine::initStaticResource() {
-	// assign music resource data
-	static const char *const pcMusicFileListIntro[] = { "LOREINTR" };
-	static const char *const pcMusicFileListFinale[] = { "LOREFINL" };
-	static const char *const pcMusicFileListIngame[] = { "LORE%02d%c" };
-	static const char *const pcMusicFileListDemo[] = { "LOREDEMO" };
-
-	static const char *const pc98MusicFileListIntro[] = { 0, "lore84.86", "lore82.86", 0, 0, 0, "lore83.86", "lore81.86" };
-	static const char *const pc98MusicFileListFinale[] = { 0, 0, "lore85.86", "lore86.86", "lore87.86" };
-	static const char *const pc98MusicFileListIngame[] = { "lore%02d.86" };
-
-	memset(_soundData, 0, sizeof(_soundData));
-
+	// assign music resource data (not required for the PC version, resource loading is implemented differently there)
 	if (_flags.isDemo) {
-		_soundData[0].fileList = pcMusicFileListDemo;
-		_soundData[0].fileListLen = ARRAYSIZE(pcMusicFileListDemo);
-	} else if (_flags.platform == Common::kPlatformPC) {
-		_soundData[0].fileList = pcMusicFileListIntro;
-		_soundData[0].fileListLen = ARRAYSIZE(pcMusicFileListIntro);
-		_soundData[1].fileList = pcMusicFileListIngame;
-		_soundData[1].fileListLen = ARRAYSIZE(pcMusicFileListIngame);
-		_soundData[2].fileList = pcMusicFileListFinale;
-		_soundData[2].fileListLen = ARRAYSIZE(pcMusicFileListFinale);
+		static const char *const file[] = { "LOREDEMO" };
+		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_TownsPC98V2(file, ARRAYSIZE(file), 0, 0, 0));
 	} else if (_flags.platform == Common::kPlatformPC98) {
-		_soundData[0].fileList = pc98MusicFileListIntro;
-		_soundData[0].fileListLen = ARRAYSIZE(pc98MusicFileListIntro);
-		_soundData[1].fileList = pc98MusicFileListIngame;
-		_soundData[1].fileListLen = ARRAYSIZE(pc98MusicFileListIngame);
-		_soundData[2].fileList = pc98MusicFileListFinale;
-		_soundData[2].fileListLen = ARRAYSIZE(pc98MusicFileListFinale);
+		static const char *const fileListIntro[] = { 0, "lore84.86", "lore82.86", 0, 0, 0, "lore83.86", "lore81.86" };
+		static const char *const fileListFinale[] = { 0, 0, "lore85.86", "lore86.86", "lore87.86" };
+		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_TownsPC98V2(fileListIntro, ARRAYSIZE(fileListIntro), 0, 0, 0));
+		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_TownsPC98V2(0, 0, "lore%02d.86", 0, 0));
+		_sound->initAudioResourceInfo(kMusicFinale, &SoundResourceInfo_TownsPC98V2(fileListFinale, ARRAYSIZE(fileListFinale), 0, 0, 0));
 	}
 
 	if (_flags.isDemo)


Commit: 086dd66a654e5b08c7c15b8715c4b15e211f6727
    https://github.com/scummvm/scummvm/commit/086dd66a654e5b08c7c15b8715c4b15e211f6727
Author: athrxx (athrxx at scummvm.org)
Date: 2012-11-11T10:14:33-08:00

Commit Message:
KYRA: fix several GCC compile issues in previous commits

Changed paths:
    engines/kyra/sequences_hof.cpp
    engines/kyra/sound.h
    engines/kyra/sound_towns.cpp
    engines/kyra/staticres.cpp
    engines/kyra/staticres_lol.cpp



diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index 7b9e91d..757907d 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -763,14 +763,18 @@ bool SeqPlayer_HOF::checkAbortPlayback() {
 				_abortRequested = true;
 				_vm->quitGame();
 				return true;
-			} else if (event.kbd.keycode != Common::KEYCODE_ESCAPE && event.kbd.keycode != Common::KEYCODE_RETURN && event.kbd.keycode != Common::KEYCODE_SPACE)
+			} else if (event.kbd.keycode != Common::KEYCODE_ESCAPE && event.kbd.keycode != Common::KEYCODE_RETURN && event.kbd.keycode != Common::KEYCODE_SPACE) {
 				continue;
+			}
+			// fall through
 		case Common::EVENT_LBUTTONDOWN:
 		case Common::EVENT_RBUTTONDOWN:
 		case Common::EVENT_LBUTTONUP:
 		case Common::EVENT_RBUTTONUP:
 			_abortRequested = true;
 			return true;
+		default:
+			break;
 		}
 	}
 
@@ -995,7 +999,7 @@ void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastF
 		updateAllNestedAnimations();
 		updateSubTitles();
 
-		if (wsaObj || callback && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
+		if ((wsaObj || callback) && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
 			_screen->copyPage(2, 0);
 			_screen->updateScreen();
 		}
@@ -1010,7 +1014,7 @@ void SeqPlayer_HOF::playAnimation(WSAMovie_v2 *wsaObj, int startFrame, int lastF
 					break;
 			}
 
-			if (wsaObj || callback && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
+			if ((wsaObj || callback) && (!(checkAbortPlayback() || _vm->shouldQuit() || _result))) {
 				_screen->copyPage(2, 0);
 				_screen->updateScreen();
 			}
@@ -1792,7 +1796,6 @@ int SeqPlayer_HOF::cbHOF_overview(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
 	uint8 *tmpPal = _screen->getPalette(3).getData() + 0x101;
 	memset(tmpPal, 0, 256);
 	uint32 frameEnd = 0;
-	uint32 curTime = 0;
 
 	switch (_callbackCurrentFrame) {
 	case 0:
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index 48d9b60..3418c8a 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -41,15 +41,15 @@ namespace Kyra {
 struct SoundResourceInfo_PC {
 	SoundResourceInfo_PC(const char *const *files, int numFiles) : fileList(files), fileListSize(numFiles) {}
 	const char *const *fileList;
-	int fileListSize;
+	uint fileListSize;
 };
 
 struct SoundResourceInfo_Towns {
 	SoundResourceInfo_Towns(const char *const *files, int numFiles, const int32 *cdaTbl, int cdaTblSize) : fileList(files), fileListSize(numFiles), cdaTable(cdaTbl), cdaTableSize(cdaTblSize) {}
 	const char *const *fileList;
-	int fileListSize;
+	uint fileListSize;
 	const int32 *cdaTable;
-	int cdaTableSize;
+	uint cdaTableSize;
 };
 
 struct SoundResourceInfo_PC98 {
@@ -60,10 +60,10 @@ struct SoundResourceInfo_PC98 {
 struct SoundResourceInfo_TownsPC98V2 {
 	SoundResourceInfo_TownsPC98V2(const char *const *files, int numFiles, const char *fileNamePattern, const uint16 *cdaTbl, int cdaTblSize) : fileList(files), fileListSize(numFiles), pattern(fileNamePattern), cdaTable(cdaTbl), cdaTableSize(cdaTblSize) {}
 	const char *const *fileList;
-	int fileListSize;
+	uint fileListSize;
 	const char *pattern;
 	const uint16 *cdaTable;
-	int cdaTableSize;
+	uint cdaTableSize;
 };
 
 /**
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index c9a4e20..6f57ebf 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -80,7 +80,7 @@ void SoundTowns::playTrack(uint8 track) {
 		return;
 	track -= 2;
 
-	int tTableIndex = 3 * track;
+	uint tTableIndex = 3 * track;
 
 	assert(tTableIndex + 2 < res()->cdaTableSize);
 
@@ -137,6 +137,7 @@ void SoundTowns::selectAudioResourceSet(int set) {
 bool SoundTowns::hasSoundFile(uint file) {
 	if (file < res()->fileListSize)
 		return (res()->fileList[file] != 0);
+	return false;
 }
 
 void SoundTowns::loadSoundFile(uint file) {
@@ -532,9 +533,9 @@ bool SoundTownsPC98_v2::init() {
 		// this misses the possibility that we play the tracks
 		// right off CD. So we should find another way to
 		// check if we have access to CD audio.
-		Resource *res = _vm->resource();
+		Resource *r = _vm->resource();
 		if (_musicEnabled &&
-			(res->exists("track1.mp3") || res->exists("track1.ogg") || res->exists("track1.flac") || res->exists("track1.fla")))
+			(r->exists("track1.mp3") || r->exists("track1.ogg") || r->exists("track1.flac") || r->exists("track1.fla")))
 				_musicEnabled = 2;
 		else
 			_musicEnabled = 1;
@@ -566,6 +567,7 @@ void SoundTownsPC98_v2::selectAudioResourceSet(int set) {
 bool SoundTownsPC98_v2::hasSoundFile(uint file) {
 	if (file < res()->fileListSize)
 		return (res()->fileList[file] != 0);
+	return false;
 }
 
 void SoundTownsPC98_v2::loadSoundFile(Common::String file) {
@@ -583,7 +585,7 @@ void SoundTownsPC98_v2::playTrack(uint8 track) {
 
 	int trackNum = -1;
 	if (_vm->gameFlags().platform == Common::kPlatformFMTowns) {
-		for (int i = 0; i < res()->cdaTableSize; i++) {
+		for (uint i = 0; i < res()->cdaTableSize; i++) {
 			if (track == (uint8) READ_LE_UINT16(&res()->cdaTable[i * 2])) {
 				trackNum = (int) READ_LE_UINT16(&res()->cdaTable[i * 2 + 1]) - 1;
 				break;
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 5909931..a488884 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -824,14 +824,20 @@ void KyraEngine_LoK::initStaticResource() {
 	// FIXME: It seems Kyra1 MAC CD includes AdLib and MIDI music and sfx, thus we enable
 	// support for those for now. (Based on patch #2767489 "Support for Mac Kyrandia 1 CD" by satz).
 	if (_flags.platform == Common::kPlatformPC || _flags.platform == Common::kPlatformMacintosh) {
-		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_PC(soundFilesIntro, soundFilesIntroSize));
-		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_PC(soundFiles, soundFilesSize));
+		SoundResourceInfo_PC resInfoIntro(soundFilesIntro, soundFilesIntroSize);
+		SoundResourceInfo_PC resInfoIngame(soundFiles, soundFilesSize);
+		_sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+		_sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
 	} else if (_flags.platform == Common::kPlatformFMTowns) {
-		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_Towns(soundFiles, soundFilesSize, cdaTable, cdaTableSize));
-		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_Towns(soundFiles, soundFilesSize, cdaTable, cdaTableSize));
+		SoundResourceInfo_Towns resInfoIntro(soundFiles, soundFilesSize, cdaTable, cdaTableSize);
+		SoundResourceInfo_Towns resInfoIngame(soundFiles, soundFilesSize, cdaTable, cdaTableSize);
+		_sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+		_sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
 	} else if (_flags.platform == Common::kPlatformPC98) {
-		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_PC98("INTRO%d.DAT"));
-		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_PC98("KYRAM%d.DAT"));
+		SoundResourceInfo_PC98 resInfoIntro("INTRO%d.DAT");
+		SoundResourceInfo_PC98 resInfoIngame("KYRAM%d.DAT");
+		_sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+		_sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
 	}
 }
 
@@ -977,8 +983,6 @@ void KyraEngine_LoK::loadMainScreen(int page) {
 }
 
 void KyraEngine_HoF::initStaticResource() {
-	int tmpSize = 0;
-
 	_ingamePakList = _staticres->loadStrings(k2IngamePakFiles, _ingamePakListSize);
 	_ingameSoundList = _staticres->loadStrings(k2IngameSfxFiles, _ingameSoundListSize);
 	_ingameSoundIndex = (const uint16 *)_staticres->loadRawData(k2IngameSfxIndex, _ingameSoundIndexSize);
@@ -994,17 +998,26 @@ void KyraEngine_HoF::initStaticResource() {
 
 	// assign music data
 	if (_flags.platform == Common::kPlatformPC) {
-		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_PC(_musicFileListIntro, _musicFileListIntroSize));
-		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_PC(_musicFileListIngame, _musicFileListIngameSize));
-		_sound->initAudioResourceInfo(kMusicFinale, &SoundResourceInfo_PC(_musicFileListFinale, _musicFileListFinaleSize));
+		SoundResourceInfo_PC resInfoIntro(_musicFileListIntro, _musicFileListIntroSize);
+		SoundResourceInfo_PC resInfoIngame(_musicFileListIngame, _musicFileListIngameSize);
+		SoundResourceInfo_PC resInfoFinale(_musicFileListFinale, _musicFileListFinaleSize);
+		_sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+		_sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+		_sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
 	} else if (_flags.platform == Common::kPlatformFMTowns) {
-		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_TownsPC98V2(0, 0, "intro%d.twn", (const uint16*)_cdaTrackTableIntro, _cdaTrackTableIntroSize >> 1));
-		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_TownsPC98V2(0, 0, "km%02d.twn", (const uint16*)_cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1));
-		_sound->initAudioResourceInfo(kMusicFinale, &SoundResourceInfo_TownsPC98V2(0, 0, "finale%d.twn", (const uint16*)_cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1));
+		SoundResourceInfo_TownsPC98V2 resInfoIntro(0, 0, "intro%d.twn", (const uint16*)_cdaTrackTableIntro, _cdaTrackTableIntroSize >> 1);
+		SoundResourceInfo_TownsPC98V2 resInfoIngame(0, 0, "km%02d.twn", (const uint16*)_cdaTrackTableIngame, _cdaTrackTableIngameSize >> 1);
+		SoundResourceInfo_TownsPC98V2 resInfoFinale(0, 0, "finale%d.twn", (const uint16*)_cdaTrackTableFinale, _cdaTrackTableFinaleSize >> 1);
+		_sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+		_sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+		_sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
 	} else if (_flags.platform == Common::kPlatformPC98) {
-		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_TownsPC98V2(0, 0, "intro%d.86", 0, 0));
-		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_TownsPC98V2(0, 0, "km%02d.86", 0, 0));
-		_sound->initAudioResourceInfo(kMusicFinale, &SoundResourceInfo_TownsPC98V2(0, 0, "finale%d.86", 0, 0));
+		SoundResourceInfo_TownsPC98V2 resInfoIntro(0, 0, "intro%d.86", 0, 0);
+		SoundResourceInfo_TownsPC98V2 resInfoIngame(0, 0, "km%02d.86", 0, 0);
+		SoundResourceInfo_TownsPC98V2 resInfoFinale(0, 0, "finale%d.86", 0, 0);
+		_sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+		_sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+		_sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
 	}
 }
 
diff --git a/engines/kyra/staticres_lol.cpp b/engines/kyra/staticres_lol.cpp
index af32fb9..b8a68ff 100644
--- a/engines/kyra/staticres_lol.cpp
+++ b/engines/kyra/staticres_lol.cpp
@@ -217,13 +217,17 @@ void LoLEngine::initStaticResource() {
 	// assign music resource data (not required for the PC version, resource loading is implemented differently there)
 	if (_flags.isDemo) {
 		static const char *const file[] = { "LOREDEMO" };
-		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_TownsPC98V2(file, ARRAYSIZE(file), 0, 0, 0));
+		SoundResourceInfo_TownsPC98V2 resInfoDemo(file, ARRAYSIZE(file), 0, 0, 0);
+		_sound->initAudioResourceInfo(kMusicIntro, &resInfoDemo);
 	} else if (_flags.platform == Common::kPlatformPC98) {
 		static const char *const fileListIntro[] = { 0, "lore84.86", "lore82.86", 0, 0, 0, "lore83.86", "lore81.86" };
 		static const char *const fileListFinale[] = { 0, 0, "lore85.86", "lore86.86", "lore87.86" };
-		_sound->initAudioResourceInfo(kMusicIntro, &SoundResourceInfo_TownsPC98V2(fileListIntro, ARRAYSIZE(fileListIntro), 0, 0, 0));
-		_sound->initAudioResourceInfo(kMusicIngame, &SoundResourceInfo_TownsPC98V2(0, 0, "lore%02d.86", 0, 0));
-		_sound->initAudioResourceInfo(kMusicFinale, &SoundResourceInfo_TownsPC98V2(fileListFinale, ARRAYSIZE(fileListFinale), 0, 0, 0));
+		SoundResourceInfo_TownsPC98V2 resInfoIntro(fileListIntro, ARRAYSIZE(fileListIntro), 0, 0, 0);		
+		SoundResourceInfo_TownsPC98V2 resInfoIngame(0, 0, "lore%02d.86", 0, 0);
+		SoundResourceInfo_TownsPC98V2 resInfoFinale(fileListFinale, ARRAYSIZE(fileListFinale), 0, 0, 0);
+		_sound->initAudioResourceInfo(kMusicIntro, &resInfoIntro);
+		_sound->initAudioResourceInfo(kMusicIngame, &resInfoIngame);
+		_sound->initAudioResourceInfo(kMusicFinale, &resInfoFinale);
 	}
 
 	if (_flags.isDemo)






More information about the Scummvm-git-logs mailing list