[Scummvm-git-logs] scummvm master -> 8ee6e1ce854b006fa01009014e122ec6cc0ae5e8

mduggan mgithub at guarana.org
Mon Nov 16 23:49:43 UTC 2020


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

Summary:
95273340d2 ULTIMA8: Fix some coverity issues
4c308804bf ULTIMA8: Pause surrender proc outside fast area
e0e7823100 ULTIMA8: Add intrinsic for playing crusader cutscene
8dfc5f64fc ULTIMA8: Pause music by default while playing AVIs
ebc1902f26 ULTIMA8: Avoid a potential null ptr deref
83b16362b8 ULTIMA8: Some improved animation flag support
a732d1de70 ULTIMA8: Fix small error in combat.dat decoding
584069c426 ULTIMA8: Small cleanups in heal/charge processes
bc24f8db3b ULTIMA8: Play correct selection failed noise in Regret
c9cba70a28 ULTIMA8: Add weapon info field for default ammo count
8ee6e1ce85 ULTIMA8: Remove manual trigger of mission1 egg


Commit: 95273340d2cd4a522bb4149e40704ceb5737bc7d
    https://github.com/scummvm/scummvm/commit/95273340d2cd4a522bb4149e40704ceb5737bc7d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:43:55+09:00

Commit Message:
ULTIMA8: Fix some coverity issues

Changed paths:
    engines/ultima/ultima8/world/actors/attack_process.cpp


