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

elasota noreply at scummvm.org
Sat May 20 08:50:36 UTC 2023


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

Summary:
5b743a2617 VCRUISE: Implement SndHalt opcode
6fd5f839f4 VCRUISE: Resolve all screen names at load time to fix error when leaving first balloon area.
a9da819739 VCRUISE: Consume animation change from animChange when using it.  Fixes broken animations when using balloon nav compute


Commit: 5b743a261726c1a7d4f297e7ade9aacc6adfa39b
    https://github.com/scummvm/scummvm/commit/5b743a261726c1a7d4f297e7ade9aacc6adfa39b
Author: elasota (ejlasota at gmail.com)
Date: 2023-05-20T04:50:11-04:00

Commit Message:
VCRUISE: Implement SndHalt opcode

Changed paths:
    engines/vcruise/runtime.cpp
    engines/vcruise/runtime.h


diff --git a/engines/vcruise/runtime.cpp b/engines/vcruise/runtime.cpp
index 40ad47afe86..884dc172538 100644
--- a/engines/vcruise/runtime.cpp
+++ b/engines/vcruise/runtime.cpp
@@ -555,7 +555,7 @@ SoundCache::~SoundCache() {
 
 SoundInstance::SoundInstance()
 	: id(0), rampStartVolume(0), rampEndVolume(0), rampRatePerMSec(0), rampStartTime(0), rampTerminateOnCompletion(false),
-	  volume(0), balance(0), effectiveBalance(0), effectiveVolume(0), is3D(false), isLooping(false), isSpeech(false), isSilencedLoop(false), x(0), y(0), endTime(0), duration(0) {
+	  volume(0), balance(0), effectiveBalance(0), effectiveVolume(0), is3D(false), loopingType(kSoundLoopingTypeNotLooping), isSpeech(false), isSilencedLoop(false), x(0), y(0), startTime(0), endTime(0), duration(0) {
 }
 
 SoundInstance::~SoundInstance() {
@@ -993,7 +993,7 @@ Runtime::Runtime(OSystem *system, Audio::Mixer *mixer, const Common::FSNode &roo
 	  _havePendingCompletionCheck(false), _havePendingPlayAmbientSounds(false), _ambientSoundFinishTime(0), _escOn(false), _debugMode(false), _fastAnimationMode(false),
 	  _musicTrack(0), _musicActive(true), _scoreSectionEndTime(0), _musicVolume(getDefaultSoundVolume()), _musicVolumeRampStartTime(0), _musicVolumeRampStartVolume(0), _musicVolumeRampRatePerMSec(0), _musicVolumeRampEnd(0),
 	  _panoramaDirectionFlags(0),
-	  _loadedAnimation(0), _loadedAnimationHasSound(false), _animPendingDecodeFrame(0), _animDisplayingFrame(0), _animFirstFrame(0), _animLastFrame(0), _animStopFrame(0), _animVolume(getDefaultSoundVolume()),
+	  _loadedAnimation(0), _loadedAnimationHasSound(false), _animTerminateAtStartOfFrame(true), _animPendingDecodeFrame(0), _animDisplayingFrame(0), _animFirstFrame(0), _animLastFrame(0), _animStopFrame(0), _animVolume(getDefaultSoundVolume()),
 	  _animStartTime(0), _animFramesDecoded(0), _animDecoderState(kAnimDecoderStateStopped),
 	  _animPlayWhileIdle(false), _idleLockInteractions(false), _idleIsOnInteraction(false), _idleHaveClickInteraction(false), _idleHaveDragInteraction(false), _idleInteractionID(0), _haveIdleStaticAnimation(false),
 	  _inGameMenuState(kInGameMenuStateInvisible), _inGameMenuActiveElement(0), _inGameMenuButtonActive {false, false, false, false, false},
@@ -1791,6 +1791,8 @@ void Runtime::exitGyroIdle() {
 }
 
 void Runtime::continuePlayingAnimation(bool loop, bool useStopFrame, bool &outAnimationEnded) {
+	bool terminateAtStartOfFrame = _animTerminateAtStartOfFrame;
+
 	outAnimationEnded = false;
 
 	if (!_animDecoder) {
@@ -1835,6 +1837,11 @@ void Runtime::continuePlayingAnimation(bool loop, bool useStopFrame, bool &outAn
 		if (!needNewFrame)
 			break;
 
+		if (!terminateAtStartOfFrame && !loop && _animPendingDecodeFrame > _animLastFrame) {
+			outAnimationEnded = true;
+			return;
+		}
+
 		// We check this here for timing reasons: The no-loop case after the draw terminates the animation as soon as the last frame
 		// starts delaying without waiting for the time until the next frame to expire.
 		// The loop check here DOES wait for the time until next frame to expire.
@@ -1932,7 +1939,7 @@ void Runtime::continuePlayingAnimation(bool loop, bool useStopFrame, bool &outAn
 		}
 
 		if (!loop) {
-			if (_animDisplayingFrame >= _animLastFrame) {
+			if (terminateAtStartOfFrame && _animDisplayingFrame >= _animLastFrame) {
 				_animDecoder->pauseVideo(true);
 				_animDecoderState = kAnimDecoderStatePaused;
 
@@ -3342,6 +3349,7 @@ void Runtime::changeAnimation(const AnimationDef &animDef, uint initialFrame, bo
 	_animLastFrame = animDef.lastFrame;
 	_animConstraintRect = animDef.constraintRect;
 	_animFrameRateLock = Fraction();
+	_animTerminateAtStartOfFrame = true;
 
 	SfxData::PlaylistMap_t::const_iterator playlistIt = _sfxData.playlists.find(animDef.animName);
 
@@ -3381,11 +3389,13 @@ void Runtime::setSound3DParameters(SoundInstance &snd, int32 x, int32 y, const S
 }
 
 void Runtime::triggerSound(bool looping, SoundInstance &snd, int32 volume, int32 balance, bool is3D, bool isSpeech) {
+	SoundLoopingType oldLoopingType = snd.loopingType;
+
 	snd.volume = volume;
 	snd.balance = balance;
 	snd.is3D = is3D;
-	snd.isLooping = looping;
 	snd.isSpeech = isSpeech;
+	snd.loopingType = (looping ? kSoundLoopingTypeLooping : kSoundLoopingTypeNotLooping);
 
 	computeEffectiveVolumeAndBalance(snd);
 
@@ -3417,8 +3427,9 @@ void Runtime::triggerSound(bool looping, SoundInstance &snd, int32 volume, int32
 	}
 
 	// Construct looping stream if needed and none exists
-	if (looping && !cache->loopingStream) {
+	if (looping && !cache->loopingStream || oldLoopingType == kSoundLoopingTypeTerminated) {
 		cache->player.reset();
+		cache->loopingStream.reset();
 		cache->loopingStream.reset(new Audio::LoopingAudioStream(cache->stream.get(), 0, DisposeAfterUse::NO, true));
 	}
 
@@ -3439,10 +3450,11 @@ void Runtime::triggerSound(bool looping, SoundInstance &snd, int32 volume, int32
 		cache->player->play(snd.effectiveVolume, snd.effectiveBalance);
 	}
 
+	snd.startTime = g_system->getMillis();
 	if (looping)
 		snd.endTime = 0;
 	else
-		snd.endTime = g_system->getMillis(true) + static_cast<uint32>(cache->stream->getLength().msecs()) + 1000u;
+		snd.endTime = snd.startTime + snd.duration + 1000u;
 }
 
 void Runtime::triggerSoundRamp(SoundInstance &snd, uint durationMSec, int32 newVolume, bool terminateOnCompletion) {
@@ -3452,7 +3464,7 @@ void Runtime::triggerSoundRamp(SoundInstance &snd, uint durationMSec, int32 newV
 	snd.rampStartTime = g_system->getMillis();
 	snd.rampRatePerMSec = 65536;
 
-	if (!snd.isLooping && newVolume == getSilentSoundVolume())
+	if (snd.loopingType == kSoundLoopingTypeLooping && newVolume == getSilentSoundVolume())
 		snd.rampTerminateOnCompletion = true;
 
 	if (durationMSec)
@@ -3531,6 +3543,21 @@ void Runtime::stopSound(SoundInstance &sound) {
 	sound.isSilencedLoop = false;
 }
 
+void Runtime::convertLoopingSoundToNonLooping(SoundInstance &sound) {
+	if (!sound.cache)
+		return;
+
+	if (sound.cache->loopingStream) {
+		sound.cache->loopingStream->setRemainingIterations(1);
+		sound.loopingType = kSoundLoopingTypeTerminated;
+
+		uint32 currentTime = g_system->getMillis();
+
+		uint32 alreadyPlayedTime = ((currentTime - sound.startTime) % sound.duration);
+		sound.endTime = currentTime + sound.duration - alreadyPlayedTime;
+	}
+}
+
 void Runtime::updateSounds(uint32 timestamp) {
 	for (uint sndIndex = 0; sndIndex < _activeSounds.size(); sndIndex++) {
 		SoundInstance &snd = *_activeSounds[sndIndex];
@@ -3567,7 +3594,7 @@ void Runtime::updateSounds(uint32 timestamp) {
 			snd.endTime = 0;
 		}
 
-		if (snd.isLooping) {
+		if (snd.loopingType == kSoundLoopingTypeLooping) {
 			if (snd.volume <= getSilentSoundVolume()) {
 				if (!snd.isSilencedLoop) {
 					if (snd.cache) {
@@ -4928,7 +4955,7 @@ void Runtime::recordSaveGameSnapshot() {
 		}
 
 		saveSound.is3D = sound.is3D;
-		saveSound.isLooping = sound.isLooping;
+		saveSound.isLooping = (sound.loopingType == kSoundLoopingTypeLooping);
 		saveSound.isSpeech = sound.isSpeech;
 		saveSound.x = sound.x;
 		saveSound.y = sound.y;
@@ -5034,7 +5061,7 @@ void Runtime::restoreSaveGameSnapshot() {
 		si->volume = sound.volume;
 		si->balance = sound.balance;
 		si->is3D = sound.is3D;
-		si->isLooping = sound.isLooping;
+		si->loopingType = (sound.isLooping ? kSoundLoopingTypeLooping : kSoundLoopingTypeNotLooping);
 		si->isSpeech = sound.isSpeech;
 		si->x = sound.x;
 		si->y = sound.y;
@@ -5381,6 +5408,12 @@ void Runtime::scriptOpAnimS(ScriptArg_t arg) {
 	// Static animations start on the last frame
 	changeAnimation(animDef, animDef.lastFrame, false);
 
+	// We use different behavior from the original game to mostly speed up one-frame animations by terminating them
+	// at the start of the last frame instead of the end of the last frame.  However, this causes the mechanical
+	// keyboard to play all of the pin animations at once which is kind of annoying.
+	if (_gameID == GID_SCHIZM && animDef.animName.hasPrefix("WEJSCIE_DN"))
+		_animTerminateAtStartOfFrame = false;
+
 	_gameState = kGameStateWaitingForAnimation;
 	_screenNumber = stackArgs[kAnimDefStackArgs + 0];
 	_direction = stackArgs[kAnimDefStackArgs + 1];
@@ -6626,7 +6659,18 @@ void Runtime::scriptOpSndWait(ScriptArg_t arg) {
 	}
 }
 
-OPCODE_STUB(SndHalt)
+void Runtime::scriptOpSndHalt(ScriptArg_t arg) {
+	TAKE_STACK_INT(1);
+
+	SoundInstance *snd = resolveSoundByID(stackArgs[0]);
+	if (snd) {
+		convertLoopingSoundToNonLooping(*snd);
+
+		_delayCompletionTime = snd->endTime;
+		_gameState = kGameStateDelay;
+	}
+}
+
 OPCODE_STUB(SndToBack)
 
 void Runtime::scriptOpSndStop(ScriptArg_t arg) {
diff --git a/engines/vcruise/runtime.h b/engines/vcruise/runtime.h
index 5dc39cfd4a3..2488b8da2fb 100644
--- a/engines/vcruise/runtime.h
+++ b/engines/vcruise/runtime.h
@@ -43,6 +43,7 @@ namespace Audio {
 
 class AudioStream;
 class SeekableAudioStream;
+class LoopingAudioStream;
 
 } // End of namespace Audio
 
@@ -216,10 +217,16 @@ struct SoundCache {
 	~SoundCache();
 
 	Common::SharedPtr<Audio::SeekableAudioStream> stream;
-	Common::SharedPtr<Audio::AudioStream> loopingStream;
+	Common::SharedPtr<Audio::LoopingAudioStream> loopingStream;
 	Common::SharedPtr<AudioPlayer> player;
 };
 
+enum SoundLoopingType {
+	kSoundLoopingTypeNotLooping,	// Was never looping
+	kSoundLoopingTypeTerminated,	// Was looping and then converted into non-looping
+	kSoundLoopingTypeLooping,		// Is looping
+};
+
 struct SoundInstance {
 	SoundInstance();
 	~SoundInstance();
@@ -242,7 +249,7 @@ struct SoundInstance {
 	int32 effectiveBalance;
 
 	bool is3D;
-	bool isLooping;
+	SoundLoopingType loopingType;
 	bool isSpeech;
 	bool isSilencedLoop;	// Loop is still playing but reached 0 volume so the player was unloaded
 	int32 x;
@@ -250,6 +257,7 @@ struct SoundInstance {
 
 	SoundParams3D params3D;
 
+	uint32 startTime;
 	uint32 endTime;
 	uint32 duration;
 };
@@ -817,6 +825,7 @@ private:
 	void triggerSound(bool looping, SoundInstance &sound, int32 volume, int32 balance, bool is3D, bool isSpeech);
 	void triggerSoundRamp(SoundInstance &sound, uint durationMSec, int32 newVolume, bool terminateOnCompletion);
 	void stopSound(SoundInstance &sound);
+	void convertLoopingSoundToNonLooping(SoundInstance &sound);
 	void updateSounds(uint32 timestamp);
 	void updateSubtitles();
 	void update3DSounds();
@@ -1170,6 +1179,7 @@ private:
 	Common::SharedPtr<Video::AVIDecoder> _animDecoder;
 	Common::SharedPtr<SfxPlaylist> _animPlaylist;
 	AnimDecoderState _animDecoderState;
+	bool _animTerminateAtStartOfFrame;
 	uint _animPendingDecodeFrame;
 	uint _animDisplayingFrame;
 	uint _animFirstFrame;


Commit: 6fd5f839f4dd94ad66915a16a802128693fd5f61
    https://github.com/scummvm/scummvm/commit/6fd5f839f4dd94ad66915a16a802128693fd5f61
Author: elasota (ejlasota at gmail.com)
Date: 2023-05-20T04:50:12-04:00

Commit Message:
VCRUISE: Resolve all screen names at load time to fix error when leaving first balloon area.

Changed paths:
    engines/vcruise/runtime.cpp
    engines/vcruise/runtime.h


diff --git a/engines/vcruise/runtime.cpp b/engines/vcruise/runtime.cpp
index 884dc172538..0f1bac04b4d 100644
--- a/engines/vcruise/runtime.cpp
+++ b/engines/vcruise/runtime.cpp
@@ -1218,6 +1218,9 @@ bool Runtime::bootGame(bool newGame) {
 		// but the frame range for 27 and 28 is supposed to use room 25 (the root of the duplication), not 26.
 		loadDuplicateRooms();
 		debug(1, "Duplicated rooms identified OK");
+
+		loadAllSchizmScreenNames();
+		debug(1, "Screen names resolved OK");
 	} else {
 		StartConfigDef &startConfig = _startConfigs[kStartConfigInitial];
 		startConfig.disc = 1;
@@ -2615,6 +2618,46 @@ void Runtime::loadDuplicateRooms() {
 	}
 }
 
+void Runtime::loadAllSchizmScreenNames() {
+	assert(_gameID == GID_SCHIZM);
+
+	Common::ArchiveMemberList logics;
+	SearchMan.listMatchingMembers(logics, "Log/Room##.log", true);
+
+	Common::Array<uint> roomsToCompile;
+
+	for (const Common::ArchiveMemberPtr &logic : logics) {
+		Common::String name = logic->getName();
+
+		char d10 = name[4];
+		char d1 = name[5];
+
+		uint roomNumber = (d10 - '0') * 10 + (d1 - '0');
+
+		// Rooms 1 and 3 are always compiled.  2 is a cheat room that contains garbage.
+		if (roomNumber > 3)
+			roomsToCompile.push_back(roomNumber);
+	}
+
+	Common::sort(roomsToCompile.begin(), roomsToCompile.end());
+
+	for (uint roomNumber : roomsToCompile) {
+		if (roomNumber >= _roomDuplicationOffsets.size() || _roomDuplicationOffsets[roomNumber] == 0) {
+			uint roomSetToCompile[3] = {1, 3, roomNumber};
+
+			compileSchizmLogicSet(roomSetToCompile, 3);
+
+			for (const RoomScriptSetMap_t::Node &rssNode : _scriptSet->roomScripts) {
+				if (rssNode._key != roomNumber)
+					continue;
+
+				for (const ScreenNameMap_t::Node &snNode : rssNode._value->screenNames)
+					_globalRoomScreenNameToScreenIDs[roomNumber][snNode._key] = snNode._value;
+			}
+		}
+	}
+}
+
 Common::SharedPtr<SoundInstance> Runtime::loadWave(const Common::String &soundName, uint soundID, const Common::ArchiveMemberPtr &archiveMemberPtr) {
 	for (const Common::SharedPtr<SoundInstance> &activeSound : _activeSounds) {
 		if (activeSound->name == soundName)
@@ -4453,6 +4496,7 @@ Common::SharedPtr<Graphics::Surface> Runtime::loadGraphic(const Common::String &
 
 	Common::SharedPtr<Graphics::Surface> surf(new Graphics::Surface());
 	surf->copyFrom(*bmpDecoder.getSurface());
+	surf.reset(surf->convertTo(Graphics::createPixelFormat<8888>()));
 
 	return surf;
 }
@@ -6732,15 +6776,21 @@ void Runtime::scriptOpAnimChange(ScriptArg_t arg) {
 void Runtime::scriptOpScreenName(ScriptArg_t arg) {
 	const Common::String &scrName = _scriptSet->strings[arg];
 
-	RoomScriptSet *rss = getRoomScriptSetForCurrentRoom();
-	if (!rss)
-		error("Couldn't resolve room number to find screen name: '%s'", scrName.c_str());
+	uint roomNumber = _roomNumber;
+	if (roomNumber < _roomDuplicationOffsets.size())
+		roomNumber -= _roomDuplicationOffsets[roomNumber];
+
+	RoomToScreenNameToRoomMap_t::const_iterator roomIt = _globalRoomScreenNameToScreenIDs.find(roomNumber);
+	if (roomIt != _globalRoomScreenNameToScreenIDs.end()) {
+		ScreenNameToRoomMap_t::const_iterator screenIt = roomIt->_value.find(scrName);
 
-	ScreenNameMap_t::const_iterator screenNameIt = rss->screenNames.find(scrName);
-	if (screenNameIt == rss->screenNames.end())
-		error("Couldn't resolve screen name '%s'", scrName.c_str());
+		if (screenIt != roomIt->_value.end()) {
+			_scriptStack.push_back(StackValue(static_cast<StackInt_t>(screenIt->_value)));
+			return;
+		}
+	}
 
-	_scriptStack.push_back(StackValue(static_cast<StackInt_t>(screenNameIt->_value)));
+	error("Couldn't resolve screen name '%s'", scrName.c_str());
 }
 
 void Runtime::scriptOpExtractByte(ScriptArg_t arg) {
diff --git a/engines/vcruise/runtime.h b/engines/vcruise/runtime.h
index 2488b8da2fb..03267d3b8be 100644
--- a/engines/vcruise/runtime.h
+++ b/engines/vcruise/runtime.h
@@ -547,6 +547,9 @@ struct FontCacheItem {
 	Common::SharedPtr<Graphics::Font> keepAlive;
 };
 
+typedef Common::HashMap<Common::String, uint> ScreenNameToRoomMap_t;
+typedef Common::HashMap<uint, ScreenNameToRoomMap_t> RoomToScreenNameToRoomMap_t;
+
 class Runtime {
 public:
 	friend class RuntimeMenuInterface;
@@ -794,6 +797,7 @@ private:
 	void loadConfig(const char *cfgPath);
 	void loadScore();
 	void loadDuplicateRooms();
+	void loadAllSchizmScreenNames();
 	Common::SharedPtr<SoundInstance> loadWave(const Common::String &soundName, uint soundID, const Common::ArchiveMemberPtr &archiveMemberPtr);
 	SoundCache *loadCache(SoundInstance &sound);
 	void resolveSoundByName(const Common::String &soundName, bool load, StackInt_t &outSoundID, SoundInstance *&outWave);
@@ -1150,6 +1154,7 @@ private:
 
 	Common::Array<Common::SharedPtr<RoomDef> > _roomDefs;
 	Common::Array<uint> _roomDuplicationOffsets;
+	RoomToScreenNameToRoomMap_t _globalRoomScreenNameToScreenIDs;
 	Common::SharedPtr<ScriptSet> _scriptSet;
 
 	Common::Array<CallStackFrame> _scriptCallStack;


Commit: a9da8197392edabfc60bc339df2e6a76415ba0c5
    https://github.com/scummvm/scummvm/commit/a9da8197392edabfc60bc339df2e6a76415ba0c5
Author: elasota (ejlasota at gmail.com)
Date: 2023-05-20T04:50:12-04:00

Commit Message:
VCRUISE: Consume animation change from animChange when using it.  Fixes broken animations when using balloon nav computer.

Changed paths:
    engines/vcruise/runtime.cpp
    engines/vcruise/runtime.h


diff --git a/engines/vcruise/runtime.cpp b/engines/vcruise/runtime.cpp
index 0f1bac04b4d..0d24ae68d3b 100644
--- a/engines/vcruise/runtime.cpp
+++ b/engines/vcruise/runtime.cpp
@@ -3953,7 +3953,7 @@ AnimationDef Runtime::stackArgsToAnimDef(const StackInt_t *args) const {
 	return def;
 }
 
-void Runtime::adjustUsingAnimChange(AnimationDef &animDef) const {
+void Runtime::consumeAnimChangeAndAdjustAnim(AnimationDef &animDef) {
 	if (_scriptEnv.animChangeSet) {
 		uint origFirstFrame = animDef.firstFrame;
 		uint origLastFrame = animDef.lastFrame;
@@ -3966,6 +3966,8 @@ void Runtime::adjustUsingAnimChange(AnimationDef &animDef) const {
 
 		animDef.firstFrame = newFirstFrame;
 		animDef.lastFrame = newLastFrame;
+
+		_scriptEnv.animChangeSet = false;
 	}
 }
 
@@ -5447,7 +5449,7 @@ void Runtime::scriptOpAnimS(ScriptArg_t arg) {
 
 	AnimationDef animDef = stackArgsToAnimDef(stackArgs + 0);
 
-	adjustUsingAnimChange(animDef);
+	consumeAnimChangeAndAdjustAnim(animDef);
 
 	// Static animations start on the last frame
 	changeAnimation(animDef, animDef.lastFrame, false);
@@ -5471,7 +5473,7 @@ void Runtime::scriptOpAnim(ScriptArg_t arg) {
 
 	AnimationDef animDef = stackArgsToAnimDef(stackArgs + 0);
 
-	adjustUsingAnimChange(animDef);
+	consumeAnimChangeAndAdjustAnim(animDef);
 
 	changeAnimation(animDef, animDef.firstFrame, true, _animSpeedDefault);
 
diff --git a/engines/vcruise/runtime.h b/engines/vcruise/runtime.h
index 03267d3b8be..743d50f3516 100644
--- a/engines/vcruise/runtime.h
+++ b/engines/vcruise/runtime.h
@@ -845,7 +845,7 @@ private:
 	void stopSubtitles();
 
 	AnimationDef stackArgsToAnimDef(const StackInt_t *args) const;
-	void adjustUsingAnimChange(AnimationDef &animDef) const;
+	void consumeAnimChangeAndAdjustAnim(AnimationDef &animDef);
 	void pushAnimDef(const AnimationDef &animDef);
 
 	void activateScript(const Common::SharedPtr<Script> &script, const ScriptEnvironmentVars &envVars);




More information about the Scummvm-git-logs mailing list