[Scummvm-git-logs] scummvm master -> b231384f9bb5d3b6932f14d9f8b46829bb2eb799

mgerhardy noreply at scummvm.org
Fri Sep 13 15:07:45 UTC 2024


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:
ef7b4edb9f TWINE: renamed music related methods
69c5c3a43c TWINE: updated the music code and renamed methods and variables...
37cac532dd TWINE: fixed demo menu handling for music
d6a0b5fb47 TWINE: fixed mouse cursor config var handling
faeef14bec TWINE: improved mouse support for behaviour switch and inventory
2f10fb20f8 TWINE: renamed methods to match original source
78b15a7e89 TWINE: LBA2: prepare body and anim parser for lba2
b231384f9b TWINE: LBA2: the scene index needs a small offset


Commit: ef7b4edb9f23ffbca2f2607c2460ec946a298f36
    https://github.com/scummvm/scummvm/commit/ef7b4edb9f23ffbca2f2607c2460ec946a298f36
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-09-13T17:07:29+02:00

Commit Message:
TWINE: renamed music related methods

Changed paths:
    engines/twine/audio/music.cpp
    engines/twine/audio/music.h
    engines/twine/debugger/console.cpp
    engines/twine/menu/menu.cpp
    engines/twine/menu/menuoptions.cpp
    engines/twine/movies.cpp
    engines/twine/renderer/screens.cpp
    engines/twine/scene/gamestate.cpp
    engines/twine/scene/scene.cpp
    engines/twine/script/script_life.cpp
    engines/twine/script/script_life_v1.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/audio/music.cpp b/engines/twine/audio/music.cpp
index c8cf1fd4f9b..86bae9ecd5f 100644
--- a/engines/twine/audio/music.cpp
+++ b/engines/twine/audio/music.cpp
@@ -147,7 +147,7 @@ static const char *musicTracksLba2[] = {
 	"LOGADPCM"
 };
 
