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

NMIError 60350957+NMIError at users.noreply.github.com
Tue Dec 8 16:48:12 UTC 2020


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

Summary:
419453ce00 LURE: Fix introduction animation
447d38f6a7 LURE: Fix Skorl catch animation
432529b2bb LURE: Fix chute animation
6454b69026 LURE: Fix game over screen
17f4e65aff LURE: Improve MT-32 fade-out in intro
5b01d5f09e LURE: Barrel animation fixes
fa4948eaa4 LURE: Fix endgame animation


Commit: 419453ce00ad62df76add978a3f319474cfa0655
    https://github.com/scummvm/scummvm/commit/419453ce00ad62df76add978a3f319474cfa0655
Author: NMIError (crampen at gmail.com)
Date: 2020-12-08T17:00:28+01:00

Commit Message:
LURE: Fix introduction animation

This fixes several issues with the introduction animation:
- The timing of the various parts of the introduction did not match the timing
of the original interpreter. The music did not properly match the images and
the last section was completely missing. I've adjusted the timing to beter
match the original interpreter.
- The VGA palette of the first text screens was broken and would display them
as completely white. I've added a patch to add the colors of the palette of the
following text screens.
- The animation of the soldiers approaching each other would fade out on the
original interpreter. I've added this.
- The images of the battle sequence would fade out on the EGA version. This
does not match the original interpreter and has been removed.

Changed paths:
    engines/lure/intro.cpp
    engines/lure/intro.h
    engines/lure/palette.cpp


diff --git a/engines/lure/intro.cpp b/engines/lure/intro.cpp
index 5b3d58acda..eb1b466390 100644
--- a/engines/lure/intro.cpp
+++ b/engines/lure/intro.cpp
@@ -29,21 +29,38 @@
 namespace Lure {
 
 struct AnimRecord {
+	// The resource ID of the animation
 	uint16 resourceId;
+	// The index of the palette to use
 	uint8 paletteIndex;
+	// The time that should pass before starting the animation
 	uint16 initialPause;
+	// The time that should pass at the last screen of the animation
 	uint16 endingPause;
+	// The number of the sound that should play during the animation
 	uint8 soundNumber;
+	// True if the sound should fade out before the transition
+	bool fadeOutSound;
+	// The time that should pass on the last animation screen before the
+	// next sound is played
+	uint16 soundTransitionPause;
+	// The number of the sound that should be played on the last screen
+	// (0xFF for none)
+	uint8 soundNumber2;
 };
 
 static const uint16 start_screens[] = {0x18, 0x1A, 0x1E, 0x1C, 0};
 static const AnimRecord anim_screens[] = {
-	{0x40, 0, 0x35A, 0x2C8, 0x00},		// The kingdom was at peace
-	{0x42, 1, 0, 0x5FA, 0x01},			// Cliff overhang
-	{0x44, 2, 0, 0, 0x02},				// Siluette in moonlight
-	{0x24, 3, 0, 0x328 + 0x24, 0xff},	// Exposition of reaching town
-	{0x46, 3, 0, 0, 0x03},				// Skorl approaches
-	{0, 0, 0, 0, 0xff}};
+	// Note that the ending pause of the first anim is about 8 seconds in the
+	// original interpreter vs about 14 seconds here. 8 seconds is quite short
+	// to read the screen, so I kept it at 14. Conveniently, the first music
+	// track is much longer than what was actually used in the game.
+	{0x40, 0, 0x314, 0x2BE, 0x00, true, 0x1F4, 0x01},		// The kingdom was at peace
+	{0x42, 1, 0, 0x5FA, 0x01, false, 0, 0xFF},				// Cliff overhang
+	{0x44, 2, 0, 0, 0x02, false, 0, 0xFF},					// Siluette in moonlight
+	{0x24, 3, 0, 0x62C + 0x24, 0xFF, false, 0x328, 0x03},	// Exposition of reaching town
+	{0x46, 3, 0, 0, 0x03, false, 0, 0xFF},					// Skorl approaches
+	{0, 0, 0, 0, 0xFF, false, 0, 0xFF}};
 
 // showScreen
 // Shows a screen by loading it from the given resource, and then fading it in
