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

mduggan mgithub at guarana.org
Sun May 9 04:11:28 UTC 2021


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

Summary:
531ed6865b ULTIMA8: Add comment about iteration order
f5c4374888 ULTIMA8: Refactor so all Crusader movies get subtitles
d83ccb7e9b ULTIMA8: Default to no mouse cursor in Crusader
cf085788c2 ULTIMA8: Add Crusader key for using energy cube
137fa8ea29 ULTIMA8: Implement 'grab' operation for Crusader games
bda1466e0a ULTIMA8: Fix Crusader items reappearing after exploding
26f936510f ULTIMA8: Implement "cruStasis", stops some key events
6f5538ab4d ULTIMA8: Fix actor anim speed in Crusader
cf7ae46475 ULTIMA8: Adjust Crusader step tests to match original


Commit: 531ed6865b6d73da53791a5a70b3cb4720659153
    https://github.com/scummvm/scummvm/commit/531ed6865b6d73da53791a5a70b3cb4720659153
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T07:31:43+09:00

Commit Message:
ULTIMA8: Add comment about iteration order

This function looks tempting to "optimize", by changing the order, so add a
warning for new adventurers.

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


diff --git a/engines/ultima/ultima8/world/current_map.cpp b/engines/ultima/ultima8/world/current_map.cpp
index 20bcc75a6f..3c2a3a2afd 100644
--- a/engines/ultima/ultima8/world/current_map.cpp
+++ b/engines/ultima/ultima8/world/current_map.cpp
@@ -572,6 +572,15 @@ void CurrentMap::areaSearch(UCList *itemlist, const uint8 *loopscript,
 	int maxy = ((y + range) / _mapChunkSize) + 1;
 	clipMapChunks(minx, maxx, miny, maxy);
 
+	//
+	// NOTE: Iteration order of chunks here is important for
+	// usecode compatibility!
+	//
+	// eg, No Remorse Mission 2 has a camera which searches for
+	// trigger with qlo = 5, but there are 2 of those on the map.
+	// We need to return in the correct order or it triggers
+	// the wrong one and breaks the game.
+	//
 	for (int cy = miny; cy <= maxy; cy++) {
 		for (int cx = minx; cx <= maxx; cx++) {
 			item_list::const_iterator iter;


Commit: f5c43748889c08015bfd03b060c09babb5b03e85
    https://github.com/scummvm/scummvm/commit/f5c43748889c08015bfd03b060c09babb5b03e85
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T07:31:43+09:00

Commit Message:
ULTIMA8: Refactor so all Crusader movies get subtitles

Previously there was a bit of duplication, and Weasel and the intro movies
didn't get subtitles.  Cleaned up the code a bit and now all are treated
consistently.

Changed paths:
    engines/ultima/ultima8/games/remorse_game.cpp
    engines/ultima/ultima8/gumps/movie_gump.cpp
    engines/ultima/ultima8/gumps/movie_gump.h
    engines/ultima/ultima8/gumps/weasel_gump.cpp


diff --git a/engines/ultima/ultima8/games/remorse_game.cpp b/engines/ultima/ultima8/games/remorse_game.cpp
index f9028447f5..676f67f2b8 100644
--- a/engines/ultima/ultima8/games/remorse_game.cpp
+++ b/engines/ultima/ultima8/games/remorse_game.cpp
@@ -28,6 +28,7 @@
 #include "ultima/ultima8/filesys/file_system.h"
 #include "ultima/ultima8/graphics/palette_manager.h"
 #include "ultima/ultima8/gumps/movie_gump.h"
+#include "ultima/ultima8/gumps/gump_notify_process.h"
 #include "ultima/ultima8/kernel/object_manager.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/world/world.h"
@@ -149,15 +150,13 @@ bool RemorseGame::startInitialUsecode(int saveSlot) {
 
 
 static ProcId playMovie(const char *movieID, bool fade, bool noScale) {
-	const Std::string filename = Std::string::format("flics/%s.avi", movieID);
-	FileSystem *filesys = FileSystem::get_instance();
-	Common::SeekableReadStream *rs = filesys->ReadFile(filename);
-	if (!rs) {
-		pout << "RemorseGame::playIntro: movie not found." << Std::endl;
+	MovieGump *gump = MovieGump::CruMovieViewer(movieID, 640, 480, nullptr, nullptr);
+	if (!gump) {
+		pout << "RemorseGame::playIntro: movie " << movieID << " not found." << Std::endl;
 		return 0;
 	}
-	// TODO: Add support for subtitles (.txt file).  The format is very simple.
-	return MovieGump::U8MovieViewer(rs, fade, false, noScale);
+	gump->CreateNotifier();
+	return gump->GetNotifyProcess()->getPid();
 }
 
 ProcId RemorseGame::playIntroMovie(bool fade) {
diff --git a/engines/ultima/ultima8/gumps/movie_gump.cpp b/engines/ultima/ultima8/gumps/movie_gump.cpp
index 0b2cd77246..be5e869d51 100644
--- a/engines/ultima/ultima8/gumps/movie_gump.cpp
+++ b/engines/ultima/ultima8/gumps/movie_gump.cpp
@@ -40,6 +40,60 @@
 namespace Ultima {
 namespace Ultima8 {
 
+static Std::string _fixCrusaderMovieName(const Std::string &s) {
+	/*
+	 HACK! The game comes with movies MVA01.AVI etc, but the usecode mentions both
+	 MVA01 and MVA1.  We do a translation here.	 These are the strings we need to fix:
+	 008E: 0D	push string	"mva1"
+	 036D: 0D	push string	"mva3a"
+	 04E3: 0D	push string	"mva4"
+	 0656: 0D	push string	"mva5a"
+	 07BD: 0D	push string	"mva6"
+	 0944: 0D	push string	"mva7"
+	 0A68: 0D	push string	"mva8"
+	 0B52: 0D	push string	"mva9"
+	*/
+	if (s.size() == 4)
+		return Std::string::format("mva0%c", s[3]);
+	else if (s.equals("mva3a"))
+		return "mva03a";
+	else if (s.equals("mva5a"))
+		return "mva05a";
+
+	return s;
+}
+
+static Common::SeekableReadStream *_tryLoadCruMovieFile(const Std::string &filename, const char *extn) {
+	const Std::string path = Std::string::format("flics/%s.%s", filename.c_str(), extn);
+	FileSystem *filesys = FileSystem::get_instance();
+	Common::SeekableReadStream *rs = filesys->ReadFile(path);
+	if (!rs) {
+		// Try with a "0" in the name
+		const Std::string adjustedfn = Std::string::format("flics/0%s.%s", filename.c_str(), extn);
+		rs = filesys->ReadFile(adjustedfn);
+		if (!rs)
+			return nullptr;
+	}
+	return rs;
+}
+
+static Common::SeekableReadStream *_tryLoadCruAVI(const Std::string &filename) {
+	Common::SeekableReadStream *rs = _tryLoadCruMovieFile(filename, "avi");
+	if (!rs)
+		warning("movie %s not found", filename.c_str());
+	return rs;
+}
+
+// Convenience function that tries to open both TXT (No Remorse)
+// and IFF (No Regret) subtitle formats.
+static Common::SeekableReadStream *_tryLoadCruSubtitle(const Std::string &filename) {
+	Common::SeekableReadStream *txtfile = _tryLoadCruMovieFile(filename, "txt");
+	if (txtfile)
+		return txtfile;
+	return _tryLoadCruMovieFile(filename, "iff");
+}
+
+
 DEFINE_RUNTIME_CLASSTYPE_CODE(MovieGump)
 
 MovieGump::MovieGump() : ModalGump(), _player(nullptr) {
@@ -134,7 +188,7 @@ bool MovieGump::OnKeyDown(int key, int mod) {
 	return true;
 }
 
-//static
+/*static*/
 ProcId MovieGump::U8MovieViewer(Common::SeekableReadStream *rs, bool fade, bool introMusicHack, bool noScale) {
 	ModalGump *gump;
 	if (GAME_IS_U8)
@@ -156,6 +210,18 @@ ProcId MovieGump::U8MovieViewer(Common::SeekableReadStream *rs, bool fade, bool
 	}
 }
 
+/*static*/ MovieGump *MovieGump::CruMovieViewer(const Std::string fname, int x, int y, const byte *pal, Gump *parent) {
+	Common::SeekableReadStream *rs = _tryLoadCruAVI(fname);
+	if (!rs)
+		return nullptr;
+
+	MovieGump *gump = new MovieGump(x, y, rs, false, false, pal);
+	gump->InitGump(parent, true);
+	gump->setRelativePosition(CENTER);
+	gump->loadSubtitles(_tryLoadCruSubtitle(fname));
+	return gump;
+}
+
 void MovieGump::loadSubtitles(Common::SeekableReadStream *rs) {
 	if (!rs)
 		return;
@@ -197,59 +263,6 @@ void MovieGump::saveData(Common::WriteStream *ws) {
 
 }
 
-static Std::string _fixCrusaderMovieName(const Std::string &s) {
-	/*
-	 HACK! The game comes with movies MVA01.AVI etc, but the usecode mentions both
-	 MVA01 and MVA1.  We do a translation here.	 These are the strings we need to fix:
-	 008E: 0D	push string	"mva1"
-	 036D: 0D	push string	"mva3a"
-	 04E3: 0D	push string	"mva4"
-	 0656: 0D	push string	"mva5a"
-	 07BD: 0D	push string	"mva6"
-	 0944: 0D	push string	"mva7"
-	 0A68: 0D	push string	"mva8"
-	 0B52: 0D	push string	"mva9"
-	*/
-	if (s.size() == 4)
-		return Std::string::format("mva0%c", s[3]);
-	else if (s.equals("mva3a"))
-		return "mva03a";
-	else if (s.equals("mva5a"))
-		return "mva05a";
-
-	return s;
-}
-
-static Common::SeekableReadStream *_tryLoadCruMovieFile(const Std::string &filename, const char *extn) {
-	const Std::string path = Std::string::format("flics/%s.%s", filename.c_str(), extn);
-	FileSystem *filesys = FileSystem::get_instance();
-	Common::SeekableReadStream *rs = filesys->ReadFile(path);
-	if (!rs) {
-		// Try with a "0" in the name
-		const Std::string adjustedfn = Std::string::format("flics/0%s.%s", filename.c_str(), extn);
-		rs = filesys->ReadFile(adjustedfn);
-		if (!rs)
-			return nullptr;
-	}
-	return rs;
-}
-
-static Common::SeekableReadStream *_tryLoadCruAVI(const Std::string &filename) {
-	Common::SeekableReadStream *rs = _tryLoadCruMovieFile(filename, "avi");
-	if (!rs)
-		warning("movie %s not found", filename.c_str());
-	return rs;
-}
-
-// Convenience function that tries to open both TXT (No Remorse)
-// and IFF (No Regret) subtitle formats.
-static Common::SeekableReadStream *_tryLoadCruSubtitle(const Std::string &filename) {
-	Common::SeekableReadStream *txtfile = _tryLoadCruMovieFile(filename, "txt");
-	if (txtfile)
-		return txtfile;
-	return _tryLoadCruMovieFile(filename, "iff");
-}
-
 uint32 MovieGump::I_playMovieOverlay(const uint8 *args,
 		unsigned int /*argsize*/) {
 	ARG_ITEM_FROM_PTR(item);
@@ -267,13 +280,7 @@ uint32 MovieGump::I_playMovieOverlay(const uint8 *args,
 		const Palette *pal = palman->getPalette(PaletteManager::Pal_Game);
 		assert(pal);
 
-		Common::SeekableReadStream *rs = _tryLoadCruAVI(name);
-		if (rs) {
-			MovieGump *gump = new MovieGump(x, y, rs, false, false, pal->_palette);
-			gump->InitGump(nullptr, true);
-			gump->setRelativePosition(CENTER);
-			gump->loadSubtitles(_tryLoadCruSubtitle(name));
-		}
+		CruMovieViewer(name, x, y, pal->_palette, nullptr);
 	}
 
 	return 0;
@@ -286,13 +293,7 @@ uint32 MovieGump::I_playMovieCutscene(const uint8 *args, unsigned int /*argsize*
 	ARG_UINT16(y);
 
 	if (item) {
-		Common::SeekableReadStream *rs = _tryLoadCruAVI(name);
-		if (rs) {
-			MovieGump *gump = new MovieGump(x * 3, y * 3, rs, false, false);
-			gump->InitGump(nullptr, true);
-			gump->setRelativePosition(CENTER);
-			gump->loadSubtitles(_tryLoadCruSubtitle(name));
-		}
+		CruMovieViewer(name, x * 3, y * 3, nullptr, nullptr);
 	}
 
 	return 0;
@@ -312,13 +313,7 @@ uint32 MovieGump::I_playMovieCutsceneAlt(const uint8 *args, unsigned int /*argsi
 	warning("MovieGump::I_playMovieCutsceneAlt: TODO: This intrinsic should pause and fade the background to grey");
 
 	if (item) {
-		Common::SeekableReadStream *rs = _tryLoadCruAVI(name);
-		if (rs) {
-			MovieGump *gump = new MovieGump(x * 3, y * 3, rs, false, false);
-			gump->InitGump(nullptr, true);
-			gump->setRelativePosition(CENTER);
-			gump->loadSubtitles(_tryLoadCruSubtitle(name));
-		}
+		CruMovieViewer(name, x * 3, y * 3, nullptr, nullptr);
 	}
 
 	return 0;
@@ -330,13 +325,7 @@ uint32 MovieGump::I_playMovieCutsceneRegret(const uint8 *args, unsigned int /*ar
 
 	warning("MovieGump::I_playMovieCutsceneRegret: TODO: use fade argument %d", fade);
 
-	Common::SeekableReadStream *rs = _tryLoadCruAVI(name);
-	if (rs) {
-		MovieGump *gump = new MovieGump(640, 480, rs, false, false);
-		gump->InitGump(nullptr, true);
-		gump->setRelativePosition(CENTER);
-		gump->loadSubtitles(_tryLoadCruSubtitle(name));
-	}
+	CruMovieViewer(name, 640, 480, nullptr, nullptr);
 
 	return 0;
 }
diff --git a/engines/ultima/ultima8/gumps/movie_gump.h b/engines/ultima/ultima8/gumps/movie_gump.h
index 34399ee48a..bcc8af0596 100644
--- a/engines/ultima/ultima8/gumps/movie_gump.h
+++ b/engines/ultima/ultima8/gumps/movie_gump.h
@@ -56,6 +56,7 @@ public:
 	bool OnKeyDown(int key, int mod) override;
 
 	static ProcId U8MovieViewer(Common::SeekableReadStream *rs, bool fade, bool introMusicHack, bool noScale);
+	static MovieGump *CruMovieViewer(const Std::string fname, int x, int y, const byte *pal, Gump *parent);
 
 	bool loadData(Common::ReadStream *rs);
 	void saveData(Common::WriteStream *ws) override;
diff --git a/engines/ultima/ultima8/gumps/weasel_gump.cpp b/engines/ultima/ultima8/gumps/weasel_gump.cpp
index 30fe67d4db..17b3de40e6 100644
--- a/engines/ultima/ultima8/gumps/weasel_gump.cpp
+++ b/engines/ultima/ultima8/gumps/weasel_gump.cpp
@@ -196,16 +196,11 @@ void WeaselGump::InitGump(Gump *newparent, bool take_focus) {
 }
 
 Gump *WeaselGump::playMovie(const Std::string &filename) {
-	const Std::string path = Std::string::format("flics/%s.avi", filename.c_str());
-	FileSystem *filesys = FileSystem::get_instance();
-	Common::SeekableReadStream *rs = filesys->ReadFile(path);
-	if (!rs) {
+	MovieGump *gump = MovieGump::CruMovieViewer(filename, 600, 450, nullptr, this);
+	if (!gump) {
 		warning("Couldn't load flic %s", filename.c_str());
 		return nullptr;
 	}
-	Gump *gump = new MovieGump(600, 450, rs, false, false);
-	gump->InitGump(this, true);
-	gump->setRelativePosition(CENTER);
 	gump->CreateNotifier();
 	return gump;
 }


Commit: d83ccb7e9b8cababdf8131f71eddf2395b12b6a6
    https://github.com/scummvm/scummvm/commit/d83ccb7e9b8cababdf8131f71eddf2395b12b6a6
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T07:31:43+09:00

Commit Message:
ULTIMA8: Default to no mouse cursor in Crusader

Changed paths:
    engines/ultima/ultima8/kernel/mouse.cpp


diff --git a/engines/ultima/ultima8/kernel/mouse.cpp b/engines/ultima/ultima8/kernel/mouse.cpp
index 2877a3054c..ea93c3d624 100644
--- a/engines/ultima/ultima8/kernel/mouse.cpp
+++ b/engines/ultima/ultima8/kernel/mouse.cpp
@@ -203,8 +203,11 @@ int Mouse::getMouseFrame() {
 
 	switch (cursor) {
 	case MOUSE_NORMAL: {
+		if (GAME_IS_CRUSADER)
+			return -1;
+
 		bool combat = false;
-		MainActor *av = getMainActor();
+		const MainActor *av = getMainActor();
 		if (av) {
 			combat = av->isInCombat();
 		}


Commit: cf085788c2665665eac6bac23057488aaf670f61
    https://github.com/scummvm/scummvm/commit/cf085788c2665665eac6bac23057488aaf670f61
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T07:31:43+09:00

Commit Message:
ULTIMA8: Add Crusader key for using energy cube

Had to reassign the "paint editor items" debug key because it was using 'e',
which we need.

Changed paths:
    engines/ultima/ultima8/meta_engine.cpp
    engines/ultima/ultima8/meta_engine.h
    engines/ultima/ultima8/misc/debugger.cpp
    engines/ultima/ultima8/misc/debugger.h


diff --git a/engines/ultima/ultima8/meta_engine.cpp b/engines/ultima/ultima8/meta_engine.cpp
index dbab7b78d5..2854fb2b7d 100644
--- a/engines/ultima/ultima8/meta_engine.cpp
+++ b/engines/ultima/ultima8/meta_engine.cpp
@@ -85,6 +85,7 @@ static const KeybindingRecord CRUSADER_KEYS[] = {
 	{ ACTION_NEXT_INVENTORY, "NEXT_INVENTORY", "Next Inventory Item", "MainActor::nextInvItem", nullptr, "i", nullptr, 0 },
 	{ ACTION_USE_INVENTORY, "USE_INVENTORY", "Use Inventroy Item", "MainActor::useInventoryItem", nullptr, "u", nullptr, 0 },
 	{ ACTION_USE_MEDIKIT, "USE_MEDIKIT", "Use Medical Kit", "MainActor::useMedikit", nullptr, "m", nullptr, 0 },
+	{ ACTION_USE_ENERGYCUBE, "USE_ENERGYCUBE", "Use Energy Cube", "MainActor::useEnergyCube", nullptr, "e", nullptr, 0 },
 	{ ACTION_DETONATE_BOMB, "DETONATE_BOMB", "Detonate Bomb", "MainActor::detonateBomb", nullptr, "b", nullptr, 0 },
 	{ ACTION_SELECT_ITEMS, "SELECT_ITEM", "Select Item", "ItemSelectionProcess::startSelection", nullptr, "s", nullptr, 0 },
 	{ ACTION_USE_SELECTION, "USE_SELECTION", "Use Selection", "ItemSelectionProcess::useSelectedItem", nullptr, "RETURN", nullptr, 0 },
@@ -109,7 +110,7 @@ static const KeybindingRecord CHEAT_KEYS[] = {
 
 #ifndef RELEASE_BUILD
 static const KeybindingRecord DEBUG_KEYS[] = {
-	{ ACTION_TOGGLE_PAINT, "TOGGLE_PAINT", "Toggle Paint Editor Items", "GUIApp::togglePaintEditorItems", nullptr, "e", nullptr, 0 },
+	{ ACTION_TOGGLE_PAINT, "TOGGLE_PAINT", "Toggle Paint Editor Items", "GUIApp::togglePaintEditorItems", nullptr, "F9", nullptr, 0 },
 	{ ACTION_DEC_SORT_ORDER, "DEC_SORT_ORDER", "Decrement Map Sort Order", "GameMapGump::decrementSortOrder", nullptr, "LEFTBRACKET", nullptr, 0 },
 	{ ACTION_INC_SORT_ORDER, "INC_SORT_ORDER", "Increment Map Sort Order", "GameMapGump::incrementSortOrder", nullptr, "RIGHTBRACKET", nullptr, 0 },
 	{ ACTION_ENGINE_STATS, "STATS", "List engine stats", "GUIApp::engineStats", nullptr, "t", nullptr, 0 },
diff --git a/engines/ultima/ultima8/meta_engine.h b/engines/ultima/ultima8/meta_engine.h
index b1e9564484..a67a33ad09 100644
--- a/engines/ultima/ultima8/meta_engine.h
+++ b/engines/ultima/ultima8/meta_engine.h
@@ -33,8 +33,8 @@ enum KeybindingAction {
 	ACTION_QUICKSAVE, ACTION_SAVE, ACTION_LOAD, ACTION_BEDROLL, ACTION_COMBAT,
 	ACTION_BACKPACK, ACTION_KEYRING, ACTION_MINIMAP, ACTION_RECALL,
 	ACTION_INVENTORY, ACTION_NEXT_WEAPON, ACTION_NEXT_INVENTORY,
-	ACTION_USE_INVENTORY, ACTION_USE_MEDIKIT, ACTION_SELECT_ITEMS,
-	ACTION_DETONATE_BOMB, ACTION_USE_SELECTION, ACTION_MENU,
+	ACTION_USE_INVENTORY, ACTION_USE_MEDIKIT, ACTION_USE_ENERGYCUBE,
+	ACTION_SELECT_ITEMS, ACTION_DETONATE_BOMB, ACTION_USE_SELECTION, ACTION_MENU,
 	ACTION_CLOSE_GUMPS, ACTION_HIGHLIGHT_ITEMS, ACTION_TOGGLE_TOUCHING,
 	ACTION_JUMP, ACTION_TURN_LEFT, ACTION_TURN_RIGHT, ACTION_MOVE_FORWARD,
 	ACTION_MOVE_BACK, ACTION_MOVE_UP, ACTION_MOVE_DOWN, ACTION_MOVE_LEFT,
diff --git a/engines/ultima/ultima8/misc/debugger.cpp b/engines/ultima/ultima8/misc/debugger.cpp
index 85d2036e16..a567d593a5 100644
--- a/engines/ultima/ultima8/misc/debugger.cpp
+++ b/engines/ultima/ultima8/misc/debugger.cpp
@@ -154,6 +154,7 @@ Debugger::Debugger() : Shared::Debugger() {
 	registerCmd("MainActor::nextInvItem", WRAP_METHOD(Debugger, cmdNextInventory));
 	registerCmd("MainActor::useInventoryItem", WRAP_METHOD(Debugger, cmdUseInventoryItem));
 	registerCmd("MainActor::useMedikit", WRAP_METHOD(Debugger, cmdUseMedikit));
+	registerCmd("MainActor::useEnergyCube", WRAP_METHOD(Debugger, cmdUseEnergyCube));
 	registerCmd("MainActor::detonateBomb", WRAP_METHOD(Debugger, cmdDetonateBomb));
 	registerCmd("MainActor::toggleCombat", WRAP_METHOD(Debugger, cmdToggleCombat));
 	registerCmd("ItemSelectionProcess::startSelection", WRAP_METHOD(Debugger, cmdStartSelection));
@@ -1096,6 +1097,22 @@ bool Debugger::cmdUseMedikit(int argc, const char **argv) {
 	return false;
 }
 
+bool Debugger::cmdUseEnergyCube(int argc, const char **argv) {
+	if (Ultima8Engine::get_instance()->isAvatarInStasis()) {
+		debugPrintf("Can't use energy cube: avatarInStasis\n");
+		return false;
+	}
+
+	// Only if controlling avatar.
+	if (!_isAvatarControlled()) {
+		return false;
+	}
+
+	MainActor *av = getMainActor();
+	av->useInventoryItem(0x582);
+	return false;
+}
+
 bool Debugger::cmdDetonateBomb(int argc, const char **argv) {
 	if (Ultima8Engine::get_instance()->isAvatarInStasis()) {
 		debugPrintf("Can't detonate bomb: avatarInStasis\n");
diff --git a/engines/ultima/ultima8/misc/debugger.h b/engines/ultima/ultima8/misc/debugger.h
index 7ae8c902ac..95145920aa 100644
--- a/engines/ultima/ultima8/misc/debugger.h
+++ b/engines/ultima/ultima8/misc/debugger.h
@@ -222,6 +222,7 @@ private:
 	bool cmdToggleCombat(int argc, const char **argv);
 	bool cmdUseInventoryItem(int argc, const char **argv);
 	bool cmdUseMedikit(int argc, const char **argv);
+	bool cmdUseEnergyCube(int argc, const char **argv);
 	bool cmdDetonateBomb(int argc, const char **argv);
 	bool cmdStartSelection(int argc, const char **argv);
 	bool cmdUseSelection(int argc, const char **argv);


Commit: 137fa8ea290c31aa061830e9158e4ddc407b45b7
    https://github.com/scummvm/scummvm/commit/137fa8ea290c31aa061830e9158e4ddc407b45b7
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T07:48:26+09:00

Commit Message:
ULTIMA8: Implement 'grab' operation for Crusader games

Since it only works on loose items and not for searching boxes etc, it's
actually not so useful, but implemented for completeness.

Changed paths:
    engines/ultima/ultima8/meta_engine.cpp
    engines/ultima/ultima8/meta_engine.h
    engines/ultima/ultima8/misc/debugger.cpp
    engines/ultima/ultima8/misc/debugger.h
    engines/ultima/ultima8/world/item_selection_process.cpp
    engines/ultima/ultima8/world/item_selection_process.h


diff --git a/engines/ultima/ultima8/meta_engine.cpp b/engines/ultima/ultima8/meta_engine.cpp
index 2854fb2b7d..bd3abdfaa8 100644
--- a/engines/ultima/ultima8/meta_engine.cpp
+++ b/engines/ultima/ultima8/meta_engine.cpp
@@ -89,6 +89,7 @@ static const KeybindingRecord CRUSADER_KEYS[] = {
 	{ ACTION_DETONATE_BOMB, "DETONATE_BOMB", "Detonate Bomb", "MainActor::detonateBomb", nullptr, "b", nullptr, 0 },
 	{ ACTION_SELECT_ITEMS, "SELECT_ITEM", "Select Item", "ItemSelectionProcess::startSelection", nullptr, "s", nullptr, 0 },
 	{ ACTION_USE_SELECTION, "USE_SELECTION", "Use Selection", "ItemSelectionProcess::useSelectedItem", nullptr, "RETURN", nullptr, 0 },
+	{ ACTION_GRAB_ITEMS, "GRAB_ITEM", "Grab Items", "ItemSelectionProcess::grabItems", nullptr, "g", nullptr, 0 },
 	{ ACTION_ATTACK, "ATTACK", "Attack", "AvatarMoverProcess::tryAttack", nullptr, "SPACE", nullptr, 0 },
 	{ ACTION_CAMERA_AVATAR, "CAMERA_AVATAR", "Focus Camera on Silencer", "CameraProcess::moveToAvatar", nullptr, "z", nullptr, 0 },
 	{ ACTION_JUMP, "JUMP", "Jump / Roll / Crouch", "AvatarMoverProcess::startJump", "AvatarMoverProcess::stopJump", "LCTRL", nullptr, FLAG_MENU_ENABLED },
diff --git a/engines/ultima/ultima8/meta_engine.h b/engines/ultima/ultima8/meta_engine.h
index a67a33ad09..c1b435fb2a 100644
--- a/engines/ultima/ultima8/meta_engine.h
+++ b/engines/ultima/ultima8/meta_engine.h
@@ -34,12 +34,12 @@ enum KeybindingAction {
 	ACTION_BACKPACK, ACTION_KEYRING, ACTION_MINIMAP, ACTION_RECALL,
 	ACTION_INVENTORY, ACTION_NEXT_WEAPON, ACTION_NEXT_INVENTORY,
 	ACTION_USE_INVENTORY, ACTION_USE_MEDIKIT, ACTION_USE_ENERGYCUBE,
-	ACTION_SELECT_ITEMS, ACTION_DETONATE_BOMB, ACTION_USE_SELECTION, ACTION_MENU,
-	ACTION_CLOSE_GUMPS, ACTION_HIGHLIGHT_ITEMS, ACTION_TOGGLE_TOUCHING,
-	ACTION_JUMP, ACTION_TURN_LEFT, ACTION_TURN_RIGHT, ACTION_MOVE_FORWARD,
-	ACTION_MOVE_BACK, ACTION_MOVE_UP, ACTION_MOVE_DOWN, ACTION_MOVE_LEFT,
-	ACTION_MOVE_RIGHT, ACTION_MOVE_RUN, ACTION_MOVE_STEP, ACTION_ATTACK,
-	ACTION_CAMERA_AVATAR,
+	ACTION_SELECT_ITEMS, ACTION_DETONATE_BOMB, ACTION_USE_SELECTION,
+	ACTION_GRAB_ITEMS, ACTION_MENU,	ACTION_CLOSE_GUMPS, ACTION_HIGHLIGHT_ITEMS,
+	ACTION_TOGGLE_TOUCHING, ACTION_JUMP, ACTION_TURN_LEFT, ACTION_TURN_RIGHT,
+	ACTION_MOVE_FORWARD, ACTION_MOVE_BACK, ACTION_MOVE_UP, ACTION_MOVE_DOWN,
+	ACTION_MOVE_LEFT, ACTION_MOVE_RIGHT, ACTION_MOVE_RUN, ACTION_MOVE_STEP,
+	ACTION_ATTACK, ACTION_CAMERA_AVATAR,
 
 	ACTION_CLIPPING, ACTION_DEC_SORT_ORDER,
 	ACTION_INC_SORT_ORDER, ACTION_QUICK_MOVE_ASCEND, ACTION_QUICK_MOVE_DESCEND,
diff --git a/engines/ultima/ultima8/misc/debugger.cpp b/engines/ultima/ultima8/misc/debugger.cpp
index a567d593a5..cd1734b99d 100644
--- a/engines/ultima/ultima8/misc/debugger.cpp
+++ b/engines/ultima/ultima8/misc/debugger.cpp
@@ -159,6 +159,7 @@ Debugger::Debugger() : Shared::Debugger() {
 	registerCmd("MainActor::toggleCombat", WRAP_METHOD(Debugger, cmdToggleCombat));
 	registerCmd("ItemSelectionProcess::startSelection", WRAP_METHOD(Debugger, cmdStartSelection));
 	registerCmd("ItemSelectionProcess::useSelectedItem", WRAP_METHOD(Debugger, cmdUseSelection));
+	registerCmd("ItemSelectionProcess::grabItems", WRAP_METHOD(Debugger, cmdGrabItems));
 
 	registerCmd("ObjectManager::objectTypes", WRAP_METHOD(Debugger, cmdObjectTypes));
 	registerCmd("ObjectManager::objectInfo", WRAP_METHOD(Debugger, cmdObjectInfo));
@@ -1498,7 +1499,7 @@ bool Debugger::cmdStartSelection(int argc, const char **argv) {
 
 	ItemSelectionProcess *proc = ItemSelectionProcess::get_instance();
 	if (proc)
-		proc->selectNextItem();
+		proc->selectNextItem(false);
 	return false;
 }
 
@@ -1519,6 +1520,23 @@ bool Debugger::cmdUseSelection(int argc, const char **argv) {
 	return false;
 }
 
+bool Debugger::cmdGrabItems(int argc, const char **argv) {
+	if (Ultima8Engine::get_instance()->isAvatarInStasis()) {
+		debugPrintf("Can't grab items: avatarInStasis\n");
+		return false;
+	}
+
+	// Only if controlling avatar.
+	if (!_isAvatarControlled()) {
+		return false;
+	}
+
+	ItemSelectionProcess *proc = ItemSelectionProcess::get_instance();
+	if (proc)
+		proc->selectNextItem(true);
+	return false;
+}
+
 bool Debugger::cmdObjectTypes(int argc, const char **argv) {
 	ObjectManager::get_instance()->objectTypes();
 	return true;
diff --git a/engines/ultima/ultima8/misc/debugger.h b/engines/ultima/ultima8/misc/debugger.h
index 95145920aa..bdd7b74adb 100644
--- a/engines/ultima/ultima8/misc/debugger.h
+++ b/engines/ultima/ultima8/misc/debugger.h
@@ -226,6 +226,7 @@ private:
 	bool cmdDetonateBomb(int argc, const char **argv);
 	bool cmdStartSelection(int argc, const char **argv);
 	bool cmdUseSelection(int argc, const char **argv);
+	bool cmdGrabItems(int argc, const char **argv);
 
 	// Object Manager
 	bool cmdObjectTypes(int argc, const char **argv);
diff --git a/engines/ultima/ultima8/world/item_selection_process.cpp b/engines/ultima/ultima8/world/item_selection_process.cpp
index f0c45a7476..2e9e6bcf80 100644
--- a/engines/ultima/ultima8/world/item_selection_process.cpp
+++ b/engines/ultima/ultima8/world/item_selection_process.cpp
@@ -51,7 +51,7 @@ _ax(0), _ay(0), _az(0) {
 void ItemSelectionProcess::run() {
 }
 
-bool ItemSelectionProcess::selectNextItem() {
+bool ItemSelectionProcess::selectNextItem(bool grab) {
 	MainActor *mainactor = getMainActor();
 	CurrentMap *currentmap = World::get_instance()->getCurrentMap();
 
@@ -94,9 +94,22 @@ bool ItemSelectionProcess::selectNextItem() {
 				continue;
 
 			candidates.push_back(item);
+			if (grab) {
+				const ShapeInfo *info = item->getShapeInfo();
+				if (!info || !(info->_flags & ShapeInfo::SI_CRU_SELECTABLE)) {
+					MainActor *actor = getMainActor();
+					if (actor)
+						actor->addItemCru(item, true);
+				}
+			}
 		}
 	}
 
+	if (grab) {
+		clearSelection();
+		return false;
+	}
+
 	if (candidates.size() < 1) {
 		AudioProcess *audio = AudioProcess::get_instance();
 		assert(audio);
diff --git a/engines/ultima/ultima8/world/item_selection_process.h b/engines/ultima/ultima8/world/item_selection_process.h
index f544804707..509e2256bb 100644
--- a/engines/ultima/ultima8/world/item_selection_process.h
+++ b/engines/ultima/ultima8/world/item_selection_process.h
@@ -42,16 +42,16 @@ public:
 
 	void run() override;
 
-	//!< Select the next item
-	bool selectNextItem();
+	//! Select the next item.  If grab is true, pick up loose items now.
+	bool selectNextItem(bool grab);
 
-	//!< Clear the selector
+	//! Clear the selector sprite
 	void clearSelection();
 
-	//!< Avatar moved - clear the selector if needed.
+	//! Avatar moved - clear the selector if needed.
 	void avatarMoved();
 
-	//!< Use the selected item (if any)
+	//! Use the selected item (if any)
 	void useSelectedItem();
 
 	bool loadData(Common::ReadStream *rs, uint32 version);


Commit: bda1466e0a1326bcaa8ee240722d01f97c22e341
    https://github.com/scummvm/scummvm/commit/bda1466e0a1326bcaa8ee240722d01f97c22e341
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T08:17:01+09:00

Commit Message:
ULTIMA8: Fix Crusader items reappearing after exploding

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


diff --git a/engines/ultima/ultima8/world/damage_info.cpp b/engines/ultima/ultima8/world/damage_info.cpp
index bc59f45f5c..a849103af3 100644
--- a/engines/ultima/ultima8/world/damage_info.cpp
+++ b/engines/ultima/ultima8/world/damage_info.cpp
@@ -63,6 +63,8 @@ bool DamageInfo::applyToItem(Item *item, uint16 points) const {
 
 	if (explode()) {
 		item->explode(explosionType(), explodeDestroysItem(), explodeWithDamage());
+		if (explodeDestroysItem())
+			item = nullptr;
 	}
 	if (_sound) {
 		AudioProcess *audio = AudioProcess::get_instance();
@@ -75,8 +77,9 @@ bool DamageInfo::applyToItem(Item *item, uint16 points) const {
 		uint8 replacementFrame = getReplacementFrame();
 		Item *newitem = ItemFactory::createItem(replacementShape, replacementFrame, q, 0, 0, mapnum, 0, true);
 		newitem->move(x, y, z);
+		if (item)
+			item->destroy();
 	} else if (!explodeDestroysItem()) {
-		assert(!explodeDestroysItem());
 		if (frameDataIsAbsolute()) {
 			int frameval = 1;
 			if (_data[1])


Commit: 26f936510f54fbf8b16ff26cefe8fc6330d2b54f
    https://github.com/scummvm/scummvm/commit/26f936510f54fbf8b16ff26cefe8fc6330d2b54f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T09:08:31+09:00

Commit Message:
ULTIMA8: Implement "cruStasis", stops some key events

The main bugs that this fixes are when using a remote camera:
* Z should not recenter camera on avatar
* Escape should close remote viewing, not open menu

Changed paths:
    engines/ultima/ultima8/misc/debugger.cpp
    engines/ultima/ultima8/ultima8.cpp
    engines/ultima/ultima8/ultima8.h


diff --git a/engines/ultima/ultima8/misc/debugger.cpp b/engines/ultima/ultima8/misc/debugger.cpp
index cd1734b99d..856865a0c2 100644
--- a/engines/ultima/ultima8/misc/debugger.cpp
+++ b/engines/ultima/ultima8/misc/debugger.cpp
@@ -1179,6 +1179,10 @@ bool Debugger::cmdAttack(int argc, const char **argv) {
 }
 
 bool Debugger::cmdCameraOnAvatar(int argc, const char **argv) {
+	if (Ultima8Engine::get_instance()->isCruStasis()) {
+		debugPrintf("Can't move camera: cruStasis\n");
+		return false;
+	}
 	Actor *actor = getControlledActor();
 	if (actor) {
 		int32 x, y, z;
@@ -1803,10 +1807,16 @@ bool Debugger::cmdU8ShapeViewer(int argc, const char **argv) {
 
 bool Debugger::cmdShowMenu(int argc, const char **argv) {
 	World *world = World::get_instance();
+	// In Crusader escape is also used to stop controlling another NPC
 	if (world && world->getControlledNPCNum() != 1) {
 		world->setControlledNPCNum(1);
 		return false;
 	}
+	if (Ultima8Engine::get_instance()->isCruStasis()) {
+		Ultima8Engine::get_instance()->moveKeyEvent();
+		debugPrintf("Not opening menu: cruStasis\n");
+		return false;
+	}
 	MenuGump::showMenu();
 	return false;
 }
diff --git a/engines/ultima/ultima8/ultima8.cpp b/engines/ultima/ultima8/ultima8.cpp
index 460d1906a3..15a16a2a89 100644
--- a/engines/ultima/ultima8/ultima8.cpp
+++ b/engines/ultima/ultima8/ultima8.cpp
@@ -125,7 +125,7 @@ Ultima8Engine::Ultima8Engine(OSystem *syst, const Ultima::UltimaGameDescription
 		_screen(nullptr), _fontManager(nullptr), _paletteManager(nullptr), _gameData(nullptr),
 		_world(nullptr), _desktopGump(nullptr), _gameMapGump(nullptr), _avatarMoverProcess(nullptr),
 		_frameSkip(false), _frameLimit(true), _interpolate(true), _animationRate(100),
-		_avatarInStasis(false), _paintEditorItems(false), _inversion(0),
+		_avatarInStasis(false), _cruStasis(false), _paintEditorItems(false), _inversion(0),
 		_showTouching(false), _timeOffset(0), _hasCheated(false), _cheatsEnabled(false),
 		_fontOverride(false), _fontAntialiasing(false), _audioMixer(0), _inverterGump(nullptr),
 	    _lerpFactor(256), _inBetweenFrame(false), _unkCrusaderFlag(false), _moveKeyFrame(0) {
@@ -864,7 +864,7 @@ void Ultima8Engine::writeSaveInfo(Common::WriteStream *ws) {
 
 bool Ultima8Engine::canSaveGameStateCurrently(bool isAutosave) {
 	// Can't save when avatar in stasis during cutscenes
-	if (_avatarInStasis)
+	if (_avatarInStasis || _cruStasis)
 		return false;
 
 	// Check for gumps that prevent saving
@@ -1507,13 +1507,12 @@ uint32 Ultima8Engine::I_getAvatarInStasis(const uint8 * /*args*/, unsigned int /
 }
 
 uint32 Ultima8Engine::I_setCruStasis(const uint8 *args, unsigned int argsize) {
-	// This is like avatar stasis, but stops a lot of other keyboard inputs too.
-	warning("I_setCruStasis: TODO: implement me");
+	get_instance()->setCruStasis(true);
 	return 0;
 }
 
 uint32 Ultima8Engine::I_clrCruStasis(const uint8 *args, unsigned int argsize) {
-	warning("I_clrCruStasis: TODO: implement me");
+	get_instance()->setCruStasis(false);
 	return 0;
 }
 
diff --git a/engines/ultima/ultima8/ultima8.h b/engines/ultima/ultima8/ultima8.h
index b72dec55ae..8a915f453e 100644
--- a/engines/ultima/ultima8/ultima8.h
+++ b/engines/ultima/ultima8/ultima8.h
@@ -123,6 +123,7 @@ private:
 	unsigned int _inversion;
 	bool _unkCrusaderFlag; //!< not sure what this is but it's only used in usecode for crusader, so just keep track of it..
 	uint32 _moveKeyFrame; //!< An imperfect way for the Crusader usecode to stop remote camera viewing.
+	bool _cruStasis; //!< A slightly different kind of stasis for Crusader that stops some keyboard events
 private:
 	/**
 	 * Does engine deinitialization
@@ -260,6 +261,12 @@ public:
 	void setUnkCrusaderFlag(bool flag) {
 		_unkCrusaderFlag = flag;
 	}
+	void setCruStasis(bool flag) {
+		_cruStasis = flag;
+	}
+	bool isCruStasis() const {
+		return _cruStasis;
+	}
 
 	void moveKeyEvent();
 	bool moveKeyDownRecently();


Commit: 6f5538ab4dac77cb2f46f4ddff73c8a28f8dd55f
    https://github.com/scummvm/scummvm/commit/6f5538ab4dac77cb2f46f4ddff73c8a28f8dd55f
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T12:04:25+09:00

Commit Message:
ULTIMA8: Fix actor anim speed in Crusader

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 9f3bf1373c..f21e0b5e62 100644
--- a/engines/ultima/ultima8/graphics/anim_dat.cpp
+++ b/engines/ultima/ultima8/graphics/anim_dat.cpp
@@ -199,6 +199,13 @@ void AnimDat::load(Common::SeekableReadStream *rs) {
 			if (GAME_IS_U8 && (repeatAndRotateFlag & 0xf0)) {
 				// This should never happen..
 				error("Anim data: frame repeat byte should never be > 0xf");
+			} else if (GAME_IS_CRUSADER) {
+				// WORKAROUND: In Crusader, the process wait semantics changed so
+				// wait of 1 frame was the same as no wait.  The frame repeat
+				// is implemented as a process wait, so this effectively reduced
+				// all frame repeats by 1.
+				if (a->_actions[action]->_frameRepeat)
+					a->_actions[action]->_frameRepeat--;
 			}
 			// byte 3: flags high byte
 			rawflags |= rs->readByte() << 8;


Commit: cf7ae464756ca9f9e994b111d219058a46180695
    https://github.com/scummvm/scummvm/commit/cf7ae464756ca9f9e994b111d219058a46180695
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-05-09T13:09:08+09:00

Commit Message:
ULTIMA8: Adjust Crusader step tests to match original

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


diff --git a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
index 95648f774a..b413d933d1 100644
--- a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -380,8 +380,9 @@ void CruAvatarMoverProcess::step(Animation::Sequence action, Direction direction
 		Direction dir_left = Direction_TurnByDelta(direction, -4, dirmode_16dirs);
 		Point3 origpt;
 		avatar->getLocation(origpt);
-		static const int ADJUSTMENTS[] = {0x10, 0x10, 0x20, 0x20, 0x30, 0x30,
-			0x40, 0x40, 0x50, 0x50};
+		// Double the values in original to match our coordinate space
+		static const int ADJUSTMENTS[] = {0x20, 0x20, 0x40, 0x40, 0x60, 0x60,
+			0x80, 0x80, 0xA0, 0xA0};
 
 		for (int i = 0; i < ARRAYSIZE(ADJUSTMENTS); i++) {
 			Direction testdir = (i % 2 ? dir_left : dir_right);




More information about the Scummvm-git-logs mailing list