diff --git a/engines/ultima/ultima8/world/actors/attack_process.cpp b/engines/ultima/ultima8/world/actors/attack_process.cpp
index 322b009d9f..2a2fc464d3 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.cpp
+++ b/engines/ultima/ultima8/world/actors/attack_process.cpp
@@ -75,12 +75,12 @@ static bool World_FinishedAvatarMoveTimeout() {
 
 
 static inline int32 randomOf(int32 max) {
-	return getRandom() % max;
+	return (max > 0 ? getRandom() % max : 0);
 }
 
 AttackProcess::AttackProcess() : Process(), _block(0), _target(1), _tactic(0), _tacticDat(nullptr),
 _tacticDatReadStream(nullptr), _tacticDatStartOffset(0), _soundNo(-1), _playedStartSound(false),
-_npcInitialDir(dir_invalid), _field57(0), _field59(0), _field7f(false), _field96(false),
+_npcInitialDir(dir_invalid), _field57(0), _field59(0), _field7f(false), _field96(false), _field97(false),
 _isActivity9orB(false), _isActivityAorB(false), _timer3set(false), _timer2set(false),
 _doubleDelay(false), _wpnField8(1), _wpnBasedTimeout(0), _difficultyBasedTimeout(0), _timer2(0),
 _timer3(0), _timer4(0), _timer5(0), _soundTimestamp(0), _fireTimestamp(0) {
@@ -91,7 +91,7 @@ _timer3(0), _timer4(0), _timer5(0), _soundTimestamp(0), _fireTimestamp(0) {
 
 AttackProcess::AttackProcess(Actor *actor) : _block(0), _target(1), _tactic(0), _tacticDat(nullptr),
 _tacticDatReadStream(nullptr), _tacticDatStartOffset(0), _soundNo(-1), _playedStartSound(false),
-_field57(0), _field59(0), _field7f(false), _field96(false), _isActivity9orB(false),
+_field57(0), _field59(0), _field7f(false), _field96(false), _field97(false), _isActivity9orB(false),
 _isActivityAorB(false), _timer3set(false), _timer2set(false), _doubleDelay(false), _wpnField8(1),
 _wpnBasedTimeout(0), _difficultyBasedTimeout(0), _timer2(0), _timer3(0), _timer4(0), _timer5(0),
 _soundTimestamp(0), _fireTimestamp(0) {
@@ -465,7 +465,10 @@ void AttackProcess::run() {
 		{
 			uint16 offset = readNextWordRaw();
 			uint16 val = getAttackData(offset);
-			setAttackData(opcode, val / readNextWordWithData());
+			uint16 divisor = readNextWordWithData();
+			if (!divisor)
+				divisor = 1; // shouldn't happen in real data, but just to be sure..
+			setAttackData(opcode, val / divisor);
 			return;
 		}
 		case 0xb4:


Commit: 4c308804bf8f6cb45110f6def93907d7db100add
    https://github.com/scummvm/scummvm/commit/4c308804bf8f6cb45110f6def93907d7db100add
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:43:55+09:00

Commit Message:
ULTIMA8: Pause surrender proc outside fast area

Changed paths:
    engines/ultima/ultima8/world/actors/surrender_process.cpp


diff --git a/engines/ultima/ultima8/world/actors/surrender_process.cpp b/engines/ultima/ultima8/world/actors/surrender_process.cpp
index d5a4291803..3d316e34e8 100644
--- a/engines/ultima/ultima8/world/actors/surrender_process.cpp
+++ b/engines/ultima/ultima8/world/actors/surrender_process.cpp
@@ -68,6 +68,10 @@ void SurrenderProcess::run() {
 		return;
 	}
 
+	// do nothing while we are not in the fast area
+	if (!a->hasFlags(Item::FLG_FASTAREA))
+		return;
+
 	int animating = Kernel::get_instance()->getNumProcesses(_itemNum, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
 	if (animating) {
 		// already busy.


Commit: e0e78231000150af226afdaf3d61b189066f8862
    https://github.com/scummvm/scummvm/commit/e0e78231000150af226afdaf3d61b189066f8862
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:43:55+09:00

Commit Message:
ULTIMA8: Add intrinsic for playing crusader cutscene

Changed paths:
    engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
    engines/ultima/ultima8/gumps/movie_gump.cpp
    engines/ultima/ultima8/gumps/movie_gump.h
    engines/ultima/ultima8/usecode/remorse_intrinsics.h


diff --git a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
index 71bab6143b..ca50c3e7c3 100644
--- a/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
+++ b/engines/ultima/ultima8/convert/crusader/convert_usecode_crusader.h
@@ -264,7 +264,7 @@ const char* const ConvertUsecodeCrusader::_intrinsics[] = {
 	// 00D0
 	"int16 Item::I_use(Item *)", // same coff as 080, 0D5
 	"void AudioProcess:I_stopAllSFX(void)", // based on disasm.
-	"void I_playFlic0D2(int *item,char *flicname,word sizex,word sizey)", // play flic
+	"void I_playMovieCutscene(int *item,char *flicname,word sizex,word sizey)", // play flic
 	"void Intrinsic0D3(void)", // clears some globals and calls a kernel function.. TODO: work out what those globals do?
 	"void I_playSFX(2 bytes)", // same coff as 0AA.  Based on disasm.
 	"int16 Item::I_use(Item *)", // same coff as 080, 0D0
diff --git a/engines/ultima/ultima8/gumps/movie_gump.cpp b/engines/ultima/ultima8/gumps/movie_gump.cpp
index 314552fb89..9457704fe9 100644
--- a/engines/ultima/ultima8/gumps/movie_gump.cpp
+++ b/engines/ultima/ultima8/gumps/movie_gump.cpp
@@ -191,5 +191,36 @@ uint32 MovieGump::I_playMovieOverlay(const uint8 *args,
 	return 0;
 }
 
+uint32 MovieGump::I_playMovieCutscene(const uint8 *args, unsigned int /*argsize*/) {
+	ARG_ITEM_FROM_PTR(item);
+	ARG_STRING(name);
+	ARG_UINT16(x);
+	ARG_UINT16(y);
+
+	FileSystem *filesys = FileSystem::get_instance();
+	if (item) {
+		const Std::string filename = Std::string::format("@game/flics/%s.avi", name.c_str());
+		Common::SeekableReadStream *rs = filesys->ReadFile(filename);
+		if (!rs) {
+			// Try with a "0" in the name
+			const Std::string adjustedfn = Std::string::format("@game/flics/0%s.avi", name.c_str());
+			rs = filesys->ReadFile(adjustedfn);
+			if (!rs) {
+				warning("I_playMovieCutscene: movie %s not found", name.c_str());
+				return 0;
+			}
+		}
+
+		// TODO: Support playback with gap lines for the CRT effect
+		Gump *gump = new MovieGump(x * 3, y * 3, rs, false);
+		gump->InitGump(nullptr, true);
+		gump->setRelativePosition(CENTER);
+	}
+
+	return 0;
+
+}
+
+
 } // End of namespace Ultima8
 } // End of namespace Ultima
diff --git a/engines/ultima/ultima8/gumps/movie_gump.h b/engines/ultima/ultima8/gumps/movie_gump.h
index c1fa2b39ec..43cf138f37 100644
--- a/engines/ultima/ultima8/gumps/movie_gump.h
+++ b/engines/ultima/ultima8/gumps/movie_gump.h
@@ -60,6 +60,7 @@ public:
 	void saveData(Common::WriteStream *ws) override;
 
 	INTRINSIC(I_playMovieOverlay);
+	INTRINSIC(I_playMovieCutscene);
 
 protected:
 	MoviePlayer *_player;
diff --git a/engines/ultima/ultima8/usecode/remorse_intrinsics.h b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
index 15138e0218..2a03054c04 100644
--- a/engines/ultima/ultima8/usecode/remorse_intrinsics.h
+++ b/engines/ultima/ultima8/usecode/remorse_intrinsics.h
@@ -258,7 +258,7 @@ Intrinsic RemorseIntrinsics[] = {
 	// 0x0D0
 	Item::I_use, // void Intrinsic0D0(4 bytes)
 	AudioProcess::I_stopAllSFX,
-	0, // void I_playFlic(int *item,char *flicname,word sizex,word sizey) // play flic
+	MovieGump::I_playMovieCutscene, // void I_playFlic(int *item,char *flicname,word sizex,word sizey) // play flic
 	0, // void Intrinsic0D3(void)
 	AudioProcess::I_playSFX, // void Intrinsic0D4(2 bytes)
 	Item::I_use, // void Intrinsic0D5(4 bytes)


Commit: 8dfc5f64fccbf0ee10db8c8ed756210f344c425c
    https://github.com/scummvm/scummvm/commit/8dfc5f64fccbf0ee10db8c8ed756210f344c425c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:43:55+09:00

Commit Message:
ULTIMA8: Pause music by default while playing AVIs

Changed paths:
    engines/ultima/ultima8/audio/music_process.h
    engines/ultima/ultima8/audio/remorse_music_process.cpp
    engines/ultima/ultima8/audio/remorse_music_process.h
    engines/ultima/ultima8/audio/u8_music_process.cpp
    engines/ultima/ultima8/audio/u8_music_process.h
    engines/ultima/ultima8/graphics/avi_player.cpp
    engines/ultima/ultima8/graphics/avi_player.h
    engines/ultima/ultima8/gumps/movie_gump.cpp


diff --git a/engines/ultima/ultima8/audio/music_process.h b/engines/ultima/ultima8/audio/music_process.h
index b938fefe7e..76d0736028 100644
--- a/engines/ultima/ultima8/audio/music_process.h
+++ b/engines/ultima/ultima8/audio/music_process.h
@@ -72,6 +72,14 @@ public:
 	//! Bring back the track state from before it was put on hold
 	virtual void restoreTrackState() = 0;
 
+	//! Is a track currently playing?
+	virtual bool isPlaying() = 0;
+
+	//! Pause the currently playing track
+	virtual void pauseMusic() = 0;
+	//! Resume the current track after pausing
+	virtual void unpauseMusic() = 0;
+
 	INTRINSIC(I_playMusic);
 	INTRINSIC(I_stopMusic);
 	INTRINSIC(I_pauseMusic);
diff --git a/engines/ultima/ultima8/audio/remorse_music_process.cpp b/engines/ultima/ultima8/audio/remorse_music_process.cpp
index d082e0e660..aeb39a4dcc 100644
--- a/engines/ultima/ultima8/audio/remorse_music_process.cpp
+++ b/engines/ultima/ultima8/audio/remorse_music_process.cpp
@@ -155,6 +155,7 @@ void RemorseMusicProcess::playMusic_internal(int track) {
 
 	mixer->stopHandle(_soundHandle);
 	_soundHandle = Audio::SoundHandle();
+	_currentTrack = track;
 
 	if (track > 0) {
 		// TODO: It's a bit ugly having this here.  Should be in GameData.
@@ -202,5 +203,26 @@ bool RemorseMusicProcess::loadData(Common::ReadStream *rs, uint32 version) {
 	return true;
 }
 
+bool RemorseMusicProcess::isPlaying() {
+	Audio::Mixer *mixer = Ultima8Engine::get_instance()->_mixer;
+	return _currentTrack != 0 && mixer && mixer->isSoundHandleActive(_soundHandle);
+}
+
+void RemorseMusicProcess::pauseMusic() {
+	Audio::Mixer *mixer = Ultima8Engine::get_instance()->_mixer;
+	assert(mixer);
+	if (mixer->isSoundHandleActive(_soundHandle))
+		mixer->pauseHandle(_soundHandle, true);
+}
+
+void RemorseMusicProcess::unpauseMusic() {
+	Audio::Mixer *mixer = Ultima8Engine::get_instance()->_mixer;
+	assert(mixer);
+	if (mixer->isSoundHandleActive(_soundHandle))
+		mixer->pauseHandle(_soundHandle, false);
+}
+
+
+
 } // End of namespace Ultima8
 } // End of namespace Ultima
diff --git a/engines/ultima/ultima8/audio/remorse_music_process.h b/engines/ultima/ultima8/audio/remorse_music_process.h
index 601a49bdd4..d8ea95cb8b 100644
--- a/engines/ultima/ultima8/audio/remorse_music_process.h
+++ b/engines/ultima/ultima8/audio/remorse_music_process.h
@@ -82,6 +82,14 @@ public:
 	//! Bring back the track state from before it was put on hold
 	void restoreTrackState() override;
 
+	//! Is a track currently playing?
+	bool isPlaying() override;
+
+	//! Pause the currently playing track
+	void pauseMusic() override;
+	//! Resume the current track after pausing
+	void unpauseMusic() override;
+
 	void run() override;
 
 	bool loadData(Common::ReadStream *rs, uint32 version);
diff --git a/engines/ultima/ultima8/audio/u8_music_process.cpp b/engines/ultima/ultima8/audio/u8_music_process.cpp
index 8b8b4e08c0..d76ad3be54 100644
--- a/engines/ultima/ultima8/audio/u8_music_process.cpp
+++ b/engines/ultima/ultima8/audio/u8_music_process.cpp
@@ -285,5 +285,20 @@ bool U8MusicProcess::loadData(Common::ReadStream *rs, uint32 version) {
 	return true;
 }
 
+bool U8MusicProcess::isPlaying() {
+	return _currentTrack != 0;
+}
+
+void U8MusicProcess::pauseMusic() {
+	// probably no real use for this?
+	warning("TODO: U8MusicProcess::pauseMusic Implement me.");
+}
+
+void U8MusicProcess::unpauseMusic() {
+	// probably no real use for this?
+	warning("TODO: U8MusicProcess::unpauseMusic Implement me.");
+}
+
+
 } // End of namespace Ultima8
 } // End of namespace Ultima
diff --git a/engines/ultima/ultima8/audio/u8_music_process.h b/engines/ultima/ultima8/audio/u8_music_process.h
index 5946f0e105..f4ddd0d8b7 100644
--- a/engines/ultima/ultima8/audio/u8_music_process.h
+++ b/engines/ultima/ultima8/audio/u8_music_process.h
@@ -113,6 +113,14 @@ public:
 
 	void setTrackState(const TrackState &state);
 
+	//! Is a track currently playing?
+	bool isPlaying() override;
+
+	//! Pause the currently playing track
+	void pauseMusic() override;
+	//! Resume the current track after pausing
+	void unpauseMusic() override;
+
 	void run() override;
 
 	bool loadData(Common::ReadStream *rs, uint32 version);
diff --git a/engines/ultima/ultima8/graphics/avi_player.cpp b/engines/ultima/ultima8/graphics/avi_player.cpp
index 5f55deb2a6..80596ec8e8 100644
--- a/engines/ultima/ultima8/graphics/avi_player.cpp
+++ b/engines/ultima/ultima8/graphics/avi_player.cpp
@@ -20,6 +20,7 @@
  *
  */
 
+#include "ultima/ultima8/audio/music_process.h"
 #include "ultima/ultima8/misc/pent_include.h"
 #include "ultima/ultima8/graphics/avi_player.h"
 #include "ultima/ultima8/graphics/render_surface.h"
@@ -35,7 +36,7 @@ namespace Ultima8 {
 
 AVIPlayer::AVIPlayer(Common::SeekableReadStream *rs, int width, int height, const byte *overridePal)
 	: MoviePlayer(), _playing(false), _width(width), _height(height),
-	  _doubleSize(false), _overridePal(overridePal) {
+	  _doubleSize(false), _pausedMusic(false), _overridePal(overridePal) {
 	_decoder = new Video::AVIDecoder();
 	_decoder->loadStream(rs);
 	uint32 vidWidth = _decoder->getWidth();
@@ -54,11 +55,23 @@ AVIPlayer::~AVIPlayer() {
 }
 
 void AVIPlayer::start() {
+	MusicProcess *music = MusicProcess::get_instance();
+	if (music && music->isPlaying()) {
+		music->pauseMusic();
+		_pausedMusic = true;
+	}
+
 	_playing = true;
 	_decoder->start();
 }
 
 void AVIPlayer::stop() {
+	MusicProcess *music = MusicProcess::get_instance();
+	if (music && _pausedMusic) {
+		music->unpauseMusic();
+		_pausedMusic = false;
+	}
+
 	_playing = false;
 	_decoder->stop();
 }
diff --git a/engines/ultima/ultima8/graphics/avi_player.h b/engines/ultima/ultima8/graphics/avi_player.h
index 0c73d864e8..6a090b90ae 100644
--- a/engines/ultima/ultima8/graphics/avi_player.h
+++ b/engines/ultima/ultima8/graphics/avi_player.h
@@ -61,6 +61,7 @@ private:
 	uint32 _yoff;
 	bool _doubleSize;
 	const byte *_overridePal;
+	bool _pausedMusic;
 
 };
 
diff --git a/engines/ultima/ultima8/gumps/movie_gump.cpp b/engines/ultima/ultima8/gumps/movie_gump.cpp
index 9457704fe9..01c1745dd1 100644
--- a/engines/ultima/ultima8/gumps/movie_gump.cpp
+++ b/engines/ultima/ultima8/gumps/movie_gump.cpp
@@ -77,6 +77,8 @@ void MovieGump::InitGump(Gump *newparent, bool take_focus) {
 void MovieGump::Close(bool no_del) {
 	Mouse::get_instance()->popMouseCursor();
 
+	_player->stop();
+
 	ModalGump::Close(no_del);
 }
 


Commit: ebc1902f26ae41d40edf8366ff2886262aa2b0bb
    https://github.com/scummvm/scummvm/commit/ebc1902f26ae41d40edf8366ff2886262aa2b0bb
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:43:55+09:00

Commit Message:
ULTIMA8: Avoid a potential null ptr deref

Changed paths:
    engines/ultima/ultima8/graphics/anim_dat.cpp


diff --git a/engines/ultima/ultima8/graphics/anim_dat.cpp b/engines/ultima/ultima8/graphics/anim_dat.cpp
index 10a8c9f8da..d254949519 100644
--- a/engines/ultima/ultima8/graphics/anim_dat.cpp
+++ b/engines/ultima/ultima8/graphics/anim_dat.cpp
@@ -69,7 +69,7 @@ uint32 AnimDat::getActionNumberForSequence(Animation::Sequence action, const Act
 		bool isavatar = (actor && actor->getShape() == 1);
 		if (isavatar && actor->getActiveWeapon()) {
 			const Item *wpn = getItem(actor->getActiveWeapon());
-			const ShapeInfo *shapeinfo = wpn->getShapeInfo();
+			const ShapeInfo *shapeinfo = (wpn ? wpn->getShapeInfo() : nullptr);
 			const WeaponInfo *wpninfo = (shapeinfo ? shapeinfo->_weaponInfo : nullptr);
 			smallwpn = (wpninfo && wpninfo->_small);
 			altfire = (wpninfo && (wpninfo->_overlayShape == 0x36e || wpninfo->_overlayShape == 0x33b));


Commit: 83b16362b86b506b4c6e43991b5187c94c2dacf2
    https://github.com/scummvm/scummvm/commit/83b16362b86b506b4c6e43991b5187c94c2dacf2
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:43:55+09:00

Commit Message:
ULTIMA8: Some improved animation flag support

Changed paths:
    engines/ultima/ultima8/graphics/anim_dat.cpp
    engines/ultima/ultima8/world/actors/actor.cpp
    engines/ultima/ultima8/world/actors/actor.h
    engines/ultima/ultima8/world/actors/actor_anim_process.cpp
    engines/ultima/ultima8/world/actors/anim_action.h
    engines/ultima/ultima8/world/actors/animation.h


diff --git a/engines/ultima/ultima8/graphics/anim_dat.cpp b/engines/ultima/ultima8/graphics/anim_dat.cpp
index d254949519..1fc728f0e7 100644
--- a/engines/ultima/ultima8/graphics/anim_dat.cpp
+++ b/engines/ultima/ultima8/graphics/anim_dat.cpp
@@ -181,10 +181,14 @@ void AnimDat::load(Common::SeekableReadStream *rs) {
 			a->_actions[action]->_action = action;
 
 			rs->seek(actionoffset);
+			// byte 0: action size
 			uint32 actionsize = rs->readByte();
 			a->_actions[action]->_size = actionsize;
+			// byte 1: flags low byte
 			a->_actions[action]->_flags = rs->readByte();
+			// byte 2: frame repeat
 			a->_actions[action]->_frameRepeat = rs->readByte();
+			// byte 3: flags high byte
 			a->_actions[action]->_flags |= rs->readByte() << 8;
 
 			unsigned int dirCount = 8;
@@ -192,6 +196,14 @@ void AnimDat::load(Common::SeekableReadStream *rs) {
 			        (a->_actions[action]->_flags & AnimAction::AAF_CRUS_16DIRS)) {
 				dirCount = 16;
 			}
+
+			/*
+			if (a->_actions[action]->_flags & AnimAction::AAF_UNKFLAGS) {
+				warning("AnimFlags: shape %d action %d has unknown flags %04X", shape, action,
+					  a->_actions[action]->_flags & AnimAction::AAF_UNKFLAGS);
+			}
+			*/
+
 			a->_actions[action]->_dirCount = dirCount;
 
 			for (unsigned int dir = 0; dir < dirCount; dir++) {
@@ -207,13 +219,11 @@ void AnimDat::load(Common::SeekableReadStream *rs) {
 						f._deltaDir = rs->readSByte();
 						f._flags = rs->readByte();
 						f._flags += (x & 0xF8) << 8;
-						f._unk1 = 0;
-						f._unk2 = 0;
 					} else if (GAME_IS_CRUSADER) {
 						// byte 0: low byte of frame
 						f._frame = rs->readByte();
-						// byte 1: low nibble part of frame
-						uint8 x = rs->readByte();
+						// byte 1: low nibble is high part of frame, high nibble is flags (used later)
+						const uint8 x = rs->readByte();
 						f._frame += (x & 0xF) << 8;
 						// byte 2: delta z
 						f._deltaZ = rs->readByte();
@@ -221,11 +231,20 @@ void AnimDat::load(Common::SeekableReadStream *rs) {
 						f._sfx = rs->readByte();
 						// byte 4: deltadir (signed) - convert to pixels
 						f._deltaDir = rs->readSByte();
-						// byte 5: flags? TODO: Ensure "flipped" flag is mapped correctly
+						// byte 5: flags TODO: Ensure "flipped" flag is mapped correctly
 						f._flags = rs->readByte();
 						f._flags += (x & 0xF0) << 8;
-						// byte 6, 7: unknown
-						f._unk2 = rs->readSint16LE();
+						// bytes 6, 7: more flags
+						f._flags += rs->readUint16LE() << 16;
+
+						// Map the "flipped" flag to match U8.. is this right?
+						//if (f._flags & AnimFrame::AFF_CRUFLIP)
+						//	f._flags |= AnimFrame::AFF_FLIPPED;
+
+						/*if (f._flags & AnimFrame::AFF_UNKNOWN) {
+							warning("AnimFlags: shape %d action %d dir %d frame %d has unknown flags %08X", shape, action, dir, j,
+									f._flags & AnimFrame::AFF_UNKNOWN);
+						}*/
 					}
 					a->_actions[action]->_frames[dir].push_back(f);
 				}
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 1caa6cc757..1f36c6385d 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -908,6 +908,59 @@ void Actor::receiveHitCru(uint16 other, Direction dir, int damage, uint16 damage
 	}
 }
 
+void Actor::tookHitCru() {
+	Animation::Sequence lastanim = getLastAnim();
+	if ((lastanim == Animation::unknownAnim30) || (lastanim == Animation::startRunWithLargeWeapon)) {
+		//uint16 controllednpc = World::get_instance()->getControlledNPCNum();
+		bool canseecontrolled = true; //this->canSee(controllednpc);
+		if (canseecontrolled) {
+			if (getRandom() % 4)
+				setActivity(5);
+			else
+				setActivity(10);
+		}
+	} else {
+		uint32 shape = getShape();
+		if (shape != 0x576) { // 0x576 = flaming guy
+			if (shape < 0x577) {
+				if (shape == 0x385 || shape == 0x4e6) {
+				   explode(2, 0);
+				   clearFlag(FLG_IN_NPC_LIST);
+				   clearFlag(FLG_GUMP_OPEN);
+			   }
+			   return;
+		   }
+		   if (shape != 0x596) {
+			   return;
+		   }
+		}
+
+		bool violence = true; // Game::I_isViolenceEnabled
+		if (!violence)
+			return;
+
+		static const uint16 FEMALE_SCREAMS[] = {0xb, 0xa};
+		static const uint16 MALE_SCREAMS[] = {0x65, 0x66, 0x67};
+		int nsounds;
+		const uint16 *sounds;
+		if (hasExtFlags(EXT_FEMALE)) {
+			nsounds = ARRAYSIZE(FEMALE_SCREAMS);
+			sounds = FEMALE_SCREAMS;
+		} else {
+			nsounds = ARRAYSIZE(MALE_SCREAMS);
+			sounds = MALE_SCREAMS;
+		}
+		AudioProcess *audio = AudioProcess::get_instance();
+		if (!audio)
+			return;
+		for (int i = 0; i < nsounds; i++) {
+			if (audio->isSFXPlayingForObject(sounds[i], _objId))
+				return;
+		}
+		audio->playSFX(sounds[getRandom() % nsounds], 0x80, _objId, 1);
+	}
+}
+
 void Actor::receiveHitU8(uint16 other, Direction dir, int damage, uint16 damage_type) {
 	if (isDead())
 		return; // already dead, so don't bother
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 2d69f44847..eb9e1f56ef 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -280,6 +280,9 @@ public:
 
 	bool activeWeaponIsSmall() const;
 
+	// A cru-specific behavior - mostly make "ugh" noises, or explode for some robots.
+	void tookHitCru();
+
 	ENABLE_RUNTIME_CLASSTYPE()
 
 	INTRINSIC(I_isNPC);
diff --git a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
index 9e4a0ad59a..49258ea8c2 100644
--- a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
@@ -260,11 +260,15 @@ void ActorAnimProcess::run() {
 			if (audioproc) audioproc->playSFX(curframe->_sfx, 0x60, _itemNum, 0);
 		}
 
-		if (curframe && (curframe->_flags & AnimFrame::AFF_SPECIAL)) {
-			// Flag to trigger a special _action
-			// E.g.: play draw/sheathe SFX for avatar when weapon equipped,
-			// throw skull-fireball when ghost attacks, ...
-			doSpecial();
+		if (curframe) {
+			if (curframe->_flags & AnimFrame::AFF_SPECIAL) {
+				// Flag to trigger a special action
+				// E.g.: play draw/sheathe SFX for avatar when weapon equipped,
+				// throw skull-fireball when ghost attacks, ...
+				doSpecial();
+			} else if (curframe->_flags & AnimFrame::AFF_HURTY) {
+				a->tookHitCru();
+			}
 		}
 
 
diff --git a/engines/ultima/ultima8/world/actors/anim_action.h b/engines/ultima/ultima8/world/actors/anim_action.h
index 676a1a30c4..967e0ea8bd 100644
--- a/engines/ultima/ultima8/world/actors/anim_action.h
+++ b/engines/ultima/ultima8/world/actors/anim_action.h
@@ -36,16 +36,19 @@ struct AnimFrame {
 	int _deltaZ;
 	int _deltaDir;
 	int _sfx;
-	uint16 _unk1;
-	uint16 _unk2;
 	uint32 _flags;
 
 	enum AnimFrameFlags {
-		AFF_UNK1     = 0x0001,
-		AFF_ONGROUND = 0x0002,
-		AFF_FLIPPED  = 0x0020,
-		AFF_SPECIAL  = 0x0800,
-		AFF_USECODE  = 0x4000
+		AFF_UNK1     = 0x00000001,
+		AFF_ONGROUND = 0x00000002,
+		AFF_FLIPPED  = 0x00000020,
+		AFF_CRUFLIP  = 0x00000080,
+		AFF_SPECIAL  = 0x00000800, // U8 only
+		AFF_HURTY    = 0x00001000, // Crusader only - TODO: find a better name for this.
+		AFF_USECODE  = 0x00004000,
+		AFF_NOSTOP   = 0x00008000, // Crusader only - Probably - applied to most death animations
+		//AFF_UNKNOWN  = 0xF0E0B01C,
+		//AFF_FIRE     = 0x0F1F00C0
 	};
 
 	inline bool is_flipped() const {
@@ -117,7 +120,8 @@ public:
 		AAF_LOOPING2     = 0x0010, // CHECKME: guessing at this flag
 		AAF_HANGING      = 0x0080,
 		AAF_CRUS_16DIRS  = 0x4000, // Crusader
-		AAF_DESTROYACTOR = 0x8000  // destroy actor after animation finishes
+		AAF_DESTROYACTOR = 0x8000, // destroy actor after animation finishes
+		AAF_UNKFLAGS     = 0x3F60
 	};
 
 private:
diff --git a/engines/ultima/ultima8/world/actors/animation.h b/engines/ultima/ultima8/world/actors/animation.h
index 628b43d02d..9b9ba3feb7 100644
--- a/engines/ultima/ultima8/world/actors/animation.h
+++ b/engines/ultima/ultima8/world/actors/animation.h
@@ -102,6 +102,7 @@ enum Sequence {
 	kneelAndFire = 26,
 	slideLeft = 28,
 	slideRight = 29,
+	unknownAnim30 = 30,
 	startRunWithLargeWeapon = 31,
 	teleportIn = 32,
 	teleportOut = 33,


Commit: a732d1de700f18b73871b45ace8d15ba7c4144b2
    https://github.com/scummvm/scummvm/commit/a732d1de700f18b73871b45ace8d15ba7c4144b2
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:47:57+09:00

Commit Message:
ULTIMA8: Fix small error in combat.dat decoding

Changed paths:
    engines/ultima/ultima8/world/actors/attack_process.cpp


diff --git a/engines/ultima/ultima8/world/actors/attack_process.cpp b/engines/ultima/ultima8/world/actors/attack_process.cpp
index 2a2fc464d3..83871801af 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.cpp
+++ b/engines/ultima/ultima8/world/actors/attack_process.cpp
@@ -468,7 +468,7 @@ void AttackProcess::run() {
 			uint16 divisor = readNextWordWithData();
 			if (!divisor)
 				divisor = 1; // shouldn't happen in real data, but just to be sure..
-			setAttackData(opcode, val / divisor);
+			setAttackData(offset, val / divisor);
 			return;
 		}
 		case 0xb4:


Commit: 584069c42642b8843753866c4bf2b6750b171a99
    https://github.com/scummvm/scummvm/commit/584069c42642b8843753866c4bf2b6750b171a99
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:48:05+09:00

Commit Message:
ULTIMA8: Small cleanups in heal/charge processes

Changed paths:
    engines/ultima/ultima8/world/actors/battery_charger_process.cpp
    engines/ultima/ultima8/world/actors/cru_healer_process.cpp


diff --git a/engines/ultima/ultima8/world/actors/battery_charger_process.cpp b/engines/ultima/ultima8/world/actors/battery_charger_process.cpp
index 45da4260dc..be096080b3 100644
--- a/engines/ultima/ultima8/world/actors/battery_charger_process.cpp
+++ b/engines/ultima/ultima8/world/actors/battery_charger_process.cpp
@@ -25,6 +25,7 @@
 #include "ultima/ultima8/world/actors/main_actor.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/world/get_object.h"
+#include "ultima/ultima8/world/world.h"
 #include "ultima/ultima8/audio/audio_process.h"
 
 #include "common/util.h"
@@ -35,9 +36,12 @@ namespace Ultima8 {
 // p_dynamic_cast stuff
 DEFINE_RUNTIME_CLASSTYPE_CODE(BatteryChargerProcess)
 
+// These SFX IDs are the same in both No Regret and No Remorse.
+static const uint16 CHARGE_START_SFX = 0xa4;
+static const uint16 CHARGE_GOING_SFX = 0x10b;
+
 BatteryChargerProcess::BatteryChargerProcess() : Process() {
-	// TODO: This should be the "current" avatar (if controlling a robot etc)
-	MainActor *avatar = getMainActor();
+	MainActor *avatar = dynamic_cast<MainActor *>(getActor(World::get_instance()->getControlledNPCNum()));
 	if (!avatar) {
 		_itemNum = 0;
 		_targetMaxEnergy = 0;
@@ -46,27 +50,26 @@ BatteryChargerProcess::BatteryChargerProcess() : Process() {
 		_targetMaxEnergy = avatar->getMaxEnergy();
 		AudioProcess *audio = AudioProcess::get_instance();
 		if (audio) {
-			audio->playSFX(0xa4, 0x80, _itemNum, 1, false);
+			audio->playSFX(CHARGE_START_SFX, 0x80, _itemNum, 1, false);
 		}
 	}
 	_type = 0x254; // CONSTANT!
 }
 
 void BatteryChargerProcess::run() {
-	// TODO: This should be the "current" avatar (if controlling a robot etc)
-	MainActor *avatar = getMainActor();
+	MainActor *avatar = dynamic_cast<MainActor *>(getActor(World::get_instance()->getControlledNPCNum()));
 	AudioProcess *audio = AudioProcess::get_instance();
 
 	if (!avatar || avatar->isDead() || avatar->getMana() >= _targetMaxEnergy) {
-		// dead or finished healing
+		// dead or finished healing or switched to robot
 		terminate();
 		if (audio)
-			audio->stopSFX(0xa4, _itemNum);
+			audio->stopSFX(CHARGE_START_SFX, _itemNum);
 		return;
 	}
 
-    if (!audio->isSFXPlayingForObject(0x10b, _itemNum))
-		audio->playSFX(0x10b, 0x80, _itemNum, 1);
+    if (!audio->isSFXPlayingForObject(CHARGE_GOING_SFX, _itemNum))
+		audio->playSFX(CHARGE_GOING_SFX, 0x80, _itemNum, 1);
 
 	uint16 newEnergy = avatar->getMana() + 25;
 	if (newEnergy > _targetMaxEnergy)
diff --git a/engines/ultima/ultima8/world/actors/cru_healer_process.cpp b/engines/ultima/ultima8/world/actors/cru_healer_process.cpp
index fdb9ddaca7..6c451b1726 100644
--- a/engines/ultima/ultima8/world/actors/cru_healer_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_healer_process.cpp
@@ -25,6 +25,7 @@
 #include "ultima/ultima8/world/actors/main_actor.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/world/get_object.h"
+#include "ultima/ultima8/world/world.h"
 #include "ultima/ultima8/ultima8.h"
 #include "ultima/ultima8/audio/audio_process.h"
 
@@ -33,12 +34,16 @@
 namespace Ultima {
 namespace Ultima8 {
 
+
+// These SFX IDs are the same in both No Regret and No Remorse.
+static const uint16 HEAL_START_SFX = 0xdb;
+static const uint16 HEAL_GOING_SFX = 0xba;
+
 // p_dynamic_cast stuff
 DEFINE_RUNTIME_CLASSTYPE_CODE(CruHealerProcess)
 
 CruHealerProcess::CruHealerProcess() : Process() {
-	// TODO: This should be the "current" avatar (if controlling a robot etc)
-	MainActor *avatar = getMainActor();
+	MainActor *avatar = dynamic_cast<MainActor *>(getActor(World::get_instance()->getControlledNPCNum()));
 	if (!avatar) {
 		_itemNum = 0;
 		_targetMaxHP = 0;
@@ -48,7 +53,7 @@ CruHealerProcess::CruHealerProcess() : Process() {
 		AudioProcess *audio = AudioProcess::get_instance();
 		if (audio) {
 			// Sound num is the same in both No Remorse and No Regret
-			audio->playSFX(0xdb, 0x80, _itemNum, 1, false);
+			audio->playSFX(HEAL_START_SFX, 0x80, _itemNum, 1, false);
 		}
 	}
 	Ultima8Engine::get_instance()->setAvatarInStasis(true);
@@ -56,8 +61,7 @@ CruHealerProcess::CruHealerProcess() : Process() {
 }
 
 void CruHealerProcess::run() {
-	// TODO: This should be the "current" avatar (if controlling a robot etc)
-	MainActor *avatar = getMainActor();
+	MainActor *avatar = dynamic_cast<MainActor *>(getActor(World::get_instance()->getControlledNPCNum()));
 	AudioProcess *audio = AudioProcess::get_instance();
 
 	if (!avatar || avatar->isDead() || avatar->getHP() >= _targetMaxHP) {
@@ -66,13 +70,13 @@ void CruHealerProcess::run() {
 		}
 		// dead or finished healing
 		if (audio)
-			audio->stopSFX(0xdb, _itemNum);
+			audio->stopSFX(HEAL_START_SFX, _itemNum);
 		terminate();
 		return;
 	}
 
-    if (audio && !audio->isSFXPlayingForObject(0xba, _itemNum))
-		audio->playSFX(0xba, 0x80, _itemNum, 1);
+    if (audio && !audio->isSFXPlayingForObject(HEAL_GOING_SFX, _itemNum))
+		audio->playSFX(HEAL_GOING_SFX, 0x80, _itemNum, 1);
 
 	uint16 newHP = avatar->getHP() + 1;
 	if (newHP > _targetMaxHP)


Commit: bc24f8db3b0cceb595a9793020248883ca75fd8f
    https://github.com/scummvm/scummvm/commit/bc24f8db3b0cceb595a9793020248883ca75fd8f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:48:05+09:00

Commit Message:
ULTIMA8: Play correct selection failed noise in Regret

Changed paths:
    engines/ultima/ultima8/world/item_selection_process.cpp


diff --git a/engines/ultima/ultima8/world/item_selection_process.cpp b/engines/ultima/ultima8/world/item_selection_process.cpp
index 2856d80c8d..e066d7cebe 100644
--- a/engines/ultima/ultima8/world/item_selection_process.cpp
+++ b/engines/ultima/ultima8/world/item_selection_process.cpp
@@ -24,6 +24,7 @@
 
 #include "ultima/ultima8/games/game_data.h"
 #include "ultima/ultima8/audio/audio_process.h"
+#include "ultima/ultima8/kernel/core_app.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/world/actors/main_actor.h"
 #include "ultima/ultima8/world/item_selection_process.h"
@@ -42,7 +43,8 @@ namespace Ultima8 {
 ItemSelectionProcess *ItemSelectionProcess::_instance = nullptr;
 
 static const uint32 SELECTOR_SHAPE = 0x5a3;
-static const uint16 SELECTION_FAILED_SOUND = 0xb0;
+static const uint16 SELECT_FAILED_SFX_REMORSE = 0xb0;
+static const uint16 SELECT_FAILED_SFX_REGRET = 0x1a7;
 
 // p_dynamic_cast stuff
 DEFINE_RUNTIME_CLASSTYPE_CODE(ItemSelectionProcess)
@@ -102,7 +104,9 @@ bool ItemSelectionProcess::selectNextItem() {
 		AudioProcess *audio = AudioProcess::get_instance();
 		assert(audio);
 		// Play the "beeboop" selection failed sound.
-		audio->playSFX(SELECTION_FAILED_SOUND, 0x10, 0, 1);
+		uint16 sfxno = GAME_IS_REGRET ? SELECT_FAILED_SFX_REGRET : SELECT_FAILED_SFX_REMORSE;
+		if (!audio->isSFXPlaying(sfxno))
+			audio->playSFX(sfxno, 0x10, 0, 1);
 		clearSelection();
 		return false;
 	}


Commit: c9cba70a28a96a4e69a02bc64c6e7ce70ead1ac1
    https://github.com/scummvm/scummvm/commit/c9cba70a28a96a4e69a02bc64c6e7ce70ead1ac1
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:48:05+09:00

Commit Message:
ULTIMA8: Add weapon info field for default ammo count

Changed paths:
    engines/ultima/ultima8/graphics/type_flags.cpp
    engines/ultima/ultima8/world/item_factory.cpp
    engines/ultima/ultima8/world/weapon_info.h


diff --git a/engines/ultima/ultima8/graphics/type_flags.cpp b/engines/ultima/ultima8/graphics/type_flags.cpp
index 6916a647a0..039f48cb39 100644
--- a/engines/ultima/ultima8/graphics/type_flags.cpp
+++ b/engines/ultima/ultima8/graphics/type_flags.cpp
@@ -267,6 +267,9 @@ void TypeFlags::loadWeaponInfo() {
 		else
 			wi->_small = 0;
 
+		// TODO: get from real data.
+		wi->_defaultAmmo = 37;
+
 		// TODO: this should be 1, 2, or 3 depending on weapon.
 		// It's used in the AttackProcess
 		wi->_field8 = 1;
diff --git a/engines/ultima/ultima8/world/item_factory.cpp b/engines/ultima/ultima8/world/item_factory.cpp
index 7a11f7897d..c2fc0c7319 100644
--- a/engines/ultima/ultima8/world/item_factory.cpp
+++ b/engines/ultima/ultima8/world/item_factory.cpp
@@ -107,6 +107,14 @@ Item *ItemFactory::createItem(uint32 shape, uint32 frame, uint16 quality,
 			if (info->_damageInfo && info->_damageInfo->takesDamage()) {
 				item->setDamagePoints(info->_damageInfo->damagePoints());
 			}
+			if (info->_family == ShapeInfo::SF_CRUWEAPON && info->_weaponInfo &&
+				info->_weaponInfo->_defaultAmmo) {
+				item->setQuality(info->_weaponInfo->_defaultAmmo);
+			}
+			if (info->_family == ShapeInfo::SF_CRUAMMO ||
+					 info->_family == ShapeInfo::SF_CRUBOMB) {
+				item->setQuality(1);
+			}
 		}
 	}
 
diff --git a/engines/ultima/ultima8/world/weapon_info.h b/engines/ultima/ultima8/world/weapon_info.h
index a69220358d..985e23ab8a 100644
--- a/engines/ultima/ultima8/world/weapon_info.h
+++ b/engines/ultima/ultima8/world/weapon_info.h
@@ -48,6 +48,7 @@ struct WeaponInfo {
 	uint16 _displayGumpShape; //! The gump shape to use for inventory display (3,4,5)
 	uint16 _displayGumpFrame; //!< The frame to use in the inventory gump
 	uint8 _small;	//! A flag whether or not the weapon is "small" (changes the animations used)
+	uint16 _defaultAmmo; //! Count of ammo the weapon starts with
 	uint8 _field8;	//! Not totally sure, used like "cycle time" in Attack Process
 
 	enum DmgType {


Commit: 8ee6e1ce854b006fa01009014e122ec6cc0ae5e8
    https://github.com/scummvm/scummvm/commit/8ee6e1ce854b006fa01009014e122ec6cc0ae5e8
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-11-17T08:48:34+09:00

Commit Message:
ULTIMA8: Remove manual trigger of mission1 egg

This works automatically now that the unkegg offsets are fixed.

Changed paths:
    engines/ultima/ultima8/games/start_crusader_process.cpp


diff --git a/engines/ultima/ultima8/games/start_crusader_process.cpp b/engines/ultima/ultima8/games/start_crusader_process.cpp
index 4d3c51c42d..02433e2fae 100644
--- a/engines/ultima/ultima8/games/start_crusader_process.cpp
+++ b/engines/ultima/ultima8/games/start_crusader_process.cpp
@@ -102,13 +102,6 @@ void StartCrusaderProcess::run() {
 			Item *smiley = ItemFactory::createItem(0x598, 0, 0, 0, 0, mapnum, 0, true);
 			smiley->moveToContainer(avatar);
 
-			// TODO: How is this created in the game??
-			Egg *miss1egg = new Egg();
-			miss1egg->setShape(2317);
-			miss1egg->setMapNum(mapnum);
-			miss1egg->assignObjId();
-			miss1egg->callUsecodeEvent_hatch();
-
 			avatar->setDir(dir_east);
 		} else if (GAME_IS_REGRET) {
 			// TODO: Give the appropriate startup objects to the avatar




More information about the Scummvm-git-logs mailing list