@@ -122,18 +139,11 @@ bool Introduction::show() {
 	// Animated screens
 
 	AnimationSequence *anim;
-	uint8 currentSound = 0xff;
+	_currentSound = 0xFF;
 	const AnimRecord *curr_anim = anim_screens;
 	for (; curr_anim->resourceId; ++curr_anim) {
 		// Handle sound selection
-		if (curr_anim->soundNumber != 0xff) {
-			if (currentSound != 0xff)
-				// Stop the previous sound
-				Sound.musicInterface_KillAll();
-
-			currentSound = curr_anim->soundNumber;
-			Sound.musicInterface_Play(currentSound, 0, true);
-		}
+		playMusic(curr_anim->soundNumber, false);
 
 		bool fadeIn = curr_anim == anim_screens;
 		anim = new AnimationSequence(curr_anim->resourceId,
@@ -151,7 +161,14 @@ bool Introduction::show() {
 		switch (anim->show()) {
 		case ABORT_NONE:
 			if (curr_anim->endingPause != 0) {
-				result = interruptableDelay(curr_anim->endingPause * 1000 / 50);
+				if (curr_anim->soundTransitionPause != 0)
+					// Wait before transitioning to the next track
+					result = interruptableDelay(curr_anim->soundTransitionPause * 1000 / 50);
+				if (!result) {
+					playMusic(curr_anim->soundNumber2, curr_anim->fadeOutSound);
+					// Wait remaining time before the next animation
+					result = interruptableDelay((curr_anim->endingPause - curr_anim->soundTransitionPause) * 1000 / 50);
+				}
 			}
 			break;
 
@@ -171,13 +188,21 @@ bool Introduction::show() {
 		}
 	}
 
+	// Fade out last cutscene screen
+	if (!isEGA)
+		screen.paletteFadeOut();
+
 	// Show battle pictures one frame at a time
 
 	result = false;
 	anim = new AnimationSequence(0x48, isEGA ? EgaPalette : coll.getPalette(4), false);
 	do {
 		result = interruptableDelay(2000);
-		screen.paletteFadeOut();
+		if (isEGA) {
+			screen.empty();
+		} else {
+			screen.paletteFadeOut();
+		}
 		if (!result) result = interruptableDelay(500);
 		if (result) break;
 	} while (anim->step());
@@ -186,12 +211,12 @@ bool Introduction::show() {
 	if (!result) {
 		// Show final introduction animation
 		if (!isEGA)
-			showScreen(0x22, 0x21, 10000);
+			showScreen(0x22, 0x21, 33300);
 		else {
 			Palette finalPalette(0x21);
 			anim = new AnimationSequence(0x22, finalPalette, false);
 			delete anim;
-			interruptableDelay(10000);
+			interruptableDelay(34000);
 		}
 	}
 
@@ -199,4 +224,17 @@ bool Introduction::show() {
 	return false;
 }
 
+void Introduction::playMusic(uint8 soundNumber, bool fadeOut) {
+	if (soundNumber != 0xFF && _currentSound != soundNumber) {
+		// Stop the previous sound
+		if (fadeOut) {
+			// TODO Implement fade-out
+		}
+		Sound.musicInterface_KillAll();
+
+		_currentSound = soundNumber;
+		Sound.musicInterface_Play(_currentSound, 0, true);
+	}
+}
+
 } // End of namespace Lure
diff --git a/engines/lure/intro.h b/engines/lure/intro.h
index 147ebff359..ebac8f653a 100644
--- a/engines/lure/intro.h
+++ b/engines/lure/intro.h
@@ -28,11 +28,16 @@
 namespace Lure {
 
 class Introduction {
+public:
+	Introduction() : _currentSound(0xFF) { }
+
+	bool show();
 private:
+	uint8 _currentSound;
+
 	bool showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize, bool fadeOut = true);
 	bool interruptableDelay(uint32 milliseconds);
-public:
-	bool show();
+	void playMusic(uint8 soundNumber, bool fadeOut);
 };
 
 } // End of namespace Lure
diff --git a/engines/lure/palette.cpp b/engines/lure/palette.cpp
index 30a5752366..0e093d4bfc 100644
--- a/engines/lure/palette.cpp
+++ b/engines/lure/palette.cpp
@@ -195,6 +195,18 @@ PaletteCollection::PaletteCollection(uint16 resourceId) {
 		_palettes = (Palette **) Memory::alloc(_numPalettes * sizeof(Palette *));
 		for (uint8 paletteCtr = 0; paletteCtr < _numPalettes; ++paletteCtr, data += palSize)
 			_palettes[paletteCtr] = new Palette(SUB_PALETTE_SIZE, data, RGB64);
+
+		// WORKAROUND Intro animation 1 VGA palette has bad entries,
+		// causing the text to be all white instead of shades of grey.
+		// Updating it here with the color values of the other intro
+		// text screens.
+		if (resourceId == 0x32 && _palettes[0]->getEntry(0x22) == 0x00FFFFFF) {
+			_palettes[0]->setEntry(0x22, 0x00E3E3E3); // 38 38 38
+			_palettes[0]->setEntry(0x24, 0x00C3C3C3); // 30 30 30
+			_palettes[0]->setEntry(0x26, 0x00929292); // 24 24 24
+			_palettes[0]->setEntry(0x27, 0x00717171); // 1C 1C 1C
+			_palettes[0]->setEntry(0x28, 0x00000000); // 00 00 00
+		}
 	}
 
 	delete resource;


Commit: 447d38f6a7b46c02967e7222d845e9ada13c3448
    https://github.com/scummvm/scummvm/commit/447d38f6a7b46c02967e7222d845e9ada13c3448
Author: NMIError (crampen at gmail.com)
Date: 2020-12-08T17:00:28+01:00

Commit Message:
LURE: Fix Skorl catch animation

When the player gets caught by a Skorl, an animation is shown where the player
is punched in the face. This had a few issues:
- The animation fades in and out on the original interpreter. I've added this.
- The animation plays faster on the original interpreter. Speed was updated to
match this.
- The sound effect for this animation would play right at the start instead of
at the moment of impact. I've added a delay to the sound effect using an
AnimSoundSequence.

Changed paths:
    engines/lure/animseq.cpp
    engines/lure/game.cpp


diff --git a/engines/lure/animseq.cpp b/engines/lure/animseq.cpp
index 059c710624..89f66d0dc9 100644
--- a/engines/lure/animseq.cpp
+++ b/engines/lure/animseq.cpp
@@ -231,7 +231,7 @@ AnimAbortType AnimationSequence::show() {
 
 	// Loop through displaying the animations
 	while (_pPixels < _pPixelsEnd) {
-		if ((soundFrame != NULL) && (frameCtr == 0))
+		if ((soundFrame != NULL) && (soundFrame->rolandSoundId != 0xFF) && (frameCtr == 0))
 			Sound.musicInterface_Play(
 				Sound.isRoland() ? soundFrame->rolandSoundId : soundFrame->adlibSoundId,
 				soundFrame->channelNum, soundFrame->music);
diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp
index f469c6acfe..f23a4bbeae 100644
--- a/engines/lure/game.cpp
+++ b/engines/lure/game.cpp
@@ -274,12 +274,19 @@ void Game::execute() {
 
 		// If Skorl catches player, show the catching animation
 		if ((_state & GS_CAUGHT) != 0) {
+			if (!engine.isEGA())
+				screen.paletteFadeOut();
+
 			Palette palette(SKORL_CATCH_PALETTE_ID);
-			AnimationSequence *anim = new AnimationSequence(SKORL_CATCH_ANIM_ID, palette, false);
 			mouse.cursorOff();
-			Sound.addSound(0x33);
+
+			static const AnimSoundSequence catchSound[] = { { 12, 0xFF, 0xFF, 1, false }, { 1, 41, 41, 1, false } };
+			AnimationSequence *anim = new AnimationSequence(SKORL_CATCH_ANIM_ID, palette, true, 5, catchSound);
 			anim->show();
 			delete anim;
+
+			if (!engine.isEGA())
+				screen.paletteFadeOut();
 		}
 
 		// If the Restart/Restore dialog is needed, show it


Commit: 432529b2bb9413a0e7e09feafb0067eb4617cef9
    https://github.com/scummvm/scummvm/commit/432529b2bb9413a0e7e09feafb0067eb4617cef9
Author: NMIError (crampen at gmail.com)
Date: 2020-12-08T17:00:28+01:00

Commit Message:
LURE: Fix chute animation

The animation that plays when you fall through the sewage chute near the start
of the game had some issues. Fades were missing at several points, the middle
part of the animation was played only once and too slow, and when skipping the
animation it would only skip the currently playing part instead of the entire
animation.

To fix these issues, I've added an option to AnimationSequence to loop the
animation a number of times.

Changed paths:
    engines/lure/animseq.cpp
    engines/lure/animseq.h
    engines/lure/game.cpp
    engines/lure/sound.cpp
    engines/lure/sound.h


diff --git a/engines/lure/animseq.cpp b/engines/lure/animseq.cpp
index 89f66d0dc9..8e6713558f 100644
--- a/engines/lure/animseq.cpp
+++ b/engines/lure/animseq.cpp
@@ -141,8 +141,8 @@ void AnimationSequence::vgaDecodeFrame(byte *&pPixels, byte *&pLines) {
 }
 
 AnimationSequence::AnimationSequence(uint16 screenId, Palette &palette,  bool fadeIn, int frameDelay,
-					 const AnimSoundSequence *soundList): _screenId(screenId), _palette(palette),
-					 _frameDelay(frameDelay), _soundList(soundList) {
+					 const AnimSoundSequence *soundList, uint8 loops): _screenId(screenId), _palette(palette),
+					 _frameDelay(frameDelay), _soundList(soundList), _loops(loops) {
 	Screen &screen = Screen::getReference();
 	PictureDecoder decoder;
 	Disk &d = Disk::getReference();
@@ -162,30 +162,14 @@ AnimationSequence::AnimationSequence(uint16 screenId, Palette &palette,  bool fa
 		screen.setPaletteEmpty(RES_PALETTE_ENTRIES);
 		screen.screen().empty();
 
-		// Load the screen - each four bytes contain the four planes
-		// worth of data for 8 sequential pixels
 		byte *pSrc = _decodedData->data();
-		byte *pDest = screen.screen().data().data() +
-			(FULL_SCREEN_WIDTH * MENUBAR_Y_SIZE);
-
-		for (int ctr = 0; ctr < FULL_SCREEN_WIDTH * (FULL_SCREEN_HEIGHT -
-				MENUBAR_Y_SIZE) / 8; ++ctr, pDest += EGA_PIXELS_PER_BYTE) {
-			for (int planeCtr = 0; planeCtr < EGA_NUM_LAYERS; ++planeCtr, ++pSrc) {
-				byte v = *pSrc;
-				for (int bitCtr = 0; bitCtr < 8; ++bitCtr, v <<= 1) {
-					if ((v & 0x80) != 0)
-					*(pDest + bitCtr) |= 1 << planeCtr;
-				}
-			}
-		}
-
-		screen.update();
+		pSrc = showInitialScreen(pSrc);
 		screen.setPalette(&_palette, 0, _palette.numEntries());
 
 		// Set pointers for animation
-		_pPixels = pSrc;
+		_pPixelsStart = _pPixels = pSrc;
 		_pPixelsEnd = _decodedData->data() + _decodedData->size() - 1;
-		_pLines = NULL;
+		_pLinesStart = _pLines = NULL;
 		_pLinesEnd = NULL;
 
 	} else {
@@ -194,17 +178,16 @@ AnimationSequence::AnimationSequence(uint16 screenId, Palette &palette,  bool fa
 
 		// Reset the palette and set the initial starting screen
 		screen.setPaletteEmpty(RES_PALETTE_ENTRIES);
-		screen.screen().data().copyFrom(_decodedData, 0, 0, FULL_SCREEN_HEIGHT * FULL_SCREEN_WIDTH);
-		screen.update();
+		showInitialScreen();
 
 		// Set the palette
 		if (fadeIn)	screen.paletteFadeIn(&_palette);
 		else screen.setPalette(&_palette, 0, _palette.numEntries());
 
 		// Set up frame pointers
-		_pPixels = _decodedData->data() + SCREEN_SIZE;
+		_pPixelsStart = _pPixels = _decodedData->data() + SCREEN_SIZE;
 		_pPixelsEnd = _decodedData->data() + _decodedData->size() - 1;
-		_pLines = _lineRefs->data();
+		_pLinesStart = _pLines = _lineRefs->data();
 		_pLinesEnd = _lineRefs->data() + _lineRefs->size() - 1;
 	}
 }
@@ -230,21 +213,32 @@ AnimAbortType AnimationSequence::show() {
 	LureEngine::getReference()._saveLoadAllowed = false;
 
 	// Loop through displaying the animations
-	while (_pPixels < _pPixelsEnd) {
-		if ((soundFrame != NULL) && (soundFrame->rolandSoundId != 0xFF) && (frameCtr == 0))
-			Sound.musicInterface_Play(
-				Sound.isRoland() ? soundFrame->rolandSoundId : soundFrame->adlibSoundId,
-				soundFrame->channelNum, soundFrame->music);
-
-		if (_isEGA)
-			egaDecodeFrame(_pPixels);
-		else {
-			if (_pLines >= _pLinesEnd) break;
-			vgaDecodeFrame(_pPixels, _pLines);
-		}
+	while (_loops > 0) {
+		if (_pPixels < _pPixelsEnd && (_isEGA || _pLines < _pLinesEnd)) {
+			if ((soundFrame != NULL) && (soundFrame->rolandSoundId != 0xFF) && (frameCtr == 0))
+				Sound.musicInterface_Play(
+					Sound.isRoland() ? soundFrame->rolandSoundId : soundFrame->adlibSoundId,
+					soundFrame->channelNum, soundFrame->music);
+
+			if (_isEGA)
+				egaDecodeFrame(_pPixels);
+			else {
+				vgaDecodeFrame(_pPixels, _pLines);
+			}
 
-		// Make the decoded frame visible
-		screen.update();
+			// Make the decoded frame visible
+			screen.update();
+		} else {
+			// Animation has finished.
+			_loops--;
+			if (_loops > 0) {
+				// Animation will be repeated, so reset
+				// and show the first frame again.
+				_pPixels = _pPixelsStart;
+				_pLines = _pLinesStart;
+				showInitialScreen(_decodedData->data());
+			}
+		}
 
 		result = delay(_frameDelay * 1000 / 50);
 		if (result != ABORT_NONE) return result;
@@ -277,4 +271,31 @@ bool AnimationSequence::step() {
 	return true;
 }
 
+byte *AnimationSequence::showInitialScreen(byte *pSrc) {
+	Screen &screen = Screen::getReference();
+
+	if (_isEGA) {
+		// Load the screen - each four bytes contain the four planes
+		// worth of data for 8 sequential pixels
+		byte *pDest = screen.screen().data().data() +
+			(FULL_SCREEN_WIDTH * MENUBAR_Y_SIZE);
+
+		for (int ctr = 0; ctr < FULL_SCREEN_WIDTH * (FULL_SCREEN_HEIGHT -
+			MENUBAR_Y_SIZE) / 8; ++ctr, pDest += EGA_PIXELS_PER_BYTE) {
+			for (int planeCtr = 0; planeCtr < EGA_NUM_LAYERS; ++planeCtr, ++pSrc) {
+				byte v = *pSrc;
+				for (int bitCtr = 0; bitCtr < 8; ++bitCtr, v <<= 1) {
+					if ((v & 0x80) != 0)
+						*(pDest + bitCtr) |= 1 << planeCtr;
+				}
+			}
+		}
+	} else {
+		screen.screen().data().copyFrom(_decodedData, 0, 0, FULL_SCREEN_HEIGHT * FULL_SCREEN_WIDTH);
+	}
+	screen.update();
+
+	return pSrc;
+}
+
 } // End of namespace Lure
diff --git a/engines/lure/animseq.h b/engines/lure/animseq.h
index dcc18603fc..3078f0e4be 100644
--- a/engines/lure/animseq.h
+++ b/engines/lure/animseq.h
@@ -45,20 +45,23 @@ private:
 	MemoryBlock *_decodedData;
 	MemoryBlock *_lineRefs;
 	byte *_pPixels, *_pLines;
+	byte *_pPixelsStart, *_pLinesStart;
 	byte *_pPixelsEnd, *_pLinesEnd;
 	const AnimSoundSequence *_soundList;
 	int _frameDelay;
+	uint8 _loops;
 
 	AnimAbortType delay(uint32 milliseconds);
 	void egaDecodeFrame(byte *&pPixels);
 	void vgaDecodeFrame(byte *&pPixels, byte *&pLines);
 public:
 	AnimationSequence(uint16 screenId, Palette &palette,  bool fadeIn, int frameDelay = 7,
-		const AnimSoundSequence *soundList = NULL);
+		const AnimSoundSequence *soundList = NULL, uint8 loops = 1);
 	~AnimationSequence();
 
 	AnimAbortType show();
 	bool step();
+	byte *showInitialScreen(byte *pSrc = 0);
 };
 
 } // End of namespace Lure
diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp
index f23a4bbeae..b256fe12eb 100644
--- a/engines/lure/game.cpp
+++ b/engines/lure/game.cpp
@@ -391,23 +391,31 @@ void Game::displayChuteAnimation() {
 	ValueTableData &fields = res.fieldList();
 	Palette palette(CHUTE_PALETTE_ID);
 
+	mouse.setCursorNum(CursorType::CURSOR_DISK);
+	if (!LureEngine::getReference().isEGA())
+		Screen::getReference().paletteFadeOut();
+
 	debugC(ERROR_INTERMEDIATE, kLureDebugAnimations, "Starting chute animation");
 	mouse.cursorOff();
 
 	Sound.killSounds();
-	Sound.musicInterface_Play(0x40, 0, true);
 
-	AnimationSequence *anim = new AnimationSequence(CHUTE_ANIM_ID, palette, false);
-	anim->show();
+	AnimationSequence *anim = new AnimationSequence(CHUTE_ANIM_ID, palette, true);
+	Sound.musicInterface_Play(0x40, 0, true);
+	AnimAbortType result = anim->show();
 	delete anim;
 
-	anim = new AnimationSequence(CHUTE2_ANIM_ID, palette, false);
-	anim->show();
-	delete anim;
+	if (result != ABORT_END_INTRO) {
+		anim = new AnimationSequence(CHUTE2_ANIM_ID, palette, true, 5, NULL, 4);
+		result = anim->show();
+		delete anim;
+	}
 
-	anim = new AnimationSequence(CHUTE3_ANIM_ID, palette, false);
-	anim->show();
-	delete anim;
+	if (result != ABORT_END_INTRO) {
+		anim = new AnimationSequence(CHUTE3_ANIM_ID, palette, false);
+		anim->show();
+		delete anim;
+	}
 
 	Sound.killSounds();
 	mouse.cursorOn();
diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp
index 96fc1c8d87..38ebfeb071 100644
--- a/engines/lure/sound.cpp
+++ b/engines/lure/sound.cpp
@@ -329,8 +329,7 @@ void SoundManager::addSound(uint8 soundIndex, bool tidyFlag) {
 
 	_activeSounds.push_back(SoundList::value_type(newEntry));
 
-	musicInterface_Play(rec.soundNumber, channelCtr, false, numChannels);
-	musicInterface_SetVolume(channelCtr, newEntry->volume);
+	musicInterface_Play(rec.soundNumber, channelCtr, false, numChannels, newEntry->volume);
 }
 
 void SoundManager::addSound2(uint8 soundIndex) {
@@ -474,8 +473,7 @@ void SoundManager::restoreSounds() {
 		if ((rec.numChannels != 0) && ((rec.flags & SF_RESTORE) != 0)) {
 			Common::fill(_channelsInUse + rec.channel, _channelsInUse + rec.channel + rec.numChannels, true);
 
-			musicInterface_Play(rec.soundNumber, rec.channel, false, rec.numChannels);
-			musicInterface_SetVolume(rec.channel, rec.volume);
+			musicInterface_Play(rec.soundNumber, rec.channel, false, rec.numChannels, rec.volume);
 		}
 
 		++i;
@@ -545,7 +543,7 @@ void SoundManager::resume() {
 // musicInterface_Play
 // Play the specified sound
 
-void SoundManager::musicInterface_Play(uint8 soundNumber, uint8 channelNumber, bool isMusic, uint8 numChannels) {
+void SoundManager::musicInterface_Play(uint8 soundNumber, uint8 channelNumber, bool isMusic, uint8 numChannels, uint8 volume) {
 	debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_Play soundNumber=%d, channel=%d",
 		soundNumber, channelNumber);
 	Game &game = Game::getReference();
@@ -598,7 +596,7 @@ void SoundManager::musicInterface_Play(uint8 soundNumber, uint8 channelNumber, b
 			_sourcesInUse[source] = true;
 	}
 	MidiMusic *sound = new MidiMusic(_driver, _channelsInner, channelNumber, soundNum,
-		isMusic, loop, source, numChannels, soundStart, dataSize);
+		isMusic, loop, source, numChannels, soundStart, dataSize, volume);
 	_playingSounds.push_back(MusicList::value_type(sound));
 	_soundMutex.unlock();
 }
@@ -788,7 +786,7 @@ void SoundManager::doTimer() {
 /*------------------------------------------------------------------------*/
 
 MidiMusic::MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS],
-					 uint8 channelNum, uint8 soundNum, bool isMus, bool loop, int8 source, uint8 numChannels, void *soundData, uint32 size) {
+					 uint8 channelNum, uint8 soundNum, bool isMus, bool loop, int8 source, uint8 numChannels, void *soundData, uint32 size, uint8 volume) {
 	_driver = driver;
 	assert(_driver);
 	_mt32Driver = dynamic_cast<MidiDriver_MT32GM *>(_driver);
@@ -803,9 +801,9 @@ MidiMusic::MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS],
 	_numChannels = numChannels;
 	_volume = 0;
 
-	// Default sound resource volume: 80h (neutral).
-	// TODO AdLib does not use sound resource volume, so use fixed 240.
-	setVolume(Sound.isRoland() ? 0x80 : 240);
+	// Set sound resource volume (default is 80h - neutral).
+	// TODO AdLib currently does not use sound resource volume, so use fixed 240.
+	setVolume(Sound.isRoland() ? volume : 240);
 
 	_parser = MidiParser::createParser_SMF(source);
 	_parser->setMidiDriver(this);
diff --git a/engines/lure/sound.h b/engines/lure/sound.h
index 68a985ea3e..9af92e7014 100644
--- a/engines/lure/sound.h
+++ b/engines/lure/sound.h
@@ -72,7 +72,7 @@ private:
 
 public:
 	MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS],
-		 uint8 channelNum, uint8 soundNum, bool isMus, bool loop, int8 source, uint8 numChannels, void *soundData, uint32 size);
+		 uint8 channelNum, uint8 soundNum, bool isMus, bool loop, int8 source, uint8 numChannels, void *soundData, uint32 size, uint8 volume);
 	~MidiMusic() override;
 	void setVolume(int volume);
 	int getVolume() const { return _volume; }
@@ -168,7 +168,7 @@ public:
 
 	// The following methods implement the external sound player module
 	//void musicInterface_Initialize();
-	void musicInterface_Play(uint8 soundNumber, uint8 channelNumber, bool isMusic = false, uint8 numChannels = 4);
+	void musicInterface_Play(uint8 soundNumber, uint8 channelNumber, bool isMusic = false, uint8 numChannels = 4, uint8 volume = 0x80);
 	void musicInterface_Stop(uint8 soundNumber);
 	bool musicInterface_CheckPlaying(uint8 soundNumber);
 	void musicInterface_SetVolume(uint8 channelNum, uint8 volume);


Commit: 6454b6902616fb46b40daedf0b6d3389d579de06
    https://github.com/scummvm/scummvm/commit/6454b6902616fb46b40daedf0b6d3389d579de06
Author: NMIError (crampen at gmail.com)
Date: 2020-12-08T17:00:28+01:00

Commit Message:
LURE: Fix game over screen

The music playing at the game over screen would only play once and send MIDI
CC 18 messages, which are not defined in the MIDI standard. I added looping and
removed the non-standard MIDI messages to prevent possible compatibility
issues.

The music for cutscenes and for the game over screen had some strange volume
differences compared to the original interpreter which seem to be caused by a
bug in the original interpreter where volume adjustments from sound effects
would carry over into the music. I've added a note to explain this difference.

Changed paths:
    engines/lure/sound.cpp
    engines/lure/surface.cpp


diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp
index 38ebfeb071..39e87bb62b 100644
--- a/engines/lure/sound.cpp
+++ b/engines/lure/sound.cpp
@@ -577,6 +577,15 @@ void SoundManager::musicInterface_Play(uint8 soundNumber, uint8 channelNumber, b
 		dataSize = nextDataOfs - dataOfs;
 	}
 
+	// Note: the original interpreter seems to keep track of the "volume"
+	// (velocity) adjustment last used for each MIDI channel. The volume
+	// is not set in the few instances where musicInterface_Play is used
+	// directly to play a sound instead of addSound (mostly cutscenes).
+	// As a result, the volume adjustment is used that was last set on
+	// the MIDI channel by whatever sound played there previously.
+	// I think this is unintentional, so in ScummVM volume is set to 80h
+	// (neutral) by default when calling musicInterface_Play without
+	// specifying volume.
 	_soundMutex.lock();
 	int8 source = -1;
 	if (_isRoland) {
diff --git a/engines/lure/surface.cpp b/engines/lure/surface.cpp
index b48d6b7fd6..38a1d3287c 100644
--- a/engines/lure/surface.cpp
+++ b/engines/lure/surface.cpp
@@ -1146,7 +1146,7 @@ bool RestartRestoreDialog::show() {
 	LureEngine &engine = LureEngine::getReference();
 
 	Sound.killSounds();
-	Sound.musicInterface_Play(60, 0, true);
+	Sound.musicInterface_Play(188, 0, true);
 	mouse.setCursorNum(CURSOR_ARROW);
 
 	// See if there are any savegames that can be restored


Commit: 17f4e65afff347d58e26cc1c548ca61c1eaf1096
    https://github.com/scummvm/scummvm/commit/17f4e65afff347d58e26cc1c548ca61c1eaf1096
Author: NMIError (crampen at gmail.com)
Date: 2020-12-08T17:00:28+01:00

Commit Message:
LURE: Improve MT-32 fade-out in intro

The first track in the LotT introduction fades out before the second track
starts. The fade-out is implemented by reducing the velocity of the new notes
that are being played. Because this does not affect notes that are already
playing, the fade-out effect is not very good. I've replaced this by a fade-out
using MIDI channel volume.

Changed paths:
    engines/lure/intro.cpp
    engines/lure/intro.h
    engines/lure/sound.cpp
    engines/lure/sound.h


diff --git a/engines/lure/intro.cpp b/engines/lure/intro.cpp
index eb1b466390..6a43e96e3f 100644
--- a/engines/lure/intro.cpp
+++ b/engines/lure/intro.cpp
@@ -161,14 +161,21 @@ bool Introduction::show() {
 		switch (anim->show()) {
 		case ABORT_NONE:
 			if (curr_anim->endingPause != 0) {
-				if (curr_anim->soundTransitionPause != 0)
+				if (curr_anim->soundTransitionPause != 0) {
+					uint16 pause = curr_anim->soundTransitionPause * 1000 / 50;
+					if (curr_anim->fadeOutSound) {
+						pause -= 3500;
+					}
 					// Wait before transitioning to the next track
-					result = interruptableDelay(curr_anim->soundTransitionPause * 1000 / 50);
-				if (!result) {
-					playMusic(curr_anim->soundNumber2, curr_anim->fadeOutSound);
+					result = interruptableDelay(pause);
+				}
+
+				if (!result)
+					result = playMusic(curr_anim->soundNumber2, curr_anim->fadeOutSound);
+
+				if (!result)
 					// Wait remaining time before the next animation
 					result = interruptableDelay((curr_anim->endingPause - curr_anim->soundTransitionPause) * 1000 / 50);
-				}
 			}
 			break;
 
@@ -224,17 +231,26 @@ bool Introduction::show() {
 	return false;
 }
 
-void Introduction::playMusic(uint8 soundNumber, bool fadeOut) {
+bool Introduction::playMusic(uint8 soundNumber, bool fadeOut) {
+	bool result = false;
+
 	if (soundNumber != 0xFF && _currentSound != soundNumber) {
 		// Stop the previous sound
 		if (fadeOut) {
-			// TODO Implement fade-out
+			result = Sound.fadeOut();
+			if (!result)
+				result = interruptableDelay(500);
+		} else {
+			Sound.musicInterface_KillAll();
 		}
-		Sound.musicInterface_KillAll();
 
-		_currentSound = soundNumber;
-		Sound.musicInterface_Play(_currentSound, 0, true);
+		if (!result) {
+			_currentSound = soundNumber;
+			Sound.musicInterface_Play(_currentSound, 0, true);
+		}
 	}
+
+	return result;
 }
 
 } // End of namespace Lure
diff --git a/engines/lure/intro.h b/engines/lure/intro.h
index ebac8f653a..608986539b 100644
--- a/engines/lure/intro.h
+++ b/engines/lure/intro.h
@@ -37,7 +37,7 @@ private:
 
 	bool showScreen(uint16 screenId, uint16 paletteId, uint16 delaySize, bool fadeOut = true);
 	bool interruptableDelay(uint32 milliseconds);
-	void playMusic(uint8 soundNumber, bool fadeOut);
+	bool playMusic(uint8 soundNumber, bool fadeOut);
 };
 
 } // End of namespace Lure
diff --git a/engines/lure/sound.cpp b/engines/lure/sound.cpp
index 39e87bb62b..f1b0d2f93d 100644
--- a/engines/lure/sound.cpp
+++ b/engines/lure/sound.cpp
@@ -480,33 +480,52 @@ void SoundManager::restoreSounds() {
 	}
 }
 
-void SoundManager::fadeOut() {
+bool SoundManager::fadeOut() {
 	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::fadeOut");
 
+	Events &events = Events::getReference();
+	bool result = false;
+
 	// Fade out all the active sounds
 	musicInterface_TidySounds();
 
-	bool inProgress = true;
-	while (inProgress)
-	{
-		inProgress = false;
-
-		_soundMutex.lock();
-		MusicListIterator i;
-		for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) {
-			MidiMusic &music = **i;
-			if (music.getVolume() > 0) {
-				inProgress = true;
-				music.setVolume(music.getVolume() >= 10 ? music.getVolume() - 10 : 0);
+	if (_isRoland) {
+		_mt32Driver->startFade(3000, 0);
+		while (_mt32Driver->isFading()) {
+			if (events.interruptableDelay(100)) {
+				result = ((events.type() == Common::EVENT_KEYDOWN && events.event().kbd.keycode == 27) ||
+					LureEngine::getReference().shouldQuit());
+				_mt32Driver->abortFade();
+				break;
 			}
 		}
+	} else {
+		bool inProgress = true;
+		while (inProgress) {
+			inProgress = false;
+
+			_soundMutex.lock();
+			MusicListIterator i;
+			for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) {
+				MidiMusic &music = **i;
+				if (music.getVolume() > 0) {
+					inProgress = true;
+					music.setVolume(music.getVolume() >= 10 ? music.getVolume() - 10 : 0);
+				}
+			}
 
-		_soundMutex.unlock();
-		g_system->delayMillis(10);
+			_soundMutex.unlock();
+			g_system->delayMillis(10);
+		}
 	}
 
 	// Kill all the sounds
 	musicInterface_KillAll();
+
+	if (_isRoland)
+		_mt32Driver->setSourceVolume(MidiDriver_MT32GM::DEFAULT_SOURCE_NEUTRAL_VOLUME);
+
+	return result;
 }
 
 void SoundManager::pause() {
diff --git a/engines/lure/sound.h b/engines/lure/sound.h
index 9af92e7014..f541d2319d 100644
--- a/engines/lure/sound.h
+++ b/engines/lure/sound.h
@@ -157,7 +157,7 @@ public:
 	SoundDescResource *findSound(uint8 soundNumber);
 	void removeSounds();
 	void restoreSounds();
-	void fadeOut();
+	bool fadeOut();
 	void pause();
 	void resume();
 	bool getPaused() const { return _paused; }


Commit: 5b01d5f09e53af88a694309697f7d06895367405
    https://github.com/scummvm/scummvm/commit/5b01d5f09e53af88a694309697f7d06895367405
Author: NMIError (crampen at gmail.com)
Date: 2020-12-08T17:00:28+01:00

Commit Message:
LURE: Barrel animation fixes

This change fixes some small differences in the barrel animation between the
original interpreter and ScummVM:
- The animation should fade in at the start
- The music should continue until the animation has faded out
- The mouse cursor should appear after the animation has faded out

Changed paths:
    engines/lure/game.cpp


diff --git a/engines/lure/game.cpp b/engines/lure/game.cpp
index b256fe12eb..11c8f05eec 100644
--- a/engines/lure/game.cpp
+++ b/engines/lure/game.cpp
@@ -425,19 +425,31 @@ void Game::displayChuteAnimation() {
 void Game::displayBarrelAnimation() {
 	Mouse &mouse = Mouse::getReference();
 	Resources &res = Resources::getReference();
+	LureEngine &engine = LureEngine::getReference();
+	Screen &screen = Screen::getReference();
+
+	mouse.setCursorNum(CursorType::CURSOR_DISK);
+	if (!engine.isEGA())
+		screen.paletteFadeOut();
 
 	debugC(ERROR_INTERMEDIATE, kLureDebugAnimations, "Starting barrel animation");
 	Palette palette(BARREL_PALETTE_ID);
-	AnimationSequence *anim = new AnimationSequence(BARREL_ANIM_ID, palette, false);
 	mouse.cursorOff();
 
 	Sound.killSounds();
 	Sound.musicInterface_Play(0x3B, 0, true);
 
+	AnimationSequence *anim = new AnimationSequence(BARREL_ANIM_ID, palette, true);
 	anim->show();
 
 	delete anim;
 
+	if (!engine.shouldQuit() && !engine.isEGA())
+		screen.paletteFadeOut();
+
+	Sound.killSounds();
+	mouse.cursorOn();
+
 	// Disable town NPCs that are no longer needed
 	res.deactivateHotspot(SKORL_ID);
 	res.deactivateHotspot(BLACKSMITH_ID);
@@ -447,9 +459,6 @@ void Game::displayBarrelAnimation() {
 	res.deactivateHotspot(GOEWIN_ID);
 	res.deactivateHotspot(MONK2_ID);
 	res.deactivateHotspot(WAYNE_ID);
-
-	Sound.killSounds();
-	mouse.cursorOn();
 }
 
 void Game::handleClick() {


Commit: fa4948eaa4966ed491ac70c9fa714068b8b55c10
    https://github.com/scummvm/scummvm/commit/fa4948eaa4966ed491ac70c9fa714068b8b55c10
Author: NMIError (crampen at gmail.com)
Date: 2020-12-08T17:00:28+01:00

Commit Message:
LURE: Fix endgame animation

This change fixes several issues with the endgame animation:
- The timing for the sounds for the animation was based on the number of frames
after which the sound should start playing. However, the animation code
interpreted it as the number of frames to wait after playing the sound. This
caused the timing of the sounds to be wrong. Fixed this by moving the number of
frames up to the next sound and adding a dummy sound for the initial pause.
- The pause and thunder sound effect at the end of the animation were missing.
- The AdLib endgame sound resource was not loaded, causing a sound effect to
play instead of the endgame music.
- Changed the timing of the first text screen to match the original interpreter.
- At the last text screen, the game now waits for a keypress before quitting
the game after the music has finished. This matches the behavior of the
original interpeter.
- Made animation more responsive to user quitting the game.
- Screen no longer fades in EGA version.

Changed paths:
    engines/lure/luredefs.h
    engines/lure/scripts.cpp


diff --git a/engines/lure/luredefs.h b/engines/lure/luredefs.h
index a62b50943c..6df2aa3886 100644
--- a/engines/lure/luredefs.h
+++ b/engines/lure/luredefs.h
@@ -237,6 +237,7 @@ enum CursorType {CURSOR_ARROW = 0, CURSOR_DISK = 1, CURSOR_TIME_START = 2,
 #define ROLAND_INTRO_SOUND_RESOURCE_ID 0x30
 #define ADLIB_INTRO_SOUND_RESOURCE_ID 0x31
 #define ROLAND_ENDGAME_SOUND_RESOURCE_ID 0xff10
+#define ADLIB_ENDGAME_SOUND_RESOURCE_ID 0xff11
 
 #define NOONE_ID 0x3E7
 #define PLAYER_ID 0x3E8
diff --git a/engines/lure/scripts.cpp b/engines/lure/scripts.cpp
index 9a6486983c..1c3762f2fd 100644
--- a/engines/lure/scripts.cpp
+++ b/engines/lure/scripts.cpp
@@ -46,9 +46,9 @@ static const uint16 *hotspot_dealloc_set[4] = {&dealloc_list_1[0], &dealloc_list
 
 // Details used for co-ordination of sounds during the endgame sequence
 static const AnimSoundSequence soundList[] = {
-	{9, 0x45, 2, 0, true}, {27, 0x48, 5, 0, false}, {24, 0x46, 3, 0, false}, {24, 0x37, 1, 0, false}, {3, 0x37, 1, 1, false},
-	{3, 0x37, 1, 2, false}, {3, 0x37, 1, 3, false}, {3, 0x37, 1, 4, false}, {4, 0x37, 1, 5, false}, {7, 0x47, 4, 6, false},
-	{31, 0x00, 6, 0, true}, {0, 0, 0, 0, false}
+	{9, 0xFF, 0xFF, 0, false}, {27, 0x45, 2, 0, true}, {24, 0x48, 5, 0, false}, {24, 0x46, 3, 2, false}, {3, 0x37, 1, 0, true},
+	{3, 0x37, 1, 1, true}, {3, 0x37, 1, 2, true}, {3, 0x37, 1, 3, true}, {4, 0x37, 1, 4, true}, {7, 0x37, 1, 5, true},
+	{31, 0x47, 4, 6, false}, {0, 0, 0, 0, false}
 };
 
 /*------------------------------------------------------------------------*/
@@ -194,38 +194,58 @@ void Script::endgameSequence(uint16 v1, uint16 v2, uint16 v3) {
 	Events &events = Events::getReference();
 	AnimationSequence *anim;
 
-	screen.paletteFadeOut();
+	if (!engine.isEGA())
+		screen.paletteFadeOut();
 	mouse.cursorOff();
 
 	Sound.killSounds();
 	if (Sound.isRoland())
+		// MT-32 has the sound effects for the endgame animation
+		// defined in a separate sound resource. AdLib only has
+		// the music defined in its endgame resource, so it uses
+		// sounds from the main sound resource.
 		Sound.loadSection(ROLAND_ENDGAME_SOUND_RESOURCE_ID);
 
 	Palette p(ENDGAME_PALETTE_ID);
 	anim = new AnimationSequence(ENDGAME_ANIM_ID, p, true, 9, soundList);
-	anim->show();
+	AnimAbortType animResult = anim->show();
+
+	Sound.killSounds();
+	if (animResult == ABORT_NONE) {
+		Sound.musicInterface_Play(Sound.isRoland() ? 0 : 0x28, 0, false);
+		events.interruptableDelay(5500);
+	}
 	delete anim;
 
 	Sound.killSounds();
-	Sound.musicInterface_Play(6, 0, true);
+
+	if (engine.shouldQuit())
+		return;
+
+	if (!Sound.isRoland())
+		Sound.loadSection(ADLIB_ENDGAME_SOUND_RESOURCE_ID);
+	Sound.musicInterface_Play(Sound.isRoland() ? 6 : 0, 0, true);
 
 	anim = new AnimationSequence(ENDGAME_ANIM_ID + 2, p, false);
 	anim->show();
-	events.interruptableDelay(13000);
+	events.interruptableDelay(30500);
 	delete anim;
 
+	if (engine.shouldQuit())
+		return;
+
 	anim = new AnimationSequence(ENDGAME_ANIM_ID + 4, p, false);
 	anim->show();
-	if (!events.interruptableDelay(30000)) {
-		// No key yet pressed, so keep waiting
-		while (Sound.musicInterface_CheckPlaying(6) && !engine.shouldQuit()) {
-			if (events.interruptableDelay(20))
-				break;
-		}
+	// Wait until a key is pressed
+	while (!engine.shouldQuit()) {
+		if (events.interruptableDelay(20))
+			break;
 	}
 	delete anim;
 
-	screen.paletteFadeOut();
+	if (!engine.shouldQuit() && !engine.isEGA())
+		screen.paletteFadeOut();
+
 	engine.quitGame();
 }
 




More information about the Scummvm-git-logs mailing list