-bool Music::playTrackMusicCd(int32 track) {
+bool Music::playCdTrack(int32 track) {
 	if (!_engine->_cfgfile.UseCD) {
 		return false;
 	}
@@ -176,12 +176,12 @@ bool Music::playTrackMusicCd(int32 track) {
 	return cdrom->play(track, 1, 0, 0);
 }
 
-void Music::stopTrackMusicCd() {
+void Music::stopMusicCD() {
 	AudioCDManager *cdrom = g_system->getAudioCDManager();
 	cdrom->stop();
 }
 
-bool Music::playTrackMusic(int32 track) {
+bool Music::playAllMusic(int32 track) {
 	if (track == -1) {
 		stopMusic();
 		return true;
@@ -195,12 +195,12 @@ bool Music::playTrackMusic(int32 track) {
 	}
 
 	stopMusic();
-	if (playTrackMusicCd(track)) {
+	if (playCdTrack(track)) {
 		currentMusic = track;
 		debug("Play cd music track %i", track);
 		return true;
 	}
-	if (playMidiMusic(track)) {
+	if (playMidiFile(track)) {
 		currentMusic = track;
 		debug("Play midi music track %i", track);
 		return true;
@@ -215,10 +215,10 @@ void Music::stopTrackMusic() {
 	}
 
 	musicFadeOut();
-	stopTrackMusicCd();
+	stopMusicCD();
 }
 
-bool Music::playMidiMusic(int32 midiIdx, int32 loop) {
+bool Music::playMidiFile(int32 midiIdx) {
 	if (!_engine->_cfgfile.Sound) {
 		debug("sound disabled - skip playing %i", midiIdx);
 		return false;
@@ -233,8 +233,9 @@ bool Music::playMidiMusic(int32 midiIdx, int32 loop) {
 	currentMusic = midiIdx;
 
 	musicFadeOut();
-	stopMidiMusic();
+	stopMusicMidi();
 
+	const int32 loop = 1;
 	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
 		Common::Path trackName(Common::String::format("lba1-%02i", midiIdx + 1));
 		Audio::SeekableAudioStream *stream = Audio::SeekableAudioStream::openStreamFile(trackName);
@@ -266,8 +267,8 @@ bool Music::playMidiMusic(int32 midiIdx, int32 loop) {
 	return true;
 }
 
-void Music::stopMidiMusic() {
-	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
+void Music::stopMusicMidi() {
+	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic() || _engine->isLBA2()) {
 		_engine->_system->getMixer()->stopHandle(_midiHandle);
 	}
 
@@ -284,7 +285,7 @@ bool Music::initCdrom() {
 
 void Music::stopMusic() {
 	stopTrackMusic();
-	stopMidiMusic();
+	stopMusicMidi();
 	currentMusic = -1;
 }
 
diff --git a/engines/twine/audio/music.h b/engines/twine/audio/music.h
index d580553e2a8..7e847b96ef1 100644
--- a/engines/twine/audio/music.h
+++ b/engines/twine/audio/music.h
@@ -50,7 +50,7 @@ private:
 	uint8 *midiPtr = nullptr;
 	Audio::SoundHandle _midiHandle;
 	/** Track number of the current playing music */
-	int32 currentMusic = -1;
+	int32 currentMusic = -1; // NumXmi, CurrentMusicCD
 public:
 	// TODO: implement the handling
 	int32 _nextMusic = -1;       // lba2: NextMusic
@@ -61,9 +61,9 @@ private:
 	 * Play CD music
 	 * @param track track number to play
 	 */
-	bool playTrackMusicCd(int32 track);
+	bool playCdTrack(int32 track);
 	/** Stop CD music */
-	void stopTrackMusicCd();
+	void stopMusicCD();
 public:
 	Music(TwinEEngine *engine);
 
@@ -77,7 +77,7 @@ public:
 	 * Generic play music, according with settings it plays CD or high quality sounds instead
 	 * @param track track number to play
 	 */
-	bool playTrackMusic(int32 track);
+	bool playAllMusic(int32 track);
 	/** Generic stop music according with settings */
 	void stopTrackMusic();
 	/**
@@ -85,9 +85,9 @@ public:
 	 * @param midiIdx music index under mini_mi_win.hqr
 	 * @note valid indices for lba1 are [1-32]
 	 */
-	bool playMidiMusic(int32 midiIdx, int32 loop = 1);
+	bool playMidiFile(int32 midiIdx);
 	/** Stop MIDI music */
-	void stopMidiMusic();
+	void stopMusicMidi();
 
 	/** Initialize CD-Rom */
 	bool initCdrom();
diff --git a/engines/twine/debugger/console.cpp b/engines/twine/debugger/console.cpp
index 0cc05f58e11..e614069af4f 100644
--- a/engines/twine/debugger/console.cpp
+++ b/engines/twine/debugger/console.cpp
@@ -395,7 +395,7 @@ bool TwinEConsole::doPlayMidi(int argc, const char **argv) {
 		return true;
 	}
 	int newMidiIndex = atoi(argv[1]);
-	_engine->_music->playMidiMusic(newMidiIndex);
+	_engine->_music->playMidiFile(newMidiIndex);
 	return true;
 }
 
@@ -405,7 +405,7 @@ bool TwinEConsole::doPlayMusic(int argc, const char **argv) {
 		return true;
 	}
 	int newMusicTrackIndex = atoi(argv[1]);
-	_engine->_music->playTrackMusic(newMusicTrackIndex);
+	_engine->_music->playAllMusic(newMusicTrackIndex);
 	return true;
 }
 
diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index f76e17db430..27f167388af 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -794,7 +794,7 @@ int32 Menu::optionsMenu() {
 	_engine->restoreFrontBuffer();
 
 	_engine->_sound->stopSamples();
-	_engine->_music->playTrackMusic(9); // LBA's Theme
+	_engine->_music->playAllMusic(9); // LBA's Theme
 
 	ScopedCursor scoped(_engine);
 	for (;;) {
@@ -897,9 +897,9 @@ EngineState Menu::run() {
 	_engine->_text->initDial(TextBankId::Options_and_menus);
 
 	if (_engine->isLBA1()) {
-		_engine->_music->playTrackMusic(9); // LBA's Theme
+		_engine->_music->playAllMusic(9); // LBA's Theme
 	} else {
-		_engine->_music->playTrackMusic(6); // LBA2's Theme
+		_engine->_music->playAllMusic(6); // LBA2's Theme
 	}
 	_engine->_sound->stopSamples();
 
diff --git a/engines/twine/menu/menuoptions.cpp b/engines/twine/menu/menuoptions.cpp
index cfe9ee8bd04..910a634521d 100644
--- a/engines/twine/menu/menuoptions.cpp
+++ b/engines/twine/menu/menuoptions.cpp
@@ -80,7 +80,7 @@ void MenuOptions::newGame() {
 		_engine->_screens->clearScreen();
 
 		if (!aborted) {
-			_engine->_music->playMidiMusic(1);
+			_engine->_music->playMidiFile(1);
 			_engine->_movie->playMovie(FLA_INTROD);
 		}
 
diff --git a/engines/twine/movies.cpp b/engines/twine/movies.cpp
index cac69de1097..c24bda3d57b 100644
--- a/engines/twine/movies.cpp
+++ b/engines/twine/movies.cpp
@@ -195,7 +195,7 @@ void Movies::processFrame() {
 			int16 innerOpcpde = stream.readSint16LE();
 			switch (innerOpcpde) {
 			case 1: // fla flute
-				_engine->_music->playMidiMusic(26);
+				_engine->_music->playMidiFile(26);
 				break;
 			case 2:
 				// FLA movies don't use cross fade
@@ -211,7 +211,7 @@ void Movies::processFrame() {
 				break;
 			case 4:
 				// TODO: fade out for 1 second before we stop it
-				_engine->_music->stopMidiMusic();
+				_engine->_music->stopMusicMidi();
 				break;
 			}
 			break;
diff --git a/engines/twine/renderer/screens.cpp b/engines/twine/renderer/screens.cpp
index 9235ab3f177..380b33d2528 100644
--- a/engines/twine/renderer/screens.cpp
+++ b/engines/twine/renderer/screens.cpp
@@ -51,7 +51,7 @@ int32 Screens::mapLba2Palette(int32 palIndex) {
 }
 
 bool Screens::adelineLogo() {
-	_engine->_music->playMidiMusic(31);
+	_engine->_music->playMidiFile(31);
 
 	return loadImageDelay(_engine->_resources->adelineLogo(), 7);
 }
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 882a39c08cb..d70c4a3cc64 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -524,7 +524,7 @@ void GameState::processGameoverAnimation() {
 	}
 
 	_engine->_sound->stopSamples();
-	_engine->_music->stopMidiMusic(); // stop fade music
+	_engine->_music->stopMusicMidi(); // stop fade music
 	_engine->_renderer->setProjection(_engine->width() / 2, _engine->height() / 2, 128, 200, 200);
 	int32 startLbaTime = _engine->timerRef;
 	const Common::Rect &rect = _engine->centerOnScreen(_engine->width() / 2, _engine->height() / 2);
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index d5c59624f33..25df4d33fb5 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -639,7 +639,7 @@ void Scene::changeScene() {
 
 	if (_sceneMusic != -1) {
 		debug(2, "Scene %i music track id: %i", _currentSceneIdx, _sceneMusic);
-		_engine->_music->playTrackMusic(_sceneMusic);
+		_engine->_music->playAllMusic(_sceneMusic);
 	}
 	_engine->_gameState->handleLateGameItems();
 }
@@ -675,11 +675,11 @@ void Scene::initSceneVars() {
 void Scene::playSceneMusic() {
 	if (_engine->isLBA1()) {
 		if (_currentSceneIdx == LBA1SceneId::Tippet_Island_Twinsun_Cafe && _engine->_gameState->hasArrivedHamalayi()) {
-			_engine->_music->playTrackMusic(8);
+			_engine->_music->playAllMusic(8);
 			return;
 		}
 	}
-	_engine->_music->playMidiMusic(_sceneMusic);
+	_engine->_music->playMidiFile(_sceneMusic);
 }
 
 void Scene::processEnvironmentSound() {
diff --git a/engines/twine/script/script_life.cpp b/engines/twine/script/script_life.cpp
index 244fa7cbc66..835f71dd98c 100644
--- a/engines/twine/script/script_life.cpp
+++ b/engines/twine/script/script_life.cpp
@@ -1981,7 +1981,7 @@ int32 ScriptLife::lTHE_END(TwinEEngine *engine, LifeScriptContext &ctx) {
 int32 ScriptLife::lPLAY_CD_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
 	const int32 track = ctx.stream.readByte();
 	debugC(3, kDebugLevels::kDebugScripts, "LIFE::PLAY_CD_TRACK(%i)", (int)track);
-	engine->_music->playTrackMusic(track);
+	engine->_music->playAllMusic(track);
 	return 0;
 }
 
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index 645f9b96dca..db1169fdc7c 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -54,7 +54,7 @@ int32 ScriptLifeV1::lBUBBLE_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
  */
 int32 ScriptLifeV1::lPLAY_MIDI(TwinEEngine *engine, LifeScriptContext &ctx) {
 	const int32 midiIdx = ctx.stream.readByte();
-	engine->_music->playMidiMusic(midiIdx); // TODO: improve this
+	engine->_music->playMidiFile(midiIdx); // TODO: improve this
 	debugC(3, kDebugLevels::kDebugScripts, "LIFE::PLAY_MIDI(%i)", (int)midiIdx);
 	return 0;
 }
@@ -65,7 +65,7 @@ int32 ScriptLifeV1::lPLAY_MIDI(TwinEEngine *engine, LifeScriptContext &ctx) {
  */
 int32 ScriptLifeV1::lMIDI_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
 	debugC(3, kDebugLevels::kDebugScripts, "LIFE::MIDI_OFF()");
-	engine->_music->stopMidiMusic();
+	engine->_music->stopMusicMidi();
 	return 0;
 }
 
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index a317c5dc7d9..062606e0d8b 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -387,7 +387,7 @@ Common::Error TwinEEngine::run() {
 
 	_sound->stopSamples();
 	_music->stopTrackMusic();
-	_music->stopMidiMusic();
+	_music->stopMusicMidi();
 	return Common::kNoError;
 }
 


Commit: 69c5c3a43c4444d82b0982fb28061914d0f03aed
    https://github.com/scummvm/scummvm/commit/69c5c3a43c4444d82b0982fb28061914d0f03aed
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-09-13T17:07:29+02:00

Commit Message:
TWINE: updated the music code and renamed methods and variables...

to match the original source code

This should fix issue https://bugs.scummvm.org/ticket/14669 - but it's hard to say due to the many
different versions that are out there

Changed paths:
    engines/twine/audio/music.cpp
    engines/twine/audio/music.h
    engines/twine/debugger/console.cpp
    engines/twine/menu/menu.cpp
    engines/twine/menu/menu.h
    engines/twine/menu/menuoptions.cpp
    engines/twine/scene/gamestate.cpp
    engines/twine/scene/scene.cpp
    engines/twine/scene/scene.h
    engines/twine/script/script_life.cpp
    engines/twine/script/script_life_v1.cpp
    engines/twine/script/script_life_v2.cpp
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/audio/music.cpp b/engines/twine/audio/music.cpp
index 86bae9ecd5f..02947635285 100644
--- a/engines/twine/audio/music.cpp
+++ b/engines/twine/audio/music.cpp
@@ -60,7 +60,7 @@ namespace TwinE {
  * </pre>
  */
 
-TwinEMidiPlayer::TwinEMidiPlayer(TwinEEngine* engine) : _engine(engine) {
+TwinEMidiPlayer::TwinEMidiPlayer(TwinEEngine *engine) : _engine(engine) {
 	MidiPlayer::createDriver();
 
 	int ret = _driver->open();
@@ -101,64 +101,80 @@ void TwinEMidiPlayer::play(byte *buf, int size, bool loop) {
 Music::Music(TwinEEngine *engine) : _engine(engine), _midiPlayer(engine) {
 }
 
-void Music::musicVolume(int32 volume) {
-	_engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType, volume);
-	_midiPlayer.setVolume(volume);
-}
-
-void Music::musicFadeIn() {
-	int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
-	// TODO implement fade in
-	musicVolume(volume);
+int32 Music::getLengthTrackCDR(int track) const {
+	// TODO:
+	return -1;
 }
 
-void Music::musicFadeOut() {
-	int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
-	// TODO implement fade out
-	musicVolume(volume);
-}
+bool Music::playMidi(int32 midiIdx) {
+	const int32 loop = 1;
+	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
+		Common::Path trackName(Common::String::format("lba1-%02i", midiIdx + 1));
+		Audio::SeekableAudioStream *stream = Audio::SeekableAudioStream::openStreamFile(trackName);
+		if (stream != nullptr) {
+			const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
+			_engine->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_midiHandle,
+													 Audio::makeLoopingAudioStream(stream, loop), volume);
+			return true;
+		}
+	}
 
-static const char *musicTracksLba2[] = {
-	"",
-	"TADPCM1",
-	"TADPCM2",
-	"TADPCM3",
-	"TADPCM4",
-	"TADPCM5",
-	"JADPCM01",
-	"",	// Track6.wav
-	"JADPCM02",
-	"JADPCM03",
-	"JADPCM04",
-	"JADPCM05",
-	"JADPCM06",
-	"JADPCM07",
-	"JADPCM08",
-	"JADPCM09",
-	"JADPCM10",
-	"JADPCM11",
-	"JADPCM12",
-	"JADPCM13",
-	"JADPCM14",
-	"JADPCM15",
-	"JADPCM16",
-	"JADPCM17",
-	"JADPCM18",
-	"LOGADPCM"
-};
+	const char *filename;
+	if (_engine->_cfgfile.MidiType == MIDIFILE_DOS) {
+		filename = Resources::HQR_MIDI_MI_DOS_FILE;
+	} else if (_engine->_cfgfile.MidiType == MIDIFILE_WIN) {
+		filename = Resources::HQR_MIDI_MI_WIN_FILE;
+	} else {
+		debug("midi disabled - skip playing %i", midiIdx);
+		return false;
+	}
 
-bool Music::playCdTrack(int32 track) {
-	if (!_engine->_cfgfile.UseCD) {
+	int32 midiSize = HQR::getAllocEntry(&midiPtr, filename, midiIdx);
+	if (midiSize == 0) {
+		debug("Could not find midi file for index %i", midiIdx);
 		return false;
 	}
+	debug("Play midi file for index %i", midiIdx);
+	_midiPlayer.play(midiPtr, midiSize, loop == 0 || loop > 1);
+	return true;
+}
 
+bool Music::playTrackCDR(int32 track) {
 	if (_engine->isLBA2()) {
+		static const char *musicTracksLba2[] = {
+			"",
+			"TADPCM1",
+			"TADPCM2",
+			"TADPCM3",
+			"TADPCM4",
+			"TADPCM5",
+			"JADPCM01",
+			"", // Track6.wav
+			"JADPCM02",
+			"JADPCM03",
+			"JADPCM04",
+			"JADPCM05",
+			"JADPCM06",
+			"JADPCM07",
+			"JADPCM08",
+			"JADPCM09",
+			"JADPCM10",
+			"JADPCM11",
+			"JADPCM12",
+			"JADPCM13",
+			"JADPCM14",
+			"JADPCM15",
+			"JADPCM16",
+			"JADPCM17",
+			"JADPCM18",
+			"LOGADPCM"};
+
 		const char *basename = musicTracksLba2[track];
 		Audio::SeekableAudioStream *stream = Audio::SeekableAudioStream::openStreamFile(basename);
 		if (stream != nullptr) {
 			const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
 			_engine->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_midiHandle,
-						Audio::makeLoopingAudioStream(stream, 1), volume);
+													 Audio::makeLoopingAudioStream(stream, 1), volume);
 			debug(3, "Play audio track %s for track id %i", basename, track);
 			return true;
 		}
@@ -170,10 +186,18 @@ bool Music::playCdTrack(int32 track) {
 	}
 
 	AudioCDManager *cdrom = g_system->getAudioCDManager();
-	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
-		track += 1;
-	}
-	return cdrom->play(track, 1, 0, 0);
+	return cdrom->play(track + 1, 1, 0, 0);
+}
+
+bool Music::initCdrom() {
+	AudioCDManager *cdrom = g_system->getAudioCDManager();
+	return cdrom->open();
+}
+
+void Music::stopMusic() {
+	stopMusicCD();
+	stopMusicMidi();
+	numXmi = -1;
 }
 
 void Music::stopMusicCD() {
@@ -181,7 +205,23 @@ void Music::stopMusicCD() {
 	cdrom->stop();
 }
 
-bool Music::playAllMusic(int32 track) {
+void Music::fadeMusicMidi(uint32 time) {
+	// TODO implement fade out
+	stopMusicMidi();
+}
+
+void Music::stopMusicMidi() {
+	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic() || _engine->isLBA2()) {
+		_engine->_system->getMixer()->stopHandle(_midiHandle);
+	}
+
+	_midiPlayer.stop();
+	free(midiPtr);
+	midiPtr = nullptr;
+	numXmi = -1;
+}
+
+bool Music::playMusic(int32 track) {
 	if (track == -1) {
 		stopMusic();
 		return true;
@@ -190,103 +230,101 @@ bool Music::playAllMusic(int32 track) {
 		return false;
 	}
 
-	if (track == currentMusic) {
-		return true;
-	}
-
-	stopMusic();
-	if (playCdTrack(track)) {
-		currentMusic = track;
-		debug("Play cd music track %i", track);
-		return true;
-	}
-	if (playMidiFile(track)) {
-		currentMusic = track;
-		debug("Play midi music track %i", track);
-		return true;
+	if (_engine->isCDROM()) {
+		if (_flagVoiceCD || track < 1 || track > 9) {
+			if (playMidiFile(track)) {
+				debug("Play midi music track %i", track);
+				return true;
+			}
+		} else {
+			if (playCdTrack(track)) {
+				debug("Play cd music track %i", track);
+				return true;
+			}
+		}
+	} else {
+		if (playMidiFile(track)) {
+			debug("Play midi music track %i", track);
+			return true;
+		}
 	}
 	warning("Failed to play track %i", track);
 	return false;
 }
 
-void Music::stopTrackMusic() {
-	if (!_engine->_cfgfile.Sound) {
-		return;
-	}
-
-	musicFadeOut();
-	stopMusicCD();
-}
-
 bool Music::playMidiFile(int32 midiIdx) {
 	if (!_engine->_cfgfile.Sound) {
 		debug("sound disabled - skip playing %i", midiIdx);
 		return false;
 	}
 
-	if (midiIdx == currentMusic) {
-		debug("already playing %i", midiIdx);
-		return true;
+	if (_engine->isCDROM()) {
+		stopMusicCD();
 	}
 
-	stopMusic();
-	currentMusic = midiIdx;
-
-	musicFadeOut();
-	stopMusicMidi();
-
-	const int32 loop = 1;
-	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
-		Common::Path trackName(Common::String::format("lba1-%02i", midiIdx + 1));
-		Audio::SeekableAudioStream *stream = Audio::SeekableAudioStream::openStreamFile(trackName);
-		if (stream != nullptr) {
-			const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
-			_engine->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_midiHandle,
-						Audio::makeLoopingAudioStream(stream, loop), volume);
-			return true;
+	if (midiIdx != numXmi || !isMidiPlaying()) {
+		stopMusicMidi();
+		numXmi = midiIdx;
+		if (!playMidi(midiIdx)) {
+			return false;
 		}
+		// volumeMidi(100);
 	}
+	return true;
+}
 
-	const char *filename;
-	if (_engine->_cfgfile.MidiType == MIDIFILE_DOS) {
-		filename = Resources::HQR_MIDI_MI_DOS_FILE;
-	} else if (_engine->_cfgfile.MidiType == MIDIFILE_WIN){
-		filename = Resources::HQR_MIDI_MI_WIN_FILE;
-	} else {
-		debug("midi disabled - skip playing %i", midiIdx);
-		return false;
+int32 Music::getMusicCD() {
+	AudioCDManager *cdrom = g_system->getAudioCDManager();
+	// if (_engine->_system->getMillis() > endMusicCD) {
+	if (!cdrom->isPlaying()) {
+		currentMusicCD = -1;
 	}
+	return currentMusicCD;
+}
 
-	int32 midiSize = HQR::getAllocEntry(&midiPtr, filename, midiIdx);
-	if (midiSize == 0) {
-		debug("Could not find midi file for index %i", midiIdx);
-		return false;
+bool Music::playCdTrack(int32 track) {
+	fadeMusicMidi(1);
+	numXmi = -1;
+
+	if (track != getMusicCD()) {
+		stopMusicCD();
+		// TODO: endMusicCD = _engine->toSeconds(getLengthTrackCDR(track + 1)) / 75 + _engine->toSeconds(1);
+		if (playTrackCDR(track)) {
+			// TODO: endMusicCD += _engine->_system->getMillis();
+			currentMusicCD = track;
+		}
 	}
-	debug("Play midi file for index %i", midiIdx);
-	_midiPlayer.play(midiPtr, midiSize, loop == 0 || loop > 1);
 	return true;
 }
 
-void Music::stopMusicMidi() {
-	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic() || _engine->isLBA2()) {
-		_engine->_system->getMixer()->stopHandle(_midiHandle);
+void Music::playAllMusic(int num) {
+	if (num != numXmi || !isMidiPlaying()) {
+		stopMusicMidi();
+		numXmi = num;
+		playMidi(num);
+		// volumeMidi(100);
+	}
+	if (num != getMusicCD()) {
+		stopMusicCD();
+		// TODO: endMusicCD = _engine->toSeconds(getLengthTrackCDR(num + 1)) / 75 + _engine->toSeconds(1);
+		if (playTrackCDR(num)) {
+			// TODO: endMusicCD += _engine->_system->getMillis();
+			currentMusicCD = num;
+		}
 	}
-
-	_midiPlayer.stop();
-	free(midiPtr);
-	midiPtr = nullptr;
 }
 
-bool Music::initCdrom() {
-	AudioCDManager* cdrom = g_system->getAudioCDManager();
-	_engine->_cfgfile.UseCD = cdrom->open();
-	return _engine->_cfgfile.UseCD;
+bool Music::isMidiPlaying() const {
+	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
+		return _engine->_system->getMixer()->isSoundHandleActive(_midiHandle);
+	}
+
+	return _midiPlayer.isPlaying();
 }
 
-void Music::stopMusic() {
-	stopTrackMusic();
-	stopMusicMidi();
-	currentMusic = -1;
+void Music::musicVolume(int32 volume) {
+	_engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType, volume);
+	_midiPlayer.setVolume(volume);
 }
 
 } // namespace TwinE
diff --git a/engines/twine/audio/music.h b/engines/twine/audio/music.h
index 7e847b96ef1..4a4d67f7925 100644
--- a/engines/twine/audio/music.h
+++ b/engines/twine/audio/music.h
@@ -43,27 +43,27 @@ private:
 	TwinEEngine *_engine;
 	TwinEMidiPlayer _midiPlayer;
 
-	void musicFadeIn();
-	void musicFadeOut();
+	void fadeMusicMidi(uint32 time = 1);
 
 	/** Auxiliar midi pointer to  */
 	uint8 *midiPtr = nullptr;
 	Audio::SoundHandle _midiHandle;
 	/** Track number of the current playing music */
-	int32 currentMusic = -1; // NumXmi, CurrentMusicCD
+	int32 numXmi = -1;
+	int32 currentMusicCD = -1;
+	// int32 endMusicCD = -1;
+	const bool _flagVoiceCD = false;
 public:
 	// TODO: implement the handling
 	int32 _nextMusic = -1;       // lba2: NextMusic
 	int32 _nextMusicTimer;       // lba2: NextMusicTimer
 	bool _stopLastMusic = false; // lba2: StopLastMusic
 private:
-	/**
-	 * Play CD music
-	 * @param track track number to play
-	 */
-	bool playCdTrack(int32 track);
 	/** Stop CD music */
 	void stopMusicCD();
+	bool playMidi(int32 midiIdx);
+	int32 getLengthTrackCDR(int track) const;
+	bool playTrackCDR(int32 track);
 public:
 	Music(TwinEEngine *engine);
 
@@ -73,19 +73,25 @@ public:
 	 */
 	void musicVolume(int32 volume);
 
+	/**
+	 * Play CD music
+	 * @param track track number to play
+	 */
+	bool playCdTrack(int32 track);
 	/**
 	 * Generic play music, according with settings it plays CD or high quality sounds instead
 	 * @param track track number to play
 	 */
-	bool playAllMusic(int32 track);
-	/** Generic stop music according with settings */
-	void stopTrackMusic();
+	bool playMusic(int32 track);
 	/**
 	 * Play MIDI music
 	 * @param midiIdx music index under mini_mi_win.hqr
 	 * @note valid indices for lba1 are [1-32]
 	 */
 	bool playMidiFile(int32 midiIdx);
+
+	void playAllMusic(int track);
+
 	/** Stop MIDI music */
 	void stopMusicMidi();
 
@@ -94,6 +100,9 @@ public:
 
 	/** Stop MIDI and Track music */
 	void stopMusic();
+
+	bool isMidiPlaying() const;
+	int32 getMusicCD();
 };
 
 } // namespace TwinE
diff --git a/engines/twine/debugger/console.cpp b/engines/twine/debugger/console.cpp
index e614069af4f..4553c9ac29c 100644
--- a/engines/twine/debugger/console.cpp
+++ b/engines/twine/debugger/console.cpp
@@ -405,7 +405,7 @@ bool TwinEConsole::doPlayMusic(int argc, const char **argv) {
 		return true;
 	}
 	int newMusicTrackIndex = atoi(argv[1]);
-	_engine->_music->playAllMusic(newMusicTrackIndex);
+	_engine->_music->playMusic(newMusicTrackIndex);
 	return true;
 }
 
@@ -421,7 +421,7 @@ bool TwinEConsole::doChangeScene(int argc, const char **argv) {
 	}
 	_engine->_scene->_needChangeScene = atoi(argv[1]);
 	_engine->_scene->_heroPositionType = ScenePositionType::kScene;
-	_engine->_scene->changeScene();
+	_engine->_scene->changeCube();
 	return true;
 }
 
diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index 27f167388af..af79295caea 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -447,7 +447,7 @@ int16 Menu::drawButtons(MenuSettings *menuSettings, bool hover) {
 	return mouseActiveButton;
 }
 
-int32 Menu::processMenu(MenuSettings *menuSettings) {
+int32 Menu::doGameMenu(MenuSettings *menuSettings) {
 	int16 currentButton = menuSettings->getActiveButton();
 	bool buttonsNeedRedraw = true;
 	const int32 numEntry = menuSettings->getButtonCount();
@@ -694,7 +694,7 @@ int32 Menu::advoptionsMenu() {
 
 	ScopedCursor scoped(_engine);
 	for (;;) {
-		switch (processMenu(&_advOptionsMenuState)) {
+		switch (doGameMenu(&_advOptionsMenuState)) {
 		case (int32)TextId::kReturnMenu: {
 			return 0;
 		}
@@ -718,7 +718,7 @@ int32 Menu::savemanageMenu() {
 
 	ScopedCursor scoped(_engine);
 	for (;;) {
-		switch (processMenu(&_saveManageMenuState)) {
+		switch (doGameMenu(&_saveManageMenuState)) {
 		case (int32)TextId::kReturnMenu:
 			return 0;
 		case (int32)TextId::kCreateSaveGame:
@@ -738,12 +738,20 @@ int32 Menu::savemanageMenu() {
 	return 0;
 }
 
-int32 Menu::volumeMenu() {
+int32 Menu::volumeOptions() {
 	_engine->restoreFrontBuffer();
 
+	if (_engine->isLBA1()) {
+		if (_engine->isCDROM()) {
+			_engine->_music->playAllMusic(9);
+		} else {
+			_engine->_music->playMidiFile(9);
+		}
+	}
+
 	ScopedCursor scoped(_engine);
 	for (;;) {
-		switch (processMenu(&_volumeMenuState)) {
+		switch (doGameMenu(&_volumeMenuState)) {
 		case (int32)TextId::kReturnMenu:
 			return 0;
 		case kQuitEngine:
@@ -766,7 +774,7 @@ int32 Menu::languageMenu() {
 
 	ScopedCursor scoped(_engine);
 	for (;;) {
-		switch (processMenu(&_languageMenuState)) {
+		switch (doGameMenu(&_languageMenuState)) {
 		case (int32)TextId::kReturnMenu:
 			return 0;
 		case kQuitEngine:
@@ -794,17 +802,17 @@ int32 Menu::optionsMenu() {
 	_engine->restoreFrontBuffer();
 
 	_engine->_sound->stopSamples();
-	_engine->_music->playAllMusic(9); // LBA's Theme
+	_engine->_music->playMusic(9); // LBA's Theme
 
 	ScopedCursor scoped(_engine);
 	for (;;) {
-		switch (processMenu(&_optionsMenuState)) {
+		switch (doGameMenu(&_optionsMenuState)) {
 		case (int32)TextId::kReturnGame:
 		case (int32)TextId::kReturnMenu: {
 			return 0;
 		}
 		case (int32)TextId::kVolumeSettings: {
-			checkMenuQuit(volumeMenu()) break;
+			checkMenuQuit(volumeOptions()) break;
 		}
 		case (int32)TextId::kCustomLanguageOption: {
 			checkMenuQuit(languageMenu()) break;
@@ -830,7 +838,7 @@ int32 Menu::newGameClassicMenu() {
 
 	ScopedCursor scoped(_engine);
 	for (;;) {
-		switch (processMenu(&_newGameMenuState)) {
+		switch (doGameMenu(&_newGameMenuState)) {
 		case (int32)TextId::kReturnGame:
 		case (int32)TextId::kReturnMenu: {
 			return 0;
@@ -896,15 +904,19 @@ EngineState Menu::run() {
 	FrameMarker frame(_engine);
 	_engine->_text->initDial(TextBankId::Options_and_menus);
 
+	_engine->_sound->stopSamples();
 	if (_engine->isLBA1()) {
-		_engine->_music->playAllMusic(9); // LBA's Theme
+		if (_engine->isCDROM()) {
+			_engine->_music->playCdTrack(9); // LBA's Theme
+		} else {
+			_engine->_music->playMidiFile(9); // LBA's Theme
+		}
 	} else {
-		_engine->_music->playAllMusic(6); // LBA2's Theme
+		_engine->_music->playMusic(6); // LBA2's Theme
 	}
-	_engine->_sound->stopSamples();
 
 	ScopedCursor scoped(_engine);
-	switch (processMenu(&_mainMenuState)) {
+	switch (doGameMenu(&_mainMenuState)) {
 	case (int32)TextId::toNewGame:
 	case (int32)TextId::kNewGame: {
 		if (_engine->isLba1Classic()) {
@@ -960,7 +972,7 @@ int32 Menu::giveupMenu() {
 	do {
 		FrameMarker frame(_engine);
 		_engine->_text->initDial(TextBankId::Options_and_menus);
-		menuId = processMenu(localMenu);
+		menuId = doGameMenu(localMenu);
 		switch (menuId) {
 		case (int32)TextId::kContinue:
 			_engine->_sound->resumeSamples();
diff --git a/engines/twine/menu/menu.h b/engines/twine/menu/menu.h
index 24b0e560807..4689127c220 100644
--- a/engines/twine/menu/menu.h
+++ b/engines/twine/menu/menu.h
@@ -181,7 +181,7 @@ private:
 	/** Used to run the advanced options menu */
 	int32 advoptionsMenu();
 	/** Used to run the volume menu */
-	int32 volumeMenu();
+	int32 volumeOptions();
 	int32 languageMenu();
 	/** Used to run the save game management menu */
 	int32 savemanageMenu();
@@ -226,7 +226,7 @@ public:
 	 * @param menuSettings menu settings array with the information to build the menu options
 	 * @return pressed menu button identification
 	 */
-	int32 processMenu(MenuSettings *menuSettings);
+	int32 doGameMenu(MenuSettings *menuSettings);
 
 	bool init();
 
diff --git a/engines/twine/menu/menuoptions.cpp b/engines/twine/menu/menuoptions.cpp
index 910a634521d..0a124f1cf03 100644
--- a/engines/twine/menu/menuoptions.cpp
+++ b/engines/twine/menu/menuoptions.cpp
@@ -379,7 +379,7 @@ int MenuOptions::chooseSave(TextId textIdx, bool showEmptySlots) {
 		}
 	}
 
-	const int32 id = _engine->_menu->processMenu(&saveFiles);
+	const int32 id = _engine->_menu->doGameMenu(&saveFiles);
 	switch (id) {
 	case kQuitEngine:
 	case (int32)TextId::kReturnMenu:
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index d70c4a3cc64..3442e8c522b 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -487,7 +487,7 @@ void GameState::processGameChoices(TextId choiceIdx) {
 
 	_engine->_text->drawAskQuestion(choiceIdx);
 
-	_engine->_menu->processMenu(&_gameChoicesSettings);
+	_engine->_menu->doGameMenu(&_gameChoicesSettings);
 	const int16 activeButton = _gameChoicesSettings.getActiveButton();
 	_choiceAnswer = _gameChoices[activeButton];
 
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index 25df4d33fb5..da24815b642 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -206,7 +206,7 @@ bool Scene::loadSceneLBA2() {
 	_sampleMinDelay = stream.readUint16LE();
 	_sampleMinDelayRnd = stream.readUint16LE();
 
-	_sceneMusic = stream.readByte();
+	_cubeJingle = stream.readByte();
 
 	// load hero properties
 	_sceneHeroPos.x = stream.readSint16LE();
@@ -339,7 +339,7 @@ bool Scene::loadSceneLBA1() {
 	_sampleMinDelay = stream.readUint16LE();
 	_sampleMinDelayRnd = stream.readUint16LE();
 
-	_sceneMusic = stream.readByte();
+	_cubeJingle = stream.readByte();
 
 	// load hero properties
 	_sceneHeroPos.x = (int16)stream.readUint16LE();
@@ -519,8 +519,7 @@ void Scene::dumpSceneScripts() const {
 	}
 }
 
-// ChangeCube
-void Scene::changeScene() {
+void Scene::changeCube() {
 	if (_engine->isLBA1()) {
 		if (_enableEnhancements) {
 			if (_currentSceneIdx == LBA1SceneId::Citadel_Island_Harbor && _needChangeScene == LBA1SceneId::Principal_Island_Harbor) {
@@ -637,9 +636,9 @@ void Scene::changeScene() {
 	_zoneHeroPos = IVec3();
 	_sampleAmbienceTime = 0;
 
-	if (_sceneMusic != -1) {
-		debug(2, "Scene %i music track id: %i", _currentSceneIdx, _sceneMusic);
-		_engine->_music->playAllMusic(_sceneMusic);
+	debug(2, "Scene %i music track id: %i", _currentSceneIdx, _cubeJingle);
+	if (_cubeJingle != 255) {
+		_engine->_music->playMusic(_cubeJingle);
 	}
 	_engine->_gameState->handleLateGameItems();
 }
@@ -675,11 +674,15 @@ void Scene::initSceneVars() {
 void Scene::playSceneMusic() {
 	if (_engine->isLBA1()) {
 		if (_currentSceneIdx == LBA1SceneId::Tippet_Island_Twinsun_Cafe && _engine->_gameState->hasArrivedHamalayi()) {
-			_engine->_music->playAllMusic(8);
+			if (_engine->isCDROM()) {
+				_engine->_music->playCdTrack(8);
+			} else {
+				_engine->_music->playMusic(_cubeJingle);
+			}
 			return;
 		}
 	}
-	_engine->_music->playMidiFile(_sceneMusic);
+	_engine->_music->playMidiFile(_cubeJingle);
 }
 
 void Scene::processEnvironmentSound() {
diff --git a/engines/twine/scene/scene.h b/engines/twine/scene/scene.h
index d5bf6d66b7b..7789280017f 100644
--- a/engines/twine/scene/scene.h
+++ b/engines/twine/scene/scene.h
@@ -147,7 +147,7 @@ private:
 	int16 _samplePlayed = 0;
 
 public:
-	int16 _sceneMusic = 0;  // CubeJingle
+	int16 _cubeJingle = 0;
 private:
 	IVec3 _sceneHeroPos;
 	IVec3 _zoneHeroPos;
@@ -222,7 +222,7 @@ public:
 	void reloadCurrentScene();
 
 	/** Change to another scene */
-	void changeScene();
+	void changeCube();
 
 	/** For the buggy to get the 2D coordinates of an exterior cube in the map */
 	bool loadSceneCubeXY(int sceneNum, int32 *cubeX, int32 *cubeY);
diff --git a/engines/twine/script/script_life.cpp b/engines/twine/script/script_life.cpp
index 835f71dd98c..6210082ea5c 100644
--- a/engines/twine/script/script_life.cpp
+++ b/engines/twine/script/script_life.cpp
@@ -1981,7 +1981,7 @@ int32 ScriptLife::lTHE_END(TwinEEngine *engine, LifeScriptContext &ctx) {
 int32 ScriptLife::lPLAY_CD_TRACK(TwinEEngine *engine, LifeScriptContext &ctx) {
 	const int32 track = ctx.stream.readByte();
 	debugC(3, kDebugLevels::kDebugScripts, "LIFE::PLAY_CD_TRACK(%i)", (int)track);
-	engine->_music->playAllMusic(track);
+	engine->_music->playCdTrack(track);
 	return 0;
 }
 
diff --git a/engines/twine/script/script_life_v1.cpp b/engines/twine/script/script_life_v1.cpp
index db1169fdc7c..0461d1f606b 100644
--- a/engines/twine/script/script_life_v1.cpp
+++ b/engines/twine/script/script_life_v1.cpp
@@ -54,7 +54,7 @@ int32 ScriptLifeV1::lBUBBLE_OFF(TwinEEngine *engine, LifeScriptContext &ctx) {
  */
 int32 ScriptLifeV1::lPLAY_MIDI(TwinEEngine *engine, LifeScriptContext &ctx) {
 	const int32 midiIdx = ctx.stream.readByte();
-	engine->_music->playMidiFile(midiIdx); // TODO: improve this
+	engine->_music->playMusic(midiIdx);
 	debugC(3, kDebugLevels::kDebugScripts, "LIFE::PLAY_MIDI(%i)", (int)midiIdx);
 	return 0;
 }
diff --git a/engines/twine/script/script_life_v2.cpp b/engines/twine/script/script_life_v2.cpp
index ecc88aa85b3..79cad5abc0a 100644
--- a/engines/twine/script/script_life_v2.cpp
+++ b/engines/twine/script/script_life_v2.cpp
@@ -220,7 +220,7 @@ int32 ScriptLifeV2::lPLAY_MUSIC(TwinEEngine *engine, LifeScriptContext &ctx) {
 	debugC(3, kDebugLevels::kDebugScripts, "LIFE::lPLAY_MUSIC()");
 	const int32 val = lPLAY_CD_TRACK(engine, ctx);
 	if (engine->isLBA2()) {
-		engine->_scene->_sceneMusic = 255;
+		engine->_scene->_cubeJingle = 255;
 		engine->_music->_nextMusic = -1;
 		if (engine->_gameState->hasGameFlag(157) > 0) {
 			engine->_music->_stopLastMusic = false;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 062606e0d8b..d3b2720db4d 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -386,8 +386,7 @@ Common::Error TwinEEngine::run() {
 	ConfMan.setInt("polygondetails", _cfgfile.PolygonDetails);
 
 	_sound->stopSamples();
-	_music->stopTrackMusic();
-	_music->stopMusicMidi();
+	_music->stopMusic();
 	return Common::kNoError;
 }
 
@@ -510,7 +509,6 @@ void TwinEEngine::initConfigurations() {
 		_cfgfile.Movie = CONF_MOVIE_FLAGIF;
 	}
 
-	_cfgfile.UseCD = ConfGetBoolOrDefault("usecd", false);
 	_cfgfile.Sound = ConfGetBoolOrDefault("sound", true);
 	_cfgfile.Fps = ConfGetIntOrDefault("fps", DEFAULT_FRAMES_PER_SECOND);
 	_cfgfile.Debug = ConfGetBoolOrDefault("debug", false);
@@ -528,7 +526,6 @@ void TwinEEngine::initConfigurations() {
 	if (ttsMan != nullptr)
 		ttsMan->enable(ConfGetBoolOrDefault("tts_narrator", false));
 
-	debug(1, "UseCD:          %s", (_cfgfile.UseCD ? "true" : "false"));
 	debug(1, "Sound:          %s", (_cfgfile.Sound ? "true" : "false"));
 	debug(1, "Movie:          %i", _cfgfile.Movie);
 	debug(1, "Fps:            %i", _cfgfile.Fps);
@@ -859,11 +856,11 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
 		if (!isMod() && isDemo() && isLBA1()) {
 			// the demo only has these scenes
 			if (_scene->_needChangeScene != LBA1SceneId::Citadel_Island_Prison && _scene->_needChangeScene != LBA1SceneId::Citadel_Island_outside_the_citadel && _scene->_needChangeScene != LBA1SceneId::Citadel_Island_near_the_tavern) {
-				// TODO: PlayMidiFile(6);
+				_music->playMidiFile(6);
 				return true;
 			}
 		}
-		_scene->changeScene();
+		_scene->changeCube();
 	}
 
 	_movements->update();
@@ -871,7 +868,15 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
 	_debug->processDebug();
 
 	if (_menuOptions->canShowCredits) {
-		// TODO: if current music playing != 8, than play_track(8);
+		if (isLBA1()) {
+			if (isCDROM()) {
+				if (_music->getMusicCD() != 8) {
+					_music->playCdTrack(8);
+				}
+			} else if (!_music->isMidiPlaying()) {
+				_music->playMidiFile(9);
+			}
+		}
 		if (_input->toggleAbortAction()) {
 			return true;
 		}
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index 3c44890fc50..db4db7dd456 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -98,8 +98,6 @@ struct ConfigFile {
 	MidiFileType MidiType = MIDIFILE_NONE;
 	/** Game version */
 	int32 Version = EUROPE_VERSION;
-	/** If you want to use the LBA CD or not */
-	int32 UseCD = 0;
 	/** Allow various sound types */
 	int32 Sound = 0;
 	/** Allow various movie types */


Commit: 37cac532ddc00bce55ec87a13c68c90054e6d93a
    https://github.com/scummvm/scummvm/commit/37cac532ddc00bce55ec87a13c68c90054e6d93a
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-09-13T17:07:29+02:00

Commit Message:
TWINE: fixed demo menu handling for music

Changed paths:
    engines/twine/audio/music.cpp
    engines/twine/detection.cpp
    engines/twine/detection.h
    engines/twine/menu/menu.cpp
    engines/twine/menu/menu.h
    engines/twine/menu/menuoptions.cpp
    engines/twine/menu/menuoptions.h
    engines/twine/metaengine.cpp
    engines/twine/scene/gamestate.cpp
    engines/twine/twine.cpp


diff --git a/engines/twine/audio/music.cpp b/engines/twine/audio/music.cpp
index 02947635285..f68a2ac0828 100644
--- a/engines/twine/audio/music.cpp
+++ b/engines/twine/audio/music.cpp
@@ -93,6 +93,7 @@ void TwinEMidiPlayer::play(byte *buf, int size, bool loop) {
 	_parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
 
 	syncVolume();
+	debug("play midi with volume: %i", getVolume());
 
 	_isLooping = loop;
 	_isPlaying = true;
@@ -109,12 +110,16 @@ int32 Music::getLengthTrackCDR(int track) const {
 bool Music::playMidi(int32 midiIdx) {
 	const int32 loop = 1;
 	if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
-		Common::Path trackName(Common::String::format("lba1-%02i", midiIdx + 1));
+		// the midi tracks are stored in the lba1-xx files and the adeline logo jingle
+		// is in lba1-32.xx - while the midiIdx is 31
+		const int32 trackOffset = 1;
+		Common::Path trackName(Common::String::format("lba1-%02i", midiIdx + trackOffset));
 		Audio::SeekableAudioStream *stream = Audio::SeekableAudioStream::openStreamFile(trackName);
 		if (stream != nullptr) {
 			const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
 			_engine->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_midiHandle,
 													 Audio::makeLoopingAudioStream(stream, loop), volume);
+			debug("Play midi music track %i", midiIdx);
 			return true;
 		}
 	}
@@ -197,7 +202,6 @@ bool Music::initCdrom() {
 void Music::stopMusic() {
 	stopMusicCD();
 	stopMusicMidi();
-	numXmi = -1;
 }
 
 void Music::stopMusicCD() {
@@ -233,18 +237,15 @@ bool Music::playMusic(int32 track) {
 	if (_engine->isCDROM()) {
 		if (_flagVoiceCD || track < 1 || track > 9) {
 			if (playMidiFile(track)) {
-				debug("Play midi music track %i", track);
 				return true;
 			}
 		} else {
 			if (playCdTrack(track)) {
-				debug("Play cd music track %i", track);
 				return true;
 			}
 		}
 	} else {
 		if (playMidiFile(track)) {
-			debug("Play midi music track %i", track);
 			return true;
 		}
 	}
@@ -288,9 +289,10 @@ bool Music::playCdTrack(int32 track) {
 
 	if (track != getMusicCD()) {
 		stopMusicCD();
-		// TODO: endMusicCD = _engine->toSeconds(getLengthTrackCDR(track + 1)) / 75 + _engine->toSeconds(1);
+		// TODO: endMusicCD = _engine->toSeconds(getLengthTrackCDR(track)) / 75 + _engine->toSeconds(1);
 		if (playTrackCDR(track)) {
 			// TODO: endMusicCD += _engine->_system->getMillis();
+			debug("Play cd music track %i", track);
 			currentMusicCD = track;
 		}
 	}
@@ -306,7 +308,7 @@ void Music::playAllMusic(int num) {
 	}
 	if (num != getMusicCD()) {
 		stopMusicCD();
-		// TODO: endMusicCD = _engine->toSeconds(getLengthTrackCDR(num + 1)) / 75 + _engine->toSeconds(1);
+		// TODO: endMusicCD = _engine->toSeconds(getLengthTrackCDR(num)) / 75 + _engine->toSeconds(1);
 		if (playTrackCDR(num)) {
 			// TODO: endMusicCD += _engine->_system->getMillis();
 			currentMusicCD = num;
diff --git a/engines/twine/detection.cpp b/engines/twine/detection.cpp
index 10c252ab3ef..3d4ad4f4bc5 100644
--- a/engines/twine/detection.cpp
+++ b/engines/twine/detection.cpp
@@ -416,7 +416,7 @@ static const ADGameDescription twineGameDescriptions[] = {
 class TwinEMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
 public:
 	TwinEMetaEngineDetection() : AdvancedMetaEngineDetection(twineGameDescriptions, twineGames) {
-		_guiOptions = GUIO12(GAMEOPTION_WALL_COLLISION, GAMEOPTION_DISABLE_SAVE_MENU,  GAMEOPTION_DEBUG, GAMEOPTION_AUDIO_CD, GAMEOPTION_SOUND, GAMEOPTION_VOICES, GAMEOPTION_TEXT, GAMEOPTION_MOVIES, GAMEOPTION_MOUSE, GAMEOPTION_USA_VERSION, GAMEOPTION_HIGH_RESOLUTION, GAMEOPTION_TEXT_TO_SPEECH);
+		_guiOptions = GUIO11(GAMEOPTION_WALL_COLLISION, GAMEOPTION_DISABLE_SAVE_MENU,  GAMEOPTION_DEBUG, GAMEOPTION_SOUND, GAMEOPTION_VOICES, GAMEOPTION_TEXT, GAMEOPTION_MOVIES, GAMEOPTION_MOUSE, GAMEOPTION_USA_VERSION, GAMEOPTION_HIGH_RESOLUTION, GAMEOPTION_TEXT_TO_SPEECH);
 	}
 
 	const char *getName() const override {
diff --git a/engines/twine/detection.h b/engines/twine/detection.h
index ad5978872ee..d9388f9e938 100644
--- a/engines/twine/detection.h
+++ b/engines/twine/detection.h
@@ -44,15 +44,14 @@ enum TwineFeatureFlags {
 #define GAMEOPTION_WALL_COLLISION GUIO_GAMEOPTIONS1
 #define GAMEOPTION_DISABLE_SAVE_MENU GUIO_GAMEOPTIONS2
 #define GAMEOPTION_DEBUG GUIO_GAMEOPTIONS3
-#define GAMEOPTION_AUDIO_CD GUIO_GAMEOPTIONS4
-#define GAMEOPTION_SOUND GUIO_GAMEOPTIONS5
-#define GAMEOPTION_VOICES GUIO_GAMEOPTIONS6
-#define GAMEOPTION_TEXT GUIO_GAMEOPTIONS7
-#define GAMEOPTION_MOVIES GUIO_GAMEOPTIONS8
-#define GAMEOPTION_MOUSE GUIO_GAMEOPTIONS9
-#define GAMEOPTION_USA_VERSION GUIO_GAMEOPTIONS10
-#define GAMEOPTION_HIGH_RESOLUTION GUIO_GAMEOPTIONS11
-#define GAMEOPTION_TEXT_TO_SPEECH GUIO_GAMEOPTIONS12
+#define GAMEOPTION_SOUND GUIO_GAMEOPTIONS4
+#define GAMEOPTION_VOICES GUIO_GAMEOPTIONS5
+#define GAMEOPTION_TEXT GUIO_GAMEOPTIONS6
+#define GAMEOPTION_MOVIES GUIO_GAMEOPTIONS7
+#define GAMEOPTION_MOUSE GUIO_GAMEOPTIONS8
+#define GAMEOPTION_USA_VERSION GUIO_GAMEOPTIONS9
+#define GAMEOPTION_HIGH_RESOLUTION GUIO_GAMEOPTIONS10
+#define GAMEOPTION_TEXT_TO_SPEECH GUIO_GAMEOPTIONS11
 
 } // End of namespace TwinE
 
diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index af79295caea..1cf116221b2 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -31,22 +31,22 @@
 #include "common/system.h"
 #include "common/util.h"
 #include "graphics/cursorman.h"
-#include "twine/scene/actor.h"
-#include "twine/scene/animations.h"
 #include "twine/audio/music.h"
 #include "twine/audio/sound.h"
-#include "twine/movies.h"
-#include "twine/scene/gamestate.h"
-#include "twine/scene/grid.h"
-#include "twine/resources/hqr.h"
 #include "twine/input.h"
 #include "twine/menu/interface.h"
 #include "twine/menu/menuoptions.h"
-#include "twine/scene/movements.h"
+#include "twine/movies.h"
 #include "twine/renderer/redraw.h"
 #include "twine/renderer/renderer.h"
 #include "twine/renderer/screens.h"
+#include "twine/resources/hqr.h"
 #include "twine/resources/resources.h"
+#include "twine/scene/actor.h"
+#include "twine/scene/animations.h"
+#include "twine/scene/gamestate.h"
+#include "twine/scene/grid.h"
+#include "twine/scene/movements.h"
 #include "twine/scene/scene.h"
 #include "twine/shared.h"
 #include "twine/text.h"
@@ -79,7 +79,6 @@ enum MenuButtonTypesEnum {
 	if ((callMenu) == kQuitEngine) { \
 		return kQuitEngine;          \
 	}
-#define kBackground 9999
 
 namespace _priv {
 
@@ -219,12 +218,12 @@ void Menu::plasmaEffectRenderFrame() {
 			/* Here we calculate the average of all 8 neighbour pixel values */
 
 			int16 c;
-			c = _plasmaEffectPtr[(i - 1) + (j - 1) * PLASMA_WIDTH];  //top-left
-			c += _plasmaEffectPtr[(i + 0) + (j - 1) * PLASMA_WIDTH]; //top
-			c += _plasmaEffectPtr[(i + 1) + (j - 1) * PLASMA_WIDTH]; //top-right
+			c = _plasmaEffectPtr[(i - 1) + (j - 1) * PLASMA_WIDTH];  // top-left
+			c += _plasmaEffectPtr[(i + 0) + (j - 1) * PLASMA_WIDTH]; // top
+			c += _plasmaEffectPtr[(i + 1) + (j - 1) * PLASMA_WIDTH]; // top-right
 
-			c += _plasmaEffectPtr[(i - 1) + (j + 0) * PLASMA_WIDTH]; //left
-			c += _plasmaEffectPtr[(i + 1) + (j + 0) * PLASMA_WIDTH]; //right
+			c += _plasmaEffectPtr[(i - 1) + (j + 0) * PLASMA_WIDTH]; // left
+			c += _plasmaEffectPtr[(i + 1) + (j + 0) * PLASMA_WIDTH]; // right
 
 			c += _plasmaEffectPtr[(i - 1) + (j + 1) * PLASMA_WIDTH]; // bottom-left
 			c += _plasmaEffectPtr[(i + 0) + (j + 1) * PLASMA_WIDTH]; // bottom
@@ -235,7 +234,7 @@ void Menu::plasmaEffectRenderFrame() {
 			c = (c >> 3) | ((c & 0x0003) << 13);
 
 			if (!(c & 0x6500) &&
-			    (j >= (PLASMA_HEIGHT - 4) || c > 0)) {
+				(j >= (PLASMA_HEIGHT - 4) || c > 0)) {
 				c--; /*fade this pixel*/
 			}
 
@@ -277,8 +276,8 @@ void Menu::processPlasmaEffect(const Common::Rect &rect, int32 color) {
 }
 
 void Menu::drawRectBorders(const Common::Rect &rect, int32 colorLeftTop, int32 colorRightBottom) {
-	_engine->_interface->drawLine(rect.left, rect.top, rect.right, rect.top, colorLeftTop);           // top line
-	_engine->_interface->drawLine(rect.left, rect.top, rect.left, rect.bottom, colorLeftTop);         // left line
+	_engine->_interface->drawLine(rect.left, rect.top, rect.right, rect.top, colorLeftTop);               // top line
+	_engine->_interface->drawLine(rect.left, rect.top, rect.left, rect.bottom, colorLeftTop);             // left line
 	_engine->_interface->drawLine(rect.right, rect.top + 1, rect.right, rect.bottom, colorRightBottom);   // right line
 	_engine->_interface->drawLine(rect.left + 1, rect.bottom, rect.right, rect.bottom, colorRightBottom); // bottom line
 }
@@ -447,6 +446,28 @@ int16 Menu::drawButtons(MenuSettings *menuSettings, bool hover) {
 	return mouseActiveButton;
 }
 
+void Menu::menuDemo() {
+	// TODO: lba2 only show the credits only in the main menu and you could force it by pressing shift+c
+	// TODO: lba2 has a cd audio track (2) for the credits
+	_engine->_menuOptions->showCredits();
+	if (_engine->_movie->playMovie(FLA_DRAGON3)) {
+		if (!_engine->_screens->loadImageDelay(TwineImage(Resources::HQR_RESS_FILE, 15, 16), 3)) {
+			if (!_engine->_screens->loadImageDelay(TwineImage(Resources::HQR_RESS_FILE, 17, 18), 3)) {
+				if (!_engine->_screens->loadImageDelay(TwineImage(Resources::HQR_RESS_FILE, 19, 20), 3)) {
+					if (_engine->_movie->playMovie(FLA_BATEAU)) {
+						if (_engine->_cfgfile.Version == USA_VERSION) {
+							_engine->_screens->loadImageDelay(_engine->_resources->relentLogo(), 3);
+						} else {
+							_engine->_screens->loadImageDelay(_engine->_resources->lbaLogo(), 3);
+						}
+						_engine->_screens->adelineLogo();
+					}
+				}
+			}
+		}
+	}
+}
+
 int32 Menu::doGameMenu(MenuSettings *menuSettings) {
 	int16 currentButton = menuSettings->getActiveButton();
 	bool buttonsNeedRedraw = true;
@@ -660,29 +681,14 @@ int32 Menu::doGameMenu(MenuSettings *menuSettings) {
 			}
 			startMillis = loopMillis;
 		}
-		if (!_engine->_scene->isGameRunning() && loopMillis - startMillis > 11650) {
-			// TODO: lba2 only show the credits only in the main menu and you could force it by pressing shift+c
-			// TODO: lba2 has a cd audio track (2) for the credits
-			_engine->_menuOptions->showCredits();
-			if (_engine->_movie->playMovie(FLA_DRAGON3)) {
-				if (!_engine->_screens->loadImageDelay(TwineImage(Resources::HQR_RESS_FILE, 15, 16), 3)) {
-					if (!_engine->_screens->loadImageDelay(TwineImage(Resources::HQR_RESS_FILE, 17, 18), 3)) {
-						if (!_engine->_screens->loadImageDelay(TwineImage(Resources::HQR_RESS_FILE, 19, 20), 3)) {
-							if (_engine->_movie->playMovie(FLA_BATEAU)) {
-								if (_engine->_cfgfile.Version == USA_VERSION) {
-									_engine->_screens->loadImageDelay(_engine->_resources->relentLogo(), 3);
-								} else {
-									_engine->_screens->loadImageDelay(_engine->_resources->lbaLogo(), 3);
-								}
-								_engine->_screens->adelineLogo();
-							}
-						}
-					}
-				}
+		if (menuSettings == &_mainMenuState) {
+			uint32 idleTime = 60 * 3 + 53 * 1000;
+			if (_engine->isDemo()) {
+				idleTime = 60 * 1000;
+			}
+			if (loopMillis - startMillis > idleTime) {
+				return kDemoMenu;
 			}
-			_engine->_text->initDial(TextBankId::Options_and_menus);
-			startMillis = _engine->_system->getMillis();
-			_engine->_screens->loadMenuImage(false);
 		}
 	} while (!_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter));
 
@@ -802,7 +808,14 @@ int32 Menu::optionsMenu() {
 	_engine->restoreFrontBuffer();
 
 	_engine->_sound->stopSamples();
-	_engine->_music->playMusic(9); // LBA's Theme
+	if (_engine->isLBA1()) {
+		// LBA's Theme
+		if (_engine->isCDROM()) {
+			_engine->_music->playCdTrack(9);
+		} else {
+			_engine->_music->playMidiFile(9);
+		}
+	}
 
 	ScopedCursor scoped(_engine);
 	for (;;) {
@@ -942,8 +955,9 @@ EngineState Menu::run() {
 		optionsMenu();
 		break;
 	}
-	case kBackground: {
-		_engine->_screens->loadMenuImage();
+	case kDemoMenu: {
+		menuDemo();
+		_engine->_screens->loadMenuImage(false);
 		break;
 	}
 	case (int32)TextId::kQuit:
@@ -1351,7 +1365,7 @@ void Menu::processInventoryMenu() {
 	ProgressiveTextState textState = ProgressiveTextState::ContinueRunning;
 	bool updateItemText = true;
 
-	//ScopedCursor scopedCursor(_engine);
+	// ScopedCursor scopedCursor(_engine);
 	ScopedKeyMap scopedKeyMap(_engine, uiKeyMapId);
 	for (;;) {
 		FrameMarker frame(_engine, 66);
diff --git a/engines/twine/menu/menu.h b/engines/twine/menu/menu.h
index 4689127c220..b809399c7c6 100644
--- a/engines/twine/menu/menu.h
+++ b/engines/twine/menu/menu.h
@@ -30,6 +30,7 @@ namespace TwinE {
 #define MAX_BUTTONS 10
 #define PLASMA_WIDTH 320
 #define PLASMA_HEIGHT 50
+#define kDemoMenu 9999
 #define kQuitEngine 9998
 
 class BodyData;
@@ -226,6 +227,7 @@ public:
 	 * @param menuSettings menu settings array with the information to build the menu options
 	 * @return pressed menu button identification
 	 */
+	void menuDemo();
 	int32 doGameMenu(MenuSettings *menuSettings);
 
 	bool init();
diff --git a/engines/twine/menu/menuoptions.cpp b/engines/twine/menu/menuoptions.cpp
index 0a124f1cf03..9cda9713d17 100644
--- a/engines/twine/menu/menuoptions.cpp
+++ b/engines/twine/menu/menuoptions.cpp
@@ -105,10 +105,10 @@ void MenuOptions::showCredits() {
 	_engine->_scene->_currentSceneIdx = LBA1SceneId::Credits_List_Sequence;
 	_engine->_scene->_needChangeScene = LBA1SceneId::Credits_List_Sequence;
 
-	canShowCredits = true;
+	flagCredits = true;
 	_engine->gameEngineLoop();
 	_engine->_scene->stopRunningGame();
-	canShowCredits = false;
+	flagCredits = false;
 
 	_engine->_cfgfile.ShadowMode = tmpShadowMode;
 
diff --git a/engines/twine/menu/menuoptions.h b/engines/twine/menu/menuoptions.h
index 81c8d98d362..c7945f2de9e 100644
--- a/engines/twine/menu/menuoptions.h
+++ b/engines/twine/menu/menuoptions.h
@@ -54,7 +54,7 @@ public:
 
 	void showEndSequence();
 	void showCredits();
-	bool canShowCredits = false;
+	bool flagCredits = false;
 
 	char _saveGameName[32] {'\0'};
 
diff --git a/engines/twine/metaengine.cpp b/engines/twine/metaengine.cpp
index c1120a437e8..e56b17c1309 100644
--- a/engines/twine/metaengine.cpp
+++ b/engines/twine/metaengine.cpp
@@ -72,17 +72,6 @@ static const ADExtraGuiOptionsMap twineOptionsList[] = {
 			0
 		}
 	},
-	{
-		GAMEOPTION_AUDIO_CD,
-		{
-			_s("Enable audio CD"),
-			_s("Enable the original audio cd track"),
-			"usecd",
-			false,
-			0,
-			0
-		}
-	},
 	{
 		GAMEOPTION_SOUND,
 		{
diff --git a/engines/twine/scene/gamestate.cpp b/engines/twine/scene/gamestate.cpp
index 3442e8c522b..d9cddbdae21 100644
--- a/engines/twine/scene/gamestate.cpp
+++ b/engines/twine/scene/gamestate.cpp
@@ -120,7 +120,7 @@ void GameState::initEngineVars() {
 	_engine->_scene->_needChangeScene = LBA1SceneId::Citadel_Island_Prison;
 	_engine->_sceneLoopState = SceneLoopState::Continue;
 	_engine->_scene->_mecaPenguinIdx = -1;
-	_engine->_menuOptions->canShowCredits = false;
+	_engine->_menuOptions->flagCredits = false;
 
 	_inventoryNumLeafs = 0;
 	_inventoryNumLeafsBox = 2;
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index d3b2720db4d..ba58429b30b 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -867,7 +867,7 @@ bool TwinEEngine::runGameEngine() { // mainLoopInteration
 
 	_debug->processDebug();
 
-	if (_menuOptions->canShowCredits) {
+	if (_menuOptions->flagCredits) {
 		if (isLBA1()) {
 			if (isCDROM()) {
 				if (_music->getMusicCD() != 8) {


Commit: d6a0b5fb47a7e5e2eadad4e1388f46bf15397562
    https://github.com/scummvm/scummvm/commit/d6a0b5fb47a7e5e2eadad4e1388f46bf15397562
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-09-13T17:07:29+02:00

Commit Message:
TWINE: fixed mouse cursor config var handling

Changed paths:
    engines/twine/twine.cpp
    engines/twine/twine.h


diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index ba58429b30b..5fbcea04073 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -512,7 +512,7 @@ void TwinEEngine::initConfigurations() {
 	_cfgfile.Sound = ConfGetBoolOrDefault("sound", true);
 	_cfgfile.Fps = ConfGetIntOrDefault("fps", DEFAULT_FRAMES_PER_SECOND);
 	_cfgfile.Debug = ConfGetBoolOrDefault("debug", false);
-	_cfgfile.Mouse = ConfGetIntOrDefault("mouse", true);
+	_cfgfile.Mouse = ConfGetBoolOrDefault("mouse", true);
 
 	_cfgfile.UseAutoSaving = ConfGetBoolOrDefault("useautosaving", false);
 	_cfgfile.WallCollision = ConfGetBoolOrDefault("wallcollision", false);
diff --git a/engines/twine/twine.h b/engines/twine/twine.h
index db4db7dd456..26fa2cc311b 100644
--- a/engines/twine/twine.h
+++ b/engines/twine/twine.h
@@ -110,7 +110,7 @@ struct ConfigFile {
 	bool WallCollision = false;
 	/** Use original autosaving system or save when you want */
 	bool UseAutoSaving = false;
-	bool Mouse = false;
+	bool Mouse = true;
 
 	// these settings can be changed in-game - and must be persisted
 	/** Shadow mode type, value: all, character only, none */


Commit: faeef14bec7fc96ae36182d023658e298e2acf1e
    https://github.com/scummvm/scummvm/commit/faeef14bec7fc96ae36182d023658e298e2acf1e
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-09-13T17:07:29+02:00

Commit Message:
TWINE: improved mouse support for behaviour switch and inventory

Changed paths:
    engines/twine/input.cpp
    engines/twine/input.h
    engines/twine/menu/menu.cpp
    engines/twine/menu/menu.h
    engines/twine/twine.cpp


diff --git a/engines/twine/input.cpp b/engines/twine/input.cpp
index f6d8cd82ee6..15d28ea928a 100644
--- a/engines/twine/input.cpp
+++ b/engines/twine/input.cpp
@@ -45,7 +45,9 @@ ScopedKeyMap::~ScopedKeyMap() {
 	}
 }
 
-Input::Input(TwinEEngine *engine) : _engine(engine) {}
+Input::Input(TwinEEngine *engine) : _engine(engine) {
+	resetLastHoveredMousePosition();
+}
 
 bool Input::isActionActive(TwinEActionType actionType, bool onlyFirstTime) const {
 	if (onlyFirstTime) {
@@ -172,12 +174,23 @@ Common::Point Input::getMousePositions() const {
 	return g_system->getEventManager()->getMousePos();
 }
 
-bool Input::isMouseHovering(const Common::Rect &rect) const {
+bool Input::isMouseHovering(const Common::Rect &rect, bool onlyIfMoved) {
 	if (!_engine->_cfgfile.Mouse) {
 		return false;
 	}
 	const Common::Point &point = getMousePositions();
-	return rect.contains(point);
+	if (onlyIfMoved && _lastMousePos == point) {
+		return false;
+	}
+	if (rect.contains(point)) {
+		_lastMousePos = point;
+		return true;
+	}
+	return false;
+}
+
+void Input::resetLastHoveredMousePosition() {
+	_lastMousePos = Common::Point(-1, -1);
 }
 
 } // namespace TwinE
diff --git a/engines/twine/input.h b/engines/twine/input.h
index bd088ca43e7..3d7a536b8d3 100644
--- a/engines/twine/input.h
+++ b/engines/twine/input.h
@@ -116,6 +116,7 @@ private:
 	Common::String _currentKeyMap;
 
 	uint8 _actionStates[TwinEActionType::Max]{false};
+	Common::Point _lastMousePos;
 public:
 	Input(TwinEEngine *engine);
 
@@ -137,7 +138,8 @@ public:
 	 */
 	bool isActionActive(TwinEActionType actionType, bool onlyFirstTime = true) const;
 
-	bool isMouseHovering(const Common::Rect &rect) const;
+	void resetLastHoveredMousePosition();
+	bool isMouseHovering(const Common::Rect &rect, bool onlyIfMoved = true);
 
 	/**
 	 * @brief If the action is active, the internal state is reset and a following call of this method won't return
diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index 1cf116221b2..3b5560a36ee 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -473,8 +473,6 @@ int32 Menu::doGameMenu(MenuSettings *menuSettings) {
 	bool buttonsNeedRedraw = true;
 	const int32 numEntry = menuSettings->getButtonCount();
 	int32 maxButton = numEntry - 1;
-	Common::Point mousepos = _engine->_input->getMousePositions();
-	bool useMouse = true;
 
 	_engine->_input->enableKeyMap(uiKeyMapId);
 
@@ -490,18 +488,11 @@ int32 Menu::doGameMenu(MenuSettings *menuSettings) {
 		const uint32 loopMillis = _engine->_system->getMillis();
 		_engine->readKeys();
 
-		Common::Point newmousepos = _engine->_input->getMousePositions();
-		if (mousepos != newmousepos) {
-			useMouse = true;
-			mousepos = newmousepos;
-		}
-
 		if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
 			currentButton++;
 			if (currentButton == numEntry) { // if current button is the last, than next button is the first
 				currentButton = 0;
 			}
-			useMouse = false;
 			buttonsNeedRedraw = true;
 			startMillis = loopMillis;
 		} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIUp)) {
@@ -509,7 +500,6 @@ int32 Menu::doGameMenu(MenuSettings *menuSettings) {
 			if (currentButton < 0) { // if current button is the first, than previous button is the last
 				currentButton = maxButton;
 			}
-			useMouse = false;
 			buttonsNeedRedraw = true;
 			startMillis = loopMillis;
 		}
@@ -654,7 +644,7 @@ int32 Menu::doGameMenu(MenuSettings *menuSettings) {
 		if (buttonsNeedRedraw) {
 			// draw all buttons
 			const int16 mouseButtonHovered = drawButtons(menuSettings, false);
-			if (useMouse && mouseButtonHovered != -1) {
+			if (mouseButtonHovered != -1) {
 				currentButton = mouseButtonHovered;
 			}
 			menuSettings->setActiveButton(currentButton);
@@ -662,7 +652,7 @@ int32 Menu::doGameMenu(MenuSettings *menuSettings) {
 
 		// draw plasma effect for the current selected button
 		const int16 mouseButtonHovered = drawButtons(menuSettings, true);
-		if (useMouse && mouseButtonHovered != -1) {
+		if (mouseButtonHovered != -1) {
 			if (mouseButtonHovered != currentButton) {
 				buttonsNeedRedraw = true;
 			}
@@ -1105,6 +1095,9 @@ Common::Rect Menu::calcBehaviourRect(int32 left, int32 top, HeroBehaviourType be
 }
 
 bool Menu::isBehaviourHovered(int32 left, int32 top, HeroBehaviourType behaviour) const {
+	if (!_engine->_cfgfile.Mouse) {
+		return false;
+	}
 	const Common::Rect &boxRect = calcBehaviourRect(left, top, behaviour);
 	return _engine->_input->isMouseHovering(boxRect);
 }
@@ -1235,9 +1228,7 @@ void Menu::processBehaviourMenu(bool behaviourMenu) {
 
 		int32 tmpTime = _engine->timerRef;
 
-#if 0
 		ScopedCursor scopedCursor(_engine);
-#endif
 		ScopedKeyMap scopedKeyMap(_engine, uiKeyMapId);
 		while (_engine->_input->isActionActive(TwinEActionType::BehaviourMenu) || _engine->_input->isQuickBehaviourActionActive()) {
 			FrameMarker frame(_engine, 50);
@@ -1246,17 +1237,15 @@ void Menu::processBehaviourMenu(bool behaviourMenu) {
 				break;
 			}
 
-#if 0
-			if (isBehaviourHovered(HeroBehaviourType::kNormal)) {
-				_engine->_actor->heroBehaviour = HeroBehaviourType::kNormal;
-			} else if (isBehaviourHovered(HeroBehaviourType::kAthletic)) {
-				_engine->_actor->heroBehaviour = HeroBehaviourType::kAthletic;
-			} else if (isBehaviourHovered(HeroBehaviourType::kAggressive)) {
-				_engine->_actor->heroBehaviour = HeroBehaviourType::kAggressive;
-			} else if (isBehaviourHovered(HeroBehaviourType::kDiscrete)) {
-				_engine->_actor->heroBehaviour = HeroBehaviourType::kDiscrete;
+			if (isBehaviourHovered(left, top, HeroBehaviourType::kNormal)) {
+				_engine->_actor->_heroBehaviour = HeroBehaviourType::kNormal;
+			} else if (isBehaviourHovered(left, top, HeroBehaviourType::kAthletic)) {
+				_engine->_actor->_heroBehaviour = HeroBehaviourType::kAthletic;
+			} else if (isBehaviourHovered(left, top, HeroBehaviourType::kAggressive)) {
+				_engine->_actor->_heroBehaviour = HeroBehaviourType::kAggressive;
+			} else if (isBehaviourHovered(left, top, HeroBehaviourType::kDiscrete)) {
+				_engine->_actor->_heroBehaviour = HeroBehaviourType::kDiscrete;
 			}
-#endif
 
 			int heroBehaviour = (int)_engine->_actor->_heroBehaviour;
 			if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
@@ -1298,7 +1287,7 @@ void Menu::processBehaviourMenu(bool behaviourMenu) {
 	_engine->_text->initSceneTextBank();
 }
 
-void Menu::drawItem(int32 left, int32 top, int32 item) {
+Common::Rect Menu::calcItemRect(int32 left, int32 top, int32 item, int32 *centerX, int32 *centerY) const {
 	const int32 itemWidth = 74;
 	const int32 itemHeight = 64;
 	const int32 itemPadding = 11;
@@ -1306,7 +1295,18 @@ void Menu::drawItem(int32 left, int32 top, int32 item) {
 	const int32 itemHeightHalf = itemHeight / 2;
 	const int32 itemX = (item / 4) * (itemWidth + itemPadding) + left + itemWidthHalf + itemPadding - 1;
 	const int32 itemY = (item % 4) * (itemHeight + itemPadding) + top + itemHeightHalf + itemPadding - 1;
-	const Common::Rect rect(itemX - itemWidthHalf, itemY - itemHeightHalf, itemX + itemWidthHalf, itemY + itemHeightHalf);
+	if (centerX) {
+		*centerX = itemX;
+	}
+	if (centerY) {
+		*centerY = itemY;
+	}
+	return Common::Rect(itemX - itemWidthHalf, itemY - itemHeightHalf, itemX + itemWidthHalf, itemY + itemHeightHalf);
+}
+
+void Menu::drawItem(int32 left, int32 top, int32 item) {
+	int32 itemX, itemY;
+	const Common::Rect rect = calcItemRect(left, top, item, &itemX, &itemY);
 	const int32 color = _inventorySelectedItem == item ? _inventorySelectedColor : COLOR_BLACK;
 
 	_engine->_interface->drawFilledRect(rect, color);
@@ -1330,7 +1330,6 @@ void Menu::drawInventoryItems(int32 left, int32 top) {
 	const Common::Rect rect(left, top, left + 605, top + 310);
 	_engine->_interface->drawTransparentBox(rect, 4);
 	drawRectBorders(rect);
-
 	for (int32 item = 0; item < NUM_INVENTORY_ITEMS; item++) {
 		drawItem(left, top, item);
 	}
@@ -1365,7 +1364,7 @@ void Menu::processInventoryMenu() {
 	ProgressiveTextState textState = ProgressiveTextState::ContinueRunning;
 	bool updateItemText = true;
 
-	// ScopedCursor scopedCursor(_engine);
+	ScopedCursor scopedCursor(_engine);
 	ScopedKeyMap scopedKeyMap(_engine, uiKeyMapId);
 	for (;;) {
 		FrameMarker frame(_engine, 66);
@@ -1376,6 +1375,16 @@ void Menu::processInventoryMenu() {
 			break;
 		}
 
+		for (int32 item = 0; item < NUM_INVENTORY_ITEMS; item++) {
+			const Common::Rect &rect = calcItemRect(left, top, item);
+			if (_engine->_input->isMouseHovering(rect)) {
+				_inventorySelectedItem = item;
+				drawItem(left, top, prevSelectedItem);
+				updateItemText = true;
+				break;
+			}
+		}
+
 		const bool cursorDown = _engine->_input->toggleActionIfActive(TwinEActionType::UIDown);
 		const bool cursorUp = _engine->_input->toggleActionIfActive(TwinEActionType::UIUp);
 		const bool cursorLeft = _engine->_input->toggleActionIfActive(TwinEActionType::UILeft);
diff --git a/engines/twine/menu/menu.h b/engines/twine/menu/menu.h
index b809399c7c6..c7cf2cc4403 100644
--- a/engines/twine/menu/menu.h
+++ b/engines/twine/menu/menu.h
@@ -193,6 +193,7 @@ private:
 	void drawInventoryItems(int32 left, int32 top);
 	void prepareAndDrawBehaviour(int32 left, int32 top, int32 angle, HeroBehaviourType behaviour); // DrawComportement
 	void drawBehaviourMenu(int32 left, int32 top, int32 angle); // DrawMenuComportement
+	Common::Rect calcItemRect(int32 left, int32 top, int32 item, int32 *centerX = nullptr, int32 *centerY = nullptr) const;
 	void drawItem(int32 left, int32 top, int32 item);
 
 	void drawSpriteAndString(int32 left, int32 top, const SpriteData &spriteData, const Common::String &str, int32 color = COLOR_GOLD);
diff --git a/engines/twine/twine.cpp b/engines/twine/twine.cpp
index 5fbcea04073..e4c12f999ce 100644
--- a/engines/twine/twine.cpp
+++ b/engines/twine/twine.cpp
@@ -92,6 +92,7 @@ ScopedCursor::ScopedCursor(TwinEEngine *engine) : _engine(engine) {
 
 ScopedCursor::~ScopedCursor() {
 	_engine->popMouseCursorVisible();
+	_engine->_input->resetLastHoveredMousePosition();
 }
 
 FrameMarker::FrameMarker(TwinEEngine *engine, uint32 fps) : _engine(engine), _fps(fps) {


Commit: 2f10fb20f8c02f311a5e919b887164c7097e5ac0
    https://github.com/scummvm/scummvm/commit/2f10fb20f8c02f311a5e919b887164c7097e5ac0
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-09-13T17:07:29+02:00

Commit Message:
TWINE: renamed methods to match original source

Changed paths:
    engines/twine/menu/menu.cpp
    engines/twine/menu/menu.h
    engines/twine/text.cpp


diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index 3b5560a36ee..8576d4ba9f9 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -1304,7 +1304,7 @@ Common::Rect Menu::calcItemRect(int32 left, int32 top, int32 item, int32 *center
 	return Common::Rect(itemX - itemWidthHalf, itemY - itemHeightHalf, itemX + itemWidthHalf, itemY + itemHeightHalf);
 }
 
-void Menu::drawItem(int32 left, int32 top, int32 item) {
+void Menu::drawOneInventory(int32 left, int32 top, int32 item) {
 	int32 itemX, itemY;
 	const Common::Rect rect = calcItemRect(left, top, item, &itemX, &itemY);
 	const int32 color = _inventorySelectedItem == item ? _inventorySelectedColor : COLOR_BLACK;
@@ -1326,12 +1326,12 @@ void Menu::drawItem(int32 left, int32 top, int32 item) {
 	drawRectBorders(rect);
 }
 
-void Menu::drawInventoryItems(int32 left, int32 top) {
+void Menu::drawListInventory(int32 left, int32 top) {
 	const Common::Rect rect(left, top, left + 605, top + 310);
 	_engine->_interface->drawTransparentBox(rect, 4);
 	drawRectBorders(rect);
 	for (int32 item = 0; item < NUM_INVENTORY_ITEMS; item++) {
-		drawItem(left, top, item);
+		drawOneInventory(left, top, item);
 	}
 	_engine->_interface->unsetClip();
 }
@@ -1354,7 +1354,7 @@ void Menu::processInventoryMenu() {
 
 	const int32 left = _engine->width() / 2 - 303;
 	const int32 top = _engine->height() / 2 - 210;
-	drawInventoryItems(left, top);
+	drawListInventory(left, top);
 
 	_engine->_text->initDial(TextBankId::Inventory_Intro_and_Holomap);
 
@@ -1379,7 +1379,7 @@ void Menu::processInventoryMenu() {
 			const Common::Rect &rect = calcItemRect(left, top, item);
 			if (_engine->_input->isMouseHovering(rect)) {
 				_inventorySelectedItem = item;
-				drawItem(left, top, prevSelectedItem);
+				drawOneInventory(left, top, prevSelectedItem);
 				updateItemText = true;
 				break;
 			}
@@ -1395,28 +1395,28 @@ void Menu::processInventoryMenu() {
 			if (_inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
 				_inventorySelectedItem = 0;
 			}
-			drawItem(left, top, prevSelectedItem);
+			drawOneInventory(left, top, prevSelectedItem);
 			updateItemText = true;
 		} else if (cursorUp) {
 			_inventorySelectedItem--;
 			if (_inventorySelectedItem < 0) {
 				_inventorySelectedItem = NUM_INVENTORY_ITEMS - 1;
 			}
-			drawItem(left, top, prevSelectedItem);
+			drawOneInventory(left, top, prevSelectedItem);
 			updateItemText = true;
 		} else if (cursorLeft) {
 			_inventorySelectedItem -= 4;
 			if (_inventorySelectedItem < 0) {
 				_inventorySelectedItem += NUM_INVENTORY_ITEMS;
 			}
-			drawItem(left, top, prevSelectedItem);
+			drawOneInventory(left, top, prevSelectedItem);
 			updateItemText = true;
 		} else if (cursorRight) {
 			_inventorySelectedItem += 4;
 			if (_inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
 				_inventorySelectedItem -= NUM_INVENTORY_ITEMS;
 			}
-			drawItem(left, top, prevSelectedItem);
+			drawOneInventory(left, top, prevSelectedItem);
 			updateItemText = true;
 		}
 
@@ -1448,12 +1448,12 @@ void Menu::processInventoryMenu() {
 			}
 		}
 
-		drawItem(left, top, _inventorySelectedItem);
+		drawOneInventory(left, top, _inventorySelectedItem);
 
 		if (_inventorySelectedItem < NUM_INVENTORY_ITEMS && _engine->_input->toggleActionIfActive(TwinEActionType::UIEnter) && _engine->_gameState->hasItem((InventoryItems)_inventorySelectedItem) && !_engine->_gameState->inventoryDisabled()) {
 			_engine->_loopInventoryItem = _inventorySelectedItem;
 			_inventorySelectedColor = COLOR_91;
-			drawItem(left, top, _inventorySelectedItem);
+			drawOneInventory(left, top, _inventorySelectedItem);
 			break;
 		}
 	}
diff --git a/engines/twine/menu/menu.h b/engines/twine/menu/menu.h
index c7cf2cc4403..de1e49fb5bb 100644
--- a/engines/twine/menu/menu.h
+++ b/engines/twine/menu/menu.h
@@ -190,11 +190,12 @@ private:
 	Common::Rect calcBehaviourRect(int32 left, int32 top, HeroBehaviourType behaviour) const;
 	bool isBehaviourHovered(int32 left, int32 top, HeroBehaviourType behaviour) const;
 	void drawBehaviour(int32 left, int32 top, HeroBehaviourType behaviour, int32 angle, bool cantDrawBox);
-	void drawInventoryItems(int32 left, int32 top);
+	void drawListInventory(int32 left, int32 top);
 	void prepareAndDrawBehaviour(int32 left, int32 top, int32 angle, HeroBehaviourType behaviour); // DrawComportement
 	void drawBehaviourMenu(int32 left, int32 top, int32 angle); // DrawMenuComportement
 	Common::Rect calcItemRect(int32 left, int32 top, int32 item, int32 *centerX = nullptr, int32 *centerY = nullptr) const;
-	void drawItem(int32 left, int32 top, int32 item);
+	// draw the 2d sprite of the item
+	void drawOneInventory(int32 left, int32 top, int32 item);
 
 	void drawSpriteAndString(int32 left, int32 top, const SpriteData &spriteData, const Common::String &str, int32 color = COLOR_GOLD);
 
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index d0f9df4e5ac..7ff7845d86c 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -350,12 +350,12 @@ void Text::initDialogueBox() {
 }
 
 // TODO: this blits a few pixels too much when switching an item in the inventory menu.
-void Text::initInventoryDialogueBox() {
+void Text::initInventoryDialogueBox() { // SecondInitDialWindow
 	_engine->blitWorkToFront(_dialTextBox);
 	_fadeInCharactersPos = 0;
 }
 
-void Text::initInventoryText(InventoryItems index) {
+void Text::initInventoryText(InventoryItems index) { // OpenDialNoWindow
 	// 100 if the offset for the inventory item descriptions
 	initText((TextId)(100 + (int)index));
 }


Commit: 78b15a7e89996b502f9250e3a1fc8127311d9c0a
    https://github.com/scummvm/scummvm/commit/78b15a7e89996b502f9250e3a1fc8127311d9c0a
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-09-13T17:07:29+02:00

Commit Message:
TWINE: LBA2: prepare body and anim parser for lba2

Changed paths:
    engines/twine/menu/menu.cpp
    engines/twine/parser/entity.cpp
    engines/twine/parser/entity.h
    engines/twine/scene/actor.cpp
    engines/twine/shared.h


diff --git a/engines/twine/menu/menu.cpp b/engines/twine/menu/menu.cpp
index 8576d4ba9f9..e043b9ca7df 100644
--- a/engines/twine/menu/menu.cpp
+++ b/engines/twine/menu/menu.cpp
@@ -249,6 +249,10 @@ void Menu::plasmaEffectRenderFrame() {
 }
 
 void Menu::processPlasmaEffect(const Common::Rect &rect, int32 color) {
+	if (_engine->isLBA2()) {
+		// TODO: effects are handled differently here.
+		return;
+	}
 	const int32 max_value = color + 15;
 
 	plasmaEffectRenderFrame();
diff --git a/engines/twine/parser/entity.cpp b/engines/twine/parser/entity.cpp
index d2eca34dcbd..5256b5eb62e 100644
--- a/engines/twine/parser/entity.cpp
+++ b/engines/twine/parser/entity.cpp
@@ -21,10 +21,11 @@
 
 #include "twine/parser/entity.h"
 #include "common/stream.h"
+#include "twine/shared.h"
 
 namespace TwinE {
 
-bool EntityData::loadBody(Common::SeekableReadStream &stream) {
+bool EntityData::loadBody(Common::SeekableReadStream &stream, bool lba1) {
 	EntityBody body;
 	body.index = stream.readByte();
 	const int64 pos = stream.pos();
@@ -47,9 +48,13 @@ bool EntityData::loadBody(Common::SeekableReadStream &stream) {
 	return !stream.err();
 }
 
-bool EntityData::loadAnim(Common::SeekableReadStream &stream) {
+bool EntityData::loadAnim(Common::SeekableReadStream &stream, bool lba1) {
 	EntityAnim anim;
-	anim.animation = (AnimationTypes)stream.readByte();
+	if (lba1) {
+		anim.animation = (AnimationTypes)stream.readByte();
+	} else {
+		anim.animation = (AnimationTypes)stream.readUint16LE();
+	}
 	const int64 pos = stream.pos();
 	uint8 size = stream.readByte();
 	anim.animIndex = stream.readSint16LE();
@@ -82,6 +87,11 @@ bool EntityData::loadAnim(Common::SeekableReadStream &stream) {
 			action.animFrame = stream.readByte();
 			action.sampleIndex = stream.readSint16LE();
 			action.repeat = stream.readSint16LE();
+			if (!lba1) {
+				action.decal = stream.readSint16LE();
+				action.sampleVolume = stream.readByte();
+				action.frequency = stream.readSint16LE();
+			}
 			break;
 		case ActionType::ACTION_THROW_SEARCH:
 			action.animFrame = stream.readByte();
@@ -99,6 +109,7 @@ bool EntityData::loadAnim(Common::SeekableReadStream &stream) {
 			action.xAngle = ToAngle(stream.readSint16LE());
 			action.yAngle = ToAngle(stream.readSint16LE());
 			action.xRotPoint = stream.readSint16LE();
+			// TODO: does lba2 need a scaling here for xRotPoint?
 			action.extraAngle = ToAngle(stream.readByte());
 			action.strength = stream.readByte();
 			break;
@@ -109,8 +120,12 @@ bool EntityData::loadAnim(Common::SeekableReadStream &stream) {
 			break;
 		case ActionType::ACTION_SAMPLE_STOP:
 			action.animFrame = stream.readByte();
-			action.sampleIndex = stream.readByte();
-			stream.skip(1);
+			if (lba1) {
+				action.sampleIndex = stream.readByte();
+				stream.skip(1);
+			} else {
+				action.sampleIndex = stream.readUint16LE();
+			}
 			break;
 		case ActionType::ACTION_THROW_3D:
 		case ActionType::ACTION_THROW_3D_ALPHA:
@@ -148,6 +163,104 @@ bool EntityData::loadAnim(Common::SeekableReadStream &stream) {
 		default:
 			break;
 		}
+		if (!lba1) {
+			switch (action.type) {
+			case ActionType::ACTION_ZV:
+				action.animFrame = stream.readByte();
+				action.bbox.mins.x = stream.readSint16LE();
+				action.bbox.mins.y = stream.readSint16LE();
+				action.bbox.mins.z = stream.readSint16LE();
+				action.bbox.maxs.x = stream.readSint16LE();
+				action.bbox.maxs.y = stream.readSint16LE();
+				action.bbox.maxs.z = stream.readSint16LE();
+				break;
+			case ActionType::ACTION_SUPER_HIT:
+				action.animFrame = stream.readByte();
+				action.strength = stream.readByte();
+				action.superHitX = stream.readSint16LE();
+				action.superHitY = stream.readSint16LE();
+				action.superHitZ = stream.readSint16LE();
+				action.sizeSuperHit = stream.readSint16LE();
+				break;
+			case ActionType::ACTION_THROW_OBJ_3D:
+				action.animFrame = stream.readByte();
+				action.distanceX = stream.readSint16LE();
+				action.distanceY = stream.readSint16LE();
+				action.distanceZ = stream.readSint16LE();
+				action.spriteIndex = stream.readByte();
+				action.xAngle = ToAngle(stream.readSint16LE());
+				action.yAngle = ToAngle(stream.readSint16LE());
+				action.xRotPoint = stream.readSint16LE();
+				action.extraAngle = ToAngle(stream.readByte());
+				action.strength = stream.readByte();
+				break;
+			case ActionType::ACTION_NEW_SAMPLE:
+				action.animFrame = stream.readByte();
+				action.sampleIndex = stream.readSint16LE();
+				action.frequency = stream.readSint16LE();
+				break;
+			case ActionType::ACTION_THROW_DART:
+				action.animFrame = stream.readByte();
+				action.distanceY = stream.readSint16LE();
+				action.xAngle = ToAngle(stream.readSint16LE());
+				action.speed = stream.readSint16LE();
+				action.weight = stream.readSByte();
+				break;
+			case ActionType::ACTION_SHIELD:
+				action.animFrame = stream.readByte();
+				action.lastAnimFrame = stream.readByte();
+				break;
+			case ActionType::ACTION_FLOW_3D:
+			case ActionType::ACTION_THROW_3D_CONQUE:
+				action.animFrame = stream.readByte();
+				action.xAngle = ToAngle(stream.readSint16LE());
+				action.yHeight = stream.readSint16LE();
+				action.yAngle = ToAngle(stream.readSint16LE());
+				action.spriteIndex = stream.readByte();
+				break;
+			case ActionType::ACTION_IMPACT:
+			case ActionType::ACTION_RENVOYABLE:
+				action.animFrame = stream.readByte();
+				action.strength = stream.readSint16LE();
+				break;
+			case ActionType::ACTION_SCALE:
+				action.animFrame = stream.readByte();
+				action.scale = stream.readSint32LE();
+				break;
+			case ActionType::ACTION_IMPACT_3D:
+				action.animFrame = stream.readByte();
+				action.xAngle = ToAngle(stream.readSint16LE());
+				action.yHeight = stream.readSint16LE();
+				action.yAngle = ToAngle(stream.readSint16LE());
+				action.spriteIndex = stream.readSint16LE();
+				break;
+			case ActionType::ACTION_THROW_MAGIC_EXTRA:
+				action.animFrame = stream.readByte();
+				action.pointIndex = stream.readSint16LE();
+				action.spriteIndex = stream.readByte();
+				action.xAngle = ToAngle(stream.readSint16LE());
+				action.speed = stream.readSint16LE();
+				action.weight = stream.readSByte();
+				break;
+			case ActionType::ACTION_ZV_ANIMIT:
+			case ActionType::ACTION_RENVOIE:
+			case ActionType::ACTION_TRANSPARENT:
+			case ActionType::ACTION_SAMPLE_MAGIC:
+			case ActionType::ACTION_LEFT_JUMP:
+			case ActionType::ACTION_RIGHT_JUMP:
+			case ActionType::ACTION_THROW_FOUDRE:
+				action.animFrame = stream.readByte();
+				/* empty */
+				break;
+			case ActionType::ACTION_PATH:
+			case ActionType::ACTION_FLOW:
+			default:
+				break;
+			}
+		}
+		if (action.type > ActionType::ACTION_THROW_FOUDRE) {
+			error("Unknown action type %d", (int)action.type);
+		}
 		anim._actions.push_back(action);
 	}
 	_animations.push_back(anim);
@@ -165,11 +278,11 @@ bool EntityData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
 	do {
 		const uint8 opcode = stream.readByte();
 		if (opcode == 1) {
-			if (!loadBody(stream)) {
+			if (!loadBody(stream, lba1)) {
 				return false;
 			}
 		} else if (opcode == 3) {
-			if (!loadAnim(stream)) {
+			if (!loadAnim(stream, lba1)) {
 				return false;
 			}
 		} else if (opcode == 0xFF) {
@@ -180,8 +293,8 @@ bool EntityData::loadFromStream(Common::SeekableReadStream &stream, bool lba1) {
 	return true;
 }
 
-const Common::Array<EntityAnim::Action>* EntityData::getActions(AnimationTypes animation) const {
-	for (const EntityAnim& anim : _animations) {
+const Common::Array<EntityAnim::Action> *EntityData::getActions(AnimationTypes animation) const {
+	for (const EntityAnim &anim : _animations) {
 		if (anim.animation == animation) {
 			if (anim._actions.empty()) {
 				return nullptr;
@@ -192,8 +305,8 @@ const Common::Array<EntityAnim::Action>* EntityData::getActions(AnimationTypes a
 	return nullptr;
 }
 
-const EntityBody* EntityData::getBody(const int index) const {
-	for (const EntityBody& body : _bodies) {
+const EntityBody *EntityData::getBody(const int index) const {
+	for (const EntityBody &body : _bodies) {
 		if (body.index == index) {
 			return &body;
 		}
@@ -202,7 +315,7 @@ const EntityBody* EntityData::getBody(const int index) const {
 }
 
 int32 EntityData::getAnimIndex(AnimationTypes animation) const {
-	for (const EntityAnim& anim : _animations) {
+	for (const EntityAnim &anim : _animations) {
 		if (anim.animation == animation) {
 			return anim.animIndex;
 		}
diff --git a/engines/twine/parser/entity.h b/engines/twine/parser/entity.h
index 9fbc91822f0..7fe923328ee 100644
--- a/engines/twine/parser/entity.h
+++ b/engines/twine/parser/entity.h
@@ -43,6 +43,12 @@ struct EntityAnim {
 	struct Action {
 		ActionType type = ActionType::ACTION_NOP;
 		uint8 animFrame = 0;
+		uint8 lastAnimFrame = 0;
+		int8 weight = 0;
+		byte sampleVolume = 0;
+		int16 pointIndex = 0;
+		int16 spriteIndex = 0;
+		uint8 targetActor = 0;
 		int16 sampleIndex = 0;
 		int16 frequency = 0;
 		int16 xAngle = 0;
@@ -55,9 +61,15 @@ struct EntityAnim {
 		int16 distanceY = 0;
 		int16 distanceZ = 0;
 		int16 yHeight = 0;
-		uint8 spriteIndex = 0;
-		uint8 targetActor = 0;
 		int16 repeat = 0;
+		int16 speed = 0;
+		int16 superHitX = 0;
+		int16 superHitY = 0;
+		int16 superHitZ = 0;
+		int16 sizeSuperHit = 0;
+		int16 decal = 0;
+		int32 scale = 0;
+		BoundingBox bbox;
 	};
 
 	Common::Array<Action> _actions;
@@ -71,8 +83,8 @@ private:
 	Common::Array<EntityBody> _bodies;
 	Common::Array<EntityAnim> _animations;
 
-	bool loadBody(Common::SeekableReadStream &stream);
-	bool loadAnim(Common::SeekableReadStream &stream);
+	bool loadBody(Common::SeekableReadStream &stream, bool lba1);
+	bool loadAnim(Common::SeekableReadStream &stream, bool lba1);
 
 protected:
 	void reset() override;
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index ccd057a156c..be51590936b 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -70,7 +70,11 @@ void Actor::restartHeroScene() {
 }
 
 void Actor::loadBehaviourEntity(ActorStruct *actor, EntityData &entityData, int16 &bodyAnimIndex, int32 index) {
-	if (!entityData.loadFromHQR(Resources::HQR_FILE3D_FILE, index, _engine->isLBA1())) {
+	TwineResource modelRes(Resources::HQR_FILE3D_FILE, index);
+	if (_engine->isLBA2()) {
+		modelRes = TwineResource(Resources::HQR_RESS_FILE, index + 44);
+	}
+	if (!entityData.loadFromHQR(modelRes, _engine->isLBA1())) {
 		error("Failed to load actor 3d data for index: %i", index);
 	}
 
@@ -503,7 +507,11 @@ void ActorStruct::loadModel(int32 modelIndex, bool lba1) {
 	_body = modelIndex;
 	if (!_staticFlags.bSprite3D) {
 		debug(1, "Init actor with model %i", modelIndex);
-		if (!_entityData.loadFromHQR(Resources::HQR_FILE3D_FILE, modelIndex, lba1)) {
+		TwineResource modelRes(Resources::HQR_FILE3D_FILE, modelIndex);
+		if (!lba1) {
+			modelRes = TwineResource(Resources::HQR_RESS_FILE, modelIndex + 44);
+		}
+		if (!_entityData.loadFromHQR(modelRes, lba1)) {
 			error("Failed to load entity data for index %i", modelIndex);
 		}
 		_entityDataPtr = &_entityData;
diff --git a/engines/twine/shared.h b/engines/twine/shared.h
index a0a303a2ced..38508542da8 100644
--- a/engines/twine/shared.h
+++ b/engines/twine/shared.h
@@ -678,7 +678,7 @@ enum InventoryItems {
 
 struct TwineResource {
 	const char *hqr;
-	const int32 index;
+	int32 index;
 
 	constexpr TwineResource(const char *_hqr, int32 _index) : hqr(_hqr), index(_index) {
 	}


Commit: b231384f9bb5d3b6932f14d9f8b46829bb2eb799
    https://github.com/scummvm/scummvm/commit/b231384f9bb5d3b6932f14d9f8b46829bb2eb799
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2024-09-13T17:07:29+02:00

Commit Message:
TWINE: LBA2: the scene index needs a small offset

moved entity data parsing into resource class

Changed paths:
    engines/twine/parser/entity.cpp
    engines/twine/resources/resources.cpp
    engines/twine/resources/resources.h
    engines/twine/scene/actor.cpp
    engines/twine/scene/actor.h
    engines/twine/scene/scene.cpp
    engines/twine/scene/scene.h
    engines/twine/text.cpp


diff --git a/engines/twine/parser/entity.cpp b/engines/twine/parser/entity.cpp
index 5256b5eb62e..79f41f2002e 100644
--- a/engines/twine/parser/entity.cpp
+++ b/engines/twine/parser/entity.cpp
@@ -197,6 +197,8 @@ bool EntityData::loadAnim(Common::SeekableReadStream &stream, bool lba1) {
 			case ActionType::ACTION_NEW_SAMPLE:
 				action.animFrame = stream.readByte();
 				action.sampleIndex = stream.readSint16LE();
+				action.decal = stream.readSint16LE();
+				action.sampleVolume = stream.readByte();
 				action.frequency = stream.readSint16LE();
 				break;
 			case ActionType::ACTION_THROW_DART:
diff --git a/engines/twine/resources/resources.cpp b/engines/twine/resources/resources.cpp
index 660f1b3d5a4..7e81b2d64ac 100644
--- a/engines/twine/resources/resources.cpp
+++ b/engines/twine/resources/resources.cpp
@@ -66,6 +66,25 @@ void Resources::preloadAnim3DS() {
 	_anim3DSData.loadFromHQR(Resources::HQR_ANIM3DS_FILE, index, _engine->isLBA1());
 }
 
+void Resources::loadEntityData(EntityData &entityData, int32 &index) {
+	if (_engine->isLBA1()) {
+		TwineResource modelRes(Resources::HQR_FILE3D_FILE, index);
+		if (!entityData.loadFromHQR(modelRes, _engine->isLBA1())) {
+			error("Failed to load actor 3d data for index: %i", index);
+		}
+	} else {
+		// TODO: don't allocate each time
+		TwineResource modelRes(Resources::HQR_RESS_FILE, 44);
+		uint8 *file3dBuf = nullptr;
+		const int32 holomapImageSize = HQR::getAllocEntry(&file3dBuf, modelRes);
+		if (!entityData.loadFromBuffer((uint8 *)(file3dBuf + *(((uint32 *)file3dBuf) + (index))), holomapImageSize, _engine->isLBA1())) {
+			delete file3dBuf;
+			error("Failed to load actor 3d data for index: %i", index);
+		}
+		delete file3dBuf;
+	}
+}
+
 const T_ANIM_3DS *Resources::getAnim(int index) const {
 	if (index < 0 || index >= (int)_anim3DSData.getAnims().size()) {
 		return nullptr;
diff --git a/engines/twine/resources/resources.h b/engines/twine/resources/resources.h
index 98575400024..1567ef08a52 100644
--- a/engines/twine/resources/resources.h
+++ b/engines/twine/resources/resources.h
@@ -196,6 +196,7 @@ public:
 	void initResources();
 
 	const Trajectory *getTrajectory(int index) const;
+	void loadEntityData(EntityData &entityData, int32 &index);
 
 	const TextEntry *getText(TextBankId textBankId, TextId index) const;
 	const T_ANIM_3DS *getAnim(int index) const;
diff --git a/engines/twine/scene/actor.cpp b/engines/twine/scene/actor.cpp
index be51590936b..f1fbe5a1497 100644
--- a/engines/twine/scene/actor.cpp
+++ b/engines/twine/scene/actor.cpp
@@ -70,14 +70,7 @@ void Actor::restartHeroScene() {
 }
 
 void Actor::loadBehaviourEntity(ActorStruct *actor, EntityData &entityData, int16 &bodyAnimIndex, int32 index) {
-	TwineResource modelRes(Resources::HQR_FILE3D_FILE, index);
-	if (_engine->isLBA2()) {
-		modelRes = TwineResource(Resources::HQR_RESS_FILE, index + 44);
-	}
-	if (!entityData.loadFromHQR(modelRes, _engine->isLBA1())) {
-		error("Failed to load actor 3d data for index: %i", index);
-	}
-
+	_engine->_resources->loadEntityData(entityData, index);
 	actor->_entityDataPtr = &entityData;
 	bodyAnimIndex = entityData.getAnimIndex(AnimationTypes::kStanding);
 	if (bodyAnimIndex == -1) {
@@ -503,23 +496,6 @@ void Actor::posObjectAroundAnother(uint8 numsrc, uint8 numtopos) {
 #endif
 }
 
-void ActorStruct::loadModel(int32 modelIndex, bool lba1) {
-	_body = modelIndex;
-	if (!_staticFlags.bSprite3D) {
-		debug(1, "Init actor with model %i", modelIndex);
-		TwineResource modelRes(Resources::HQR_FILE3D_FILE, modelIndex);
-		if (!lba1) {
-			modelRes = TwineResource(Resources::HQR_RESS_FILE, modelIndex + 44);
-		}
-		if (!_entityData.loadFromHQR(modelRes, lba1)) {
-			error("Failed to load entity data for index %i", modelIndex);
-		}
-		_entityDataPtr = &_entityData;
-	} else {
-		_entityDataPtr = nullptr;
-	}
-}
-
 int16 ActorMoveStruct::getRealValueFromTime(int32 time) {
 	if (timeValue) {
 		const int32 delta = time - memoTicks;
diff --git a/engines/twine/scene/actor.h b/engines/twine/scene/actor.h
index b25bd62db79..4c5610c43be 100644
--- a/engines/twine/scene/actor.h
+++ b/engines/twine/scene/actor.h
@@ -146,13 +146,12 @@ private:
 	bool _brickCausesDamage = false;
 	int32 _maxLife;
 
-	EntityData _entityData;
-
 public:
 	ActorStruct(int maxLife = 0) : _lifePoint(maxLife), _maxLife(maxLife) {}
 	StaticFlagsStruct _staticFlags; // Flags
 	DynamicFlagsStruct _workFlags;  // WorkFlags
 
+	EntityData _entityData;
 	inline ShapeType brickShape() const { return _col; }
 	inline void setCollision(ShapeType shapeType) {
 		_col = shapeType;
@@ -160,7 +159,6 @@ public:
 	}
 	inline void setBrickCausesDamage() { _brickCausesDamage = true; }
 	inline bool brickCausesDamage() { return _brickCausesDamage; }
-	void loadModel(int32 modelIndex, bool lba1);
 
 	void addLife(int32 val);
 
diff --git a/engines/twine/scene/scene.cpp b/engines/twine/scene/scene.cpp
index da24815b642..8e97158c254 100644
--- a/engines/twine/scene/scene.cpp
+++ b/engines/twine/scene/scene.cpp
@@ -179,6 +179,17 @@ bool Scene::loadSceneCubeXY(int numcube, int32 *cubex, int32 *cubey) {
 	return false;
 }
 
+void Scene::loadModel(ActorStruct &actor, int32 modelIndex, bool lba1) {
+	actor._body = modelIndex;
+	if (!actor._staticFlags.bSprite3D) {
+		debug(1, "Init actor with model %i", modelIndex);
+		_engine->_resources->loadEntityData(actor._entityData, modelIndex);
+		actor._entityDataPtr = &actor._entityData;
+	} else {
+		actor._entityDataPtr = nullptr;
+	}
+}
+
 bool Scene::loadSceneLBA2() {
 	Common::MemoryReadStream stream(_currentScene, _currentSceneSize);
 	_island = stream.readByte();
@@ -230,7 +241,7 @@ bool Scene::loadSceneLBA2() {
 		ActorStruct *act = &_sceneActors[a];
 		setActorStaticFlags(act, stream.readUint32LE());
 
-		act->loadModel((int16)stream.readUint16LE(), false);
+		loadModel(*act, (int16)stream.readUint16LE(), false);
 
 		act->_genBody = (BodyType)stream.readSint16LE();
 		act->_genAnim = (AnimationTypes)stream.readByte();
@@ -362,7 +373,7 @@ bool Scene::loadSceneLBA1() {
 		ActorStruct *act = &_sceneActors[a];
 		setActorStaticFlags(act, stream.readUint16LE());
 
-		act->loadModel(stream.readUint16LE(), true);
+		loadModel(*act, stream.readUint16LE(), true);
 
 		act->_genBody = (BodyType)stream.readByte();
 		act->_genAnim = (AnimationTypes)stream.readByte();
@@ -467,6 +478,9 @@ bool Scene::loadSceneLBA1() {
 
 bool Scene::initScene(int32 index) {
 	// load scene from file
+	if (_engine->isLBA2()) {
+		index++;
+	}
 	_currentSceneSize = HQR::getAllocEntry(&_currentScene, Resources::HQR_SCENE_FILE, index);
 	if (_currentSceneSize == 0) {
 		return false;
diff --git a/engines/twine/scene/scene.h b/engines/twine/scene/scene.h
index 7789280017f..db191260faf 100644
--- a/engines/twine/scene/scene.h
+++ b/engines/twine/scene/scene.h
@@ -117,6 +117,8 @@ class Scene {
 private:
 	TwinEEngine *_engine;
 
+	void loadModel(ActorStruct &actor, int32 modelIndex, bool lba1);
+
 	/** Process zone extra bonus */
 	void processZoneExtraBonus(ZoneStruct *zone);
 	void setActorStaticFlags(ActorStruct *act, uint32 staticFlags);
diff --git a/engines/twine/text.cpp b/engines/twine/text.cpp
index 7ff7845d86c..caca662db53 100644
--- a/engines/twine/text.cpp
+++ b/engines/twine/text.cpp
@@ -173,7 +173,8 @@ void Text::initDial(TextBankId bankIdx) {
 }
 
 void Text::initSceneTextBank() {
-	initDial((TextBankId)((int)_engine->_scene->_sceneTextBank + (int)TextBankId::Citadel_Island));
+	const int textBankId = (int)_engine->_scene->_sceneTextBank;
+	initDial((TextBankId)(textBankId + (int)TextBankId::Citadel_Island));
 }
 
 void Text::drawCharacter(int32 x, int32 y, uint16 character) {




More information about the Scummvm-git-logs mailing list