[Scummvm-git-logs] scummvm master -> 6322e399ec9d97570cba97eeaa50e650fad2a9b5

mduggan mgithub at guarana.org
Sun Mar 28 04:00:01 UTC 2021


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

Summary:
aaa2d5f5c6 ULTIMA8: Small GravityProcess cleanups (remove dead code) and assertions
e92d4791b1 ULTIMA8: Make gravity behave more like original
743ef873b2 ULTIMA8: Add LAND bit to blocking collision mask.
6a30d603aa ULTIMA8: Fix Crusader pickup gump positioning
dbad8518dc ULTIMA8: Implement Crusader style pathfinder
96f2381926 ULTIMA8: Improve const correctness
19648041c7 ULTIMA8: Remove dead code
36b42f92fe ULTIMA8: Get Crusader inventory shape dyanmically as it can change
52a40f33af ULTIMA8: Also show bombs in cru inventory
3b49490597 ULTIMA8: Refactor isBusy logic to Actor
1de427262f ULTIMA8: Update crusader stance after changing weapons
6322e399ec ULTIMA8: Fix fade on Crusader health/energy gumps


Commit: aaa2d5f5c65ed5e89760412184774b89e1546232
    https://github.com/scummvm/scummvm/commit/aaa2d5f5c65ed5e89760412184774b89e1546232
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:49:07+09:00

Commit Message:
ULTIMA8: Small GravityProcess cleanups (remove dead code) and assertions

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


diff --git a/engines/ultima/ultima8/world/gravity_process.cpp b/engines/ultima/ultima8/world/gravity_process.cpp
index e7c71053e2..c0df54e6d4 100644
--- a/engines/ultima/ultima8/world/gravity_process.cpp
+++ b/engines/ultima/ultima8/world/gravity_process.cpp
@@ -80,6 +80,9 @@ void GravityProcess::run() {
 		return;
 	}
 
+	// There should never be more than one gravity on an object
+	assert(item->getGravityPID() == _pid);
+
 	Actor *actor = dynamic_cast<Actor *>(item);
 	if (actor && actor->getFallStart() < actor->getZ()) {
 		actor->setFallStart(actor->getZ());
@@ -96,49 +99,27 @@ void GravityProcess::run() {
 
 	int32 ix, iy, iz;
 	item->getLocation(ix, iy, iz);
-	int32 ixd, iyd, izd;
-	item->getFootpadWorld(ixd, iyd, izd);
+
+	if (iz < -1000) {
+		// Shouldn't happen as item should always hit the floor.
+		warning("Item %d fell too far, stopping GravityProcess", _itemNum);
+		terminate();
+		return;
+	}
 
 	int32 tx, ty, tz;
 	tx = ix + _xSpeed;
 	ty = iy + _ySpeed;
 	tz = iz + _zSpeed;
 
-	bool clipped = false;
-
-	// Clip to region. This doesn't work
-#if 0
-	if (tx < 0 && ix >= 0) {
-		int32 scale = (ix - tx) >> 0x8;
-		tx = 0;
-		ty = iy + ((_ySpeed * scale) >> 0x2000);
-		tz = iz + ((_zSpeed * scale) >> 0x2000);
-		clipped = true;
-	}
-	if (ty < 0 && iy >= 0) {
-		int32 scale = (iy - ty) >> 0x8;
-		tx = ix + ((_xSpeed * scale) >> 0x2000);
-		ty = 0;
-		tz = iz + ((_zSpeed * scale) >> 0x2000);
-		clipped = true;
-	}
-	if (tz < 0 && iz >= 0) {
-		int32 scale = (iz - tz) >> 0x8;
-		tx = ix + ((_xSpeed * scale) >> 0x2000);
-		ty = iy + ((_ySpeed * scale) >> 0x2000);
-		tz = 0;
-		clipped = true;
-	}
-#endif
-
 //#define BOUNCE_DIAG
 
 	ObjId hititemid;
 	uint8 dirs;
 	int32 dist = item->collideMove(tx, ty, tz, false, false, &hititemid, &dirs);
 
-	if (dist == 0x4000 && !clipped) {
-		// normal move
+	if (dist == 0x4000 && !hititemid) {
+		// didn't hit anything.
 		_zSpeed -= _gravity;
 		return;
 	}
@@ -173,7 +154,7 @@ void GravityProcess::run() {
 			     << "]: hit " << hititem->getObjId() << Std::endl;
 #endif
 
-			if (!hititem->getShapeInfo()->is_land() || _zSpeed < -2 * _gravity) {
+			if (GAME_IS_U8 && (!hititem->getShapeInfo()->is_land() || _zSpeed < -2 * _gravity)) {
 				// Bounce!
 				termFlag = false;
 #ifdef BOUNCE_DIAG
@@ -284,6 +265,7 @@ void GravityProcess::terminate() {
 	//signal item GravityProcess is gone
 	Item *item = getItem(_itemNum);
 	if (item) {
+		assert(item->getGravityPID() == 0 || item->getGravityPID() == _pid);
 		item->setGravityPID(0);
 
 		// no longer bouncing


Commit: e92d4791b16dad30f768fbbe3cb7e2c41f9ef00d
    https://github.com/scummvm/scummvm/commit/e92d4791b16dad30f768fbbe3cb7e2c41f9ef00d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:49:07+09:00

Commit Message:
ULTIMA8: Make gravity behave more like original

Tweaks to make it behave more like original games:
* Don't apply gravity to weight == 0 objects
* Add a small hang time in Crusader

Changed paths:
    engines/ultima/ultima8/world/item.cpp
    engines/ultima/ultima8/world/item.h


diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 6a5f65082f..b52b0369ce 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -27,6 +27,7 @@
 #include "ultima/ultima8/usecode/uc_list.h"
 #include "ultima/ultima8/world/world.h"
 #include "ultima/ultima8/kernel/kernel.h"
+#include "ultima/ultima8/kernel/delay_process.h"
 #include "ultima/ultima8/world/get_object.h"
 #include "ultima/ultima8/graphics/main_shape_archive.h"
 #include "ultima/ultima8/graphics/gump_shape_archive.h"
@@ -1989,16 +1990,16 @@ GravityProcess *Item::ensureGravityProcess() {
 
 void Item::fall() {
 	const ShapeInfo *info = getShapeInfo();
-	if (_flags & FLG_HANGING || info->is_fixed() ||
-		(info->_weight == 0 && GAME_IS_CRUSADER)) {
+	bool hanging = GAME_IS_U8 && (_flags & FLG_HANGING);
+
+	if (hanging || info->is_fixed() || info->_weight == 0) {
 		// can't fall
 		return;
 	}
 
 	int gravity = GAME_IS_CRUSADER ? 2 : 4; //!! constants
 
-	GravityProcess *p = ensureGravityProcess();
-	p->setGravity(gravity);
+	hurl(0, 0, 0, gravity);
 }
 
 void Item::grab() {
@@ -2031,9 +2032,16 @@ void Item::grab() {
 
 
 void Item::hurl(int xs, int ys, int zs, int grav) {
+	// crusader sleeps existing gravity at first
+	bool do_sleep = GAME_IS_CRUSADER && (_gravityPid == 0);
 	GravityProcess *p = ensureGravityProcess();
 	p->setGravity(grav);
 	p->move(xs, ys, zs);
+	if (do_sleep) {
+		Process *delayProc = new DelayProcess(0x14);
+		ProcId pid = Kernel::get_instance()->addProcess(delayProc);
+		p->waitFor(pid);
+	}
 }
 
 
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index d12152159a..82a9cb010a 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -353,8 +353,9 @@ public:
 	//! Hurl the item in the given direction
 	void hurl(int xs, int ys, int zs, int grav);
 
-	//! Set the PID of the GravityProcess for this Item
+	//! Set the PID of the GravityProcess for this Item.  There should be only one.
 	void setGravityPID(ProcId pid) {
+		assert(_gravityPid == 0 || pid == 0);
 		_gravityPid = pid;
 	}
 


Commit: 743ef873b2e2e003757075a8e012d1215a2f4220
    https://github.com/scummvm/scummvm/commit/743ef873b2e2e003757075a8e012d1215a2f4220
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:49:07+09:00

Commit Message:
ULTIMA8: Add LAND bit to blocking collision mask.

Without this, some temporary items which do not have SI_SOLID can fall through
the floor.  In U8, LAND items generally don't move so this shouldn't have any
negative impact

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 bc2608d4fd..d6a2a2e603 100644
--- a/engines/ultima/ultima8/world/current_map.cpp
+++ b/engines/ultima/ultima8/world/current_map.cpp
@@ -1013,7 +1013,7 @@ bool CurrentMap::sweepTest(const int32 start[3], const int32 end[3],
                            const int32 dims[3], uint32 shapeflags,
                            ObjId item, bool blocking_only,
                            Std::list<SweepItem> *hit) const {
-	const uint32 blockflagmask = (ShapeInfo::SI_SOLID | ShapeInfo::SI_DAMAGING);
+	const uint32 blockflagmask = (ShapeInfo::SI_SOLID | ShapeInfo::SI_DAMAGING | ShapeInfo::SI_LAND);
 
 	int minx = ((start[0] - dims[0]) / _mapChunkSize) - 1;
 	int maxx = (start[0] / _mapChunkSize) + 1;


Commit: 6a30d603aaad5b4c0ba3e01c7fd4548bb7de129e
    https://github.com/scummvm/scummvm/commit/6a30d603aaad5b4c0ba3e01c7fd4548bb7de129e
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:49:07+09:00

Commit Message:
ULTIMA8: Fix Crusader pickup gump positioning

Changed paths:
    engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp


diff --git a/engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp b/engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp
index 365daafcf0..0dfdb337dc 100644
--- a/engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_pickup_area_gump.cpp
@@ -56,26 +56,28 @@ void CruPickupAreaGump::addPickup(const Item *item) {
 
 	uint32 shapeno = item->getShape();
 
+	// Find the location to draw the gump for the new item,
+	// or an existing gump to recycle if we have one already
+	// for that shape
+	int32 maxy = PICKUP_GUMP_GAP;
 	Std::list<Gump *>::iterator it;
-
 	for (it = _children.begin(); it != _children.end(); it++) {
 		CruPickupGump *pug = dynamic_cast<CruPickupGump *>(*it);
 		if (!pug)
-			return;
+			continue;
 		if (pug->getShapeNo() == shapeno) {
 			// Already a notification for this object, update it
 			pug->updateForNewItem(item);
-			break;
+			return;
 		}
+		int32 x, y;
+		pug->getLocation(x, y);
+		maxy = MAX(maxy, y + PICKUP_GUMP_GAP + PICKUP_GUMP_HEIGHT);
 	}
-	if (it == _children.end()) {
-		int32 yoff = PICKUP_GUMP_GAP;
-		if (_children.size() > 0)
-			yoff += PICKUP_GUMP_HEIGHT;
 
-		Gump *newgump = new CruPickupGump(item, yoff);
-		newgump->InitGump(this, false);
-	}
+	// didn't find one, create a new one at the bottom.
+	Gump *newgump = new CruPickupGump(item, maxy);
+	newgump->InitGump(this, false);
 }
 
 void CruPickupAreaGump::saveData(Common::WriteStream *ws) {


Commit: dbad8518dcbee6433749fa2c594e0cbf04d28e61
    https://github.com/scummvm/scummvm/commit/dbad8518dcbee6433749fa2c594e0cbf04d28e61
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:53+09:00

Commit Message:
ULTIMA8: Implement Crusader style pathfinder

Changed paths:
  A engines/ultima/ultima8/world/actors/cru_pathfinder_process.cpp
  A engines/ultima/ultima8/world/actors/cru_pathfinder_process.h
    engines/ultima/module.mk
    engines/ultima/ultima8/world/actors/actor.cpp
    engines/ultima/ultima8/world/actors/attack_process.cpp
    engines/ultima/ultima8/world/actors/attack_process.h
    engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
    engines/ultima/ultima8/world/actors/pathfinder_process.h


diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index c336cc0737..120468d620 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -555,6 +555,7 @@ MODULE_OBJS := \
 	ultima8/world/actors/clear_feign_death_process.o \
 	ultima8/world/actors/cru_avatar_mover_process.o \
 	ultima8/world/actors/cru_healer_process.o \
+	ultima8/world/actors/cru_pathfinder_process.o \
 	ultima8/world/actors/combat_dat.o \
 	ultima8/world/actors/combat_process.o \
 	ultima8/world/actors/grant_peace_process.o \
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 3b8985e3f6..42ce0b2236 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -617,6 +617,9 @@ uint16 Actor::turnTowardDir(Direction targetdir) {
 		}
 	}
 
+	if (targetdir == curdir)
+		return 0; // nothing to do.
+
 	if (combat) {
 		turnanim = Animation::combatStand;
 		standanim = Animation::combatStand;
diff --git a/engines/ultima/ultima8/world/actors/attack_process.cpp b/engines/ultima/ultima8/world/actors/attack_process.cpp
index 7241f0833b..aa407ebffa 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.cpp
+++ b/engines/ultima/ultima8/world/actors/attack_process.cpp
@@ -36,7 +36,7 @@
 #include "ultima/ultima8/world/loop_script.h"
 #include "ultima/ultima8/world/actors/combat_dat.h"
 #include "ultima/ultima8/world/actors/loiter_process.h"
-#include "ultima/ultima8/world/actors/pathfinder_process.h"
+#include "ultima/ultima8/world/actors/cru_pathfinder_process.h"
 #include "ultima/ultima8/misc/direction_util.h"
 
 namespace Ultima {
@@ -58,6 +58,7 @@ static const int16 ATTACK_SFX_7[] = {0x9B, 0x9C, 0x9D, 0x9E, 0x9F};
 // read from the data array.
 static const int MAGIC_DATA_OFF = 33000;
 
+const uint16 AttackProcess::ATTACK_PROCESS_TYPE = 0x259;
 
 static uint16 someSleepGlobal = 0;
 
@@ -66,7 +67,6 @@ static bool World_FinishedAvatarMoveTimeout() {
 	return true;
 }
 
-
 static inline int32 randomOf(int32 max) {
 	return (max > 0 ? getRandom() % max : 0);
 }
@@ -141,7 +141,7 @@ _soundTimestamp(0), _fireTimestamp(0) {
 		}
 	}
 
-	_type = 0x0259; // CONSTANT !
+	_type = ATTACK_PROCESS_TYPE;
 
 	setTacticNo(actor->getCombatTactic());
 }
@@ -242,7 +242,7 @@ void AttackProcess::run() {
 			int32 x, y, z;
 			a->getHomePosition(x, y, z);
 			ProcId pid = Kernel::get_instance()->addProcess(
-					   new PathfinderProcess(a, x, y, z));
+					   new CruPathfinderProcess(a, x, y, z, 100, 0x40, true));
 			waitFor(pid);
 			return;
 		}
@@ -252,7 +252,7 @@ void AttackProcess::run() {
 			int32 x, y, z;
 			target->getLocation(x, y, z);
 			ProcId pid = Kernel::get_instance()->addProcess(
-					   new PathfinderProcess(a, x, y, z));
+					   new CruPathfinderProcess(a, x, y, z, 12, 0x40, true));
 			waitFor(pid);
 			return;
 		}
@@ -267,7 +267,7 @@ void AttackProcess::run() {
 			int32 y = (ty + ay) / 2;
 			int32 z = (tz + az) / 2;
 			ProcId pid = Kernel::get_instance()->addProcess(
-					   new PathfinderProcess(a, x, y, z));
+					   new CruPathfinderProcess(a, x, y, z, 12, 0x40, true));
 			waitFor(pid);
 			return;
 		}
@@ -395,7 +395,7 @@ void AttackProcess::run() {
 
 				if (itemFrame == targetFrame && (targetQ == 0 || itemQlo == targetQ)) {
 					ProcId pid = Kernel::get_instance()->addProcess(
-						 new PathfinderProcess(a, founditem->getObjId()));
+						 new CruPathfinderProcess(a, founditem, 100, 0x40, true));
 					waitFor(pid);
 					break;
 				}
@@ -551,7 +551,7 @@ void AttackProcess::genericAttack() {
 			y += -0x1ff + randomOf(0x400);
 			_field96 = true;
 			const ProcId pid = Kernel::get_instance()->addProcess(
-								new PathfinderProcess(a, x, y, z));
+								new CruPathfinderProcess(a, x, y, z, 12, 0x40, true));
 			// add a tiny delay to avoid tight loops
 			Process *delayproc = new DelayProcess(2);
 			Kernel::get_instance()->addProcess(delayproc);
@@ -831,7 +831,7 @@ void AttackProcess::pathfindToItemInNPCData() {
 	Actor *a = getActor(_itemNum);
 	Actor *target = getActor(_target);
 
-	Process *pathproc = new PathfinderProcess(a, target->getObjId());
+	Process *pathproc = new CruPathfinderProcess(a, target, 12, 0x40, false);
 	// In case pathfinding fails delay for a bit to ensure we don't get
 	// stuck in a tight loop using all the cpu
 	Process *delayproc = new DelayProcess(10);
diff --git a/engines/ultima/ultima8/world/actors/attack_process.h b/engines/ultima/ultima8/world/actors/attack_process.h
index 18065acccd..73a8650ce7 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.h
+++ b/engines/ultima/ultima8/world/actors/attack_process.h
@@ -63,12 +63,20 @@ public:
 	void setField97() {
 		_field97 = true;
 	}
+	void setField7F() {
+		_field7f = true;
+	}
 
 	void setTimer3();
 
+	uint16 getTarget() const {
+		return _target;
+	}
+
 	bool loadData(Common::ReadStream *rs, uint32 version);
 	void saveData(Common::WriteStream *ws) override;
 
+	static const uint16 ATTACK_PROCESS_TYPE;
 private:
 	/** Set the current tactic in use from the combat.dat file.  If 0,
 	 * will use the genericAttack function. */
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 bf7f0c7422..2d1af824e7 100644
--- a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -236,11 +236,11 @@ void CruAvatarMoverProcess::handleCombatMode() {
 		idleanim = Animation::stopRunningAndDrawSmallWeapon;
 	}
 
-	// not doing anything in particular? stand
-	if (lastanim != idleanim) {
-		Animation::Sequence nextanim = Animation::checkWeapon(idleanim, lastanim);
-		waitFor(avatar->doAnim(nextanim, direction));
-	}
+	// not doing anything in particular? stand.  Always do the anim here as we
+	// may need to switch from small wpn to large wpn
+	Animation::Sequence nextanim = Animation::checkWeapon(idleanim, lastanim);
+	waitFor(avatar->doAnim(nextanim, direction));
+
 }
 
 void CruAvatarMoverProcess::handleNormalMode() {
diff --git a/engines/ultima/ultima8/world/actors/cru_pathfinder_process.cpp b/engines/ultima/ultima8/world/actors/cru_pathfinder_process.cpp
new file mode 100644
index 0000000000..09cab40703
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/cru_pathfinder_process.cpp
@@ -0,0 +1,375 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ultima/ultima8/world/actors/cru_pathfinder_process.h"
+#include "ultima/ultima8/world/actors/pathfinder_process.h"
+#include "ultima/ultima8/world/actors/attack_process.h"
+
+#include "ultima/ultima8/world/actors/animation.h"
+#include "ultima/ultima8/world/actors/actor.h"
+#include "ultima/ultima8/world/item.h"
+#include "ultima/ultima8/world/get_object.h"
+#include "ultima/ultima8/world/world.h"
+#include "ultima/ultima8/world/actors/pathfinder.h"
+#include "ultima/ultima8/misc/direction_util.h"
+#include "ultima/ultima8/kernel/kernel.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+static const int8 PATHFIND_DIR_OFFSETS_1[8] = {0,  2, -2,  4, -4,  6, -6, -8};
+static const int8 PATHFIND_DIR_OFFSETS_2[8] = {0, -2,  2, -4,  4, -6,  6, -8};
+
+DEFINE_RUNTIME_CLASSTYPE_CODE(CruPathfinderProcess)
+
+CruPathfinderProcess::CruPathfinderProcess() : Process(),
+		_currentStep(0), _targetItem(0), _currentDistance(0),
+		_targetX(0), _targetY(0), _targetZ(0), _randomFlag(false),
+		_nextTurn(false), _turnAtEnd(false), _lastDir(dir_current),
+		_nextDir(dir_current), _nextDir2(dir_current),
+		_solidObject(true), _directPathBlocked(false), _noShotAvailable(true),
+		_dir16Flag(false), _stopDistance(0)
+{
+}
+
+CruPathfinderProcess::CruPathfinderProcess(Actor *actor, Item *target, int maxsteps, int stopdistance, bool turnatend) :
+		_currentStep(0), _currentDistance(0), _targetX(0), _targetY(0), _targetZ(0),
+		_maxSteps(maxsteps), _stopDistance(stopdistance), _nextTurn(false), _turnAtEnd(turnatend),
+		_lastDir(dir_current), _nextDir(dir_current), _nextDir2(dir_current),
+		_directPathBlocked(false), _noShotAvailable(true), _dir16Flag(false) {
+	assert(actor && target);
+	_itemNum = actor->getObjId();
+	_type = PathfinderProcess::PATHFINDER_PROC_TYPE;
+	_randomFlag = (getRandom() % 2) != 0;
+	_targetItem = target->getObjId();
+	target->getLocation(_targetX, _targetY, _targetZ);
+
+	int32 ax, ay, az;
+	actor->getLocation(ax, ay, az);
+	_currentDistance = MAX(abs(ax - _targetX), abs(ay - _targetY));
+
+	const ShapeInfo *si = actor->getShapeInfo();
+	_solidObject = (si->_flags & ShapeInfo::SI_SOLID) && si->_z > 0;
+
+	// TODO: check if flag already set? kill other pathfinders?
+	assert(!actor->hasActorFlags(Actor::ACT_PATHFINDING));
+	actor->setActorFlag(Actor::ACT_PATHFINDING);
+}
+
+CruPathfinderProcess::CruPathfinderProcess(Actor *actor, int32 x, int32 y, int32 z, int maxsteps, int stopdistance, bool turnatend) :
+		_targetX(x), _targetY(y), _targetZ(z), _targetItem(0), _currentStep(0),
+		_maxSteps(maxsteps), _stopDistance(stopdistance), _nextTurn(false), _turnAtEnd(turnatend),
+		_lastDir(dir_current), _nextDir(dir_current), _nextDir2(dir_current),
+		_directPathBlocked(false), _noShotAvailable(true), _dir16Flag(false) {
+	assert(actor);
+	_itemNum = actor->getObjId();
+	_type = PathfinderProcess::PATHFINDER_PROC_TYPE;
+	_randomFlag = (getRandom() % 2) != 0;
+
+	int32 ax, ay, az;
+	actor->getLocation(ax, ay, az);
+	_currentDistance = MAX(abs(ax - _targetX), abs(ay - _targetY));
+
+	const ShapeInfo *si = actor->getShapeInfo();
+	_solidObject = (si->_flags & ShapeInfo::SI_SOLID) && si->_z > 0;
+
+	// TODO: check if flag already set? kill other pathfinders?
+	assert(!actor->hasActorFlags(Actor::ACT_PATHFINDING));
+	actor->setActorFlag(Actor::ACT_PATHFINDING);
+}
+
+CruPathfinderProcess::~CruPathfinderProcess() {
+}
+
+void CruPathfinderProcess::terminate() {
+	Actor *actor = getActor(_itemNum);
+	if (actor && !actor->isDead()) {
+		// TODO: only clear if it was set by us?
+		// (slightly more complicated if we kill other pathfinders on startup)
+		actor->clearActorFlag(Actor::ACT_PATHFINDING);
+
+		uint16 turnproc = 0;
+		if (_turnAtEnd) {
+			Direction destdir = dir_current;
+			// TODO: this logic can be cleaned up a bit by just updating targetx/y?
+			int32 ix, iy, iz;
+			actor->getLocationAbsolute(ix, iy, iz);
+			if (_targetItem == 0) {
+				destdir = Direction_GetWorldDir(_targetY - iy, _targetX - ix, dirmode_8dirs);
+			} else {
+				Item *target = getItem(_targetItem);
+				if (target) {
+					int32 tx, ty, tz;
+					target->getLocationAbsolute(tx, ty, tz);
+					destdir = Direction_GetWorldDir(ty - iy, tx - ix, dirmode_8dirs);
+				}
+			}
+			turnproc = actor->turnTowardDir(destdir);
+		}
+		if (!turnproc && _noShotAvailable) {
+			Animation::Sequence standanim = (actor->isInCombat() ? Animation::combatStandSmallWeapon : Animation::stand);
+			actor->doAnim(standanim, dir_current);
+		}
+	}
+
+	Process::terminate();
+}
+
+Direction CruPathfinderProcess::nextDirFromPoint(struct Point3 &npcpt) {
+	const Direction dirtotarget = Direction_GetWorldDir(_targetY - npcpt.y, _targetX - npcpt.x, dirmode_8dirs);
+	Actor *npc = getActor(_itemNum);
+
+	//assert(npc);
+
+	const int maxdiffxy = MAX(abs(npcpt.x - _targetX), abs(npcpt.y - _targetY));
+	if (maxdiffxy < _currentDistance) {
+		// each time we get closer, check again if we can walk toward the target.
+		_currentDistance = maxdiffxy;
+		PathfindingState state;
+		state._x = npcpt.x;
+		state._y = npcpt.y;
+		state._z = npcpt.z;
+		state._direction = dirtotarget;
+		state._combat = npc->isInCombat();
+		Animation::Sequence anim = npc->isInCombat() ? Animation::walk : Animation::advanceSmallWeapon;
+		Animation::Result result = npc->tryAnim(anim, dirtotarget, 0, &state);
+		if (result == Animation::SUCCESS) {
+			_directPathBlocked = false;
+		}
+	}
+
+	int startoff = 0;
+	Direction dirtable[8];
+	Direction nextdir_table[8];
+
+	if (!_directPathBlocked) {
+		for (int i = 0; i < 8; i++) {
+			if (_randomFlag) {
+				dirtable[i] = Direction_TurnByDelta(dirtotarget, PATHFIND_DIR_OFFSETS_1[i], dirmode_16dirs);
+			} else {
+				dirtable[i] = Direction_TurnByDelta(dirtotarget, PATHFIND_DIR_OFFSETS_2[i], dirmode_16dirs);
+			}
+		}
+
+	} else {
+
+		int diroffset;
+		if (_randomFlag) {
+			diroffset = (_nextTurn ? 2 : -2);
+		} else {
+			diroffset = (_nextTurn ? -2 : 2);
+		}
+		nextdir_table[0] = Direction_TurnByDelta(_nextDir, diroffset + 8, dirmode_16dirs);
+
+		for (int i = 1; i < 8; i++) {
+			if (_randomFlag) {
+				diroffset = (_nextTurn ? 2 : -2);
+			} else {
+				diroffset = (_nextTurn ? -2 : 2);
+			}
+			nextdir_table[i] = Direction_TurnByDelta(nextdir_table[i - 1], diroffset, dirmode_16dirs);
+		}
+		startoff = 1;
+	}
+
+	PathfindingState state;
+	Animation::Result animresult = Animation::SUCCESS;
+	int i;
+	for (i = startoff; i < 8; i++) {
+		// TODO: double-check these in disasm
+		if (_directPathBlocked && i == 2)
+			continue;
+		if (_directPathBlocked && i == 7)
+			break;
+
+		if (_directPathBlocked)
+			_nextDir2 = nextdir_table[i];
+		else
+			_nextDir2 = dirtable[i];
+
+		// LAB_1110_0c26:
+		Animation::Sequence anim = npc->isInCombat() ? Animation::walk : Animation::advanceSmallWeapon;
+		state._x = npcpt.x;
+		state._y = npcpt.y;
+		state._z = npcpt.z;
+		state._direction = _nextDir2;
+		state._combat = npc->isInCombat();
+		animresult = npc->tryAnim(anim, _nextDir2, 0, &state);
+
+		// Note: this will never trigger in our code -
+		// "tryAnim" code seems to behave differently in original?
+		/*if (_solidObject && ((_result >> 1) & 1)) {
+			_turnAtEnd = true;
+			return dir_invalid;
+		}*/
+
+		if (_stopDistance && (MAX(abs(_targetX - state._x), abs(_targetY - state._y)) <= _stopDistance)) {
+			_turnAtEnd = true;
+			return dir_invalid;
+		}
+
+		if (animresult == Animation::SUCCESS)
+			break;
+	}
+
+	// LAB_1110_0dd5:
+	if (animresult != Animation::SUCCESS)
+		return dir_current;
+
+	if ((_nextDir2 != dirtotarget) && !_directPathBlocked) {
+		_directPathBlocked = true;
+		_nextTurn = (i % 2);
+	}
+
+	npcpt.x = state._x;
+	npcpt.y = state._y;
+	npcpt.z = state._z;
+	bool is_controlled = World::get_instance()->getControlledNPCNum() == _itemNum;
+	if (npc->isInCombat() && !is_controlled) {
+		AttackProcess *attackproc = dynamic_cast<AttackProcess *>
+				(Kernel::get_instance()->findProcess(_itemNum, AttackProcess::ATTACK_PROCESS_TYPE));
+		if (attackproc) {
+			const Actor *target = getActor(attackproc->getTarget());
+			if (target && npc->isOnScreen() && npc->fireDistance(target, dirtotarget, 0, 0, 0)) {
+				npc->doAnim(Animation::stand, dir_current);
+				attackproc->setField7F();
+				_noShotAvailable = false;
+				_turnAtEnd = true;
+				return dir_invalid;
+			}
+		}
+	}
+	return _nextDir2;
+}
+
+
+void CruPathfinderProcess::run() {
+	Actor *npc = getActor(_itemNum);
+	if (!npc || !npc->hasFlags(Item::FLG_FASTAREA))
+		return;
+
+	if (npc->isDead()) {
+		terminate();
+		return;
+	}
+
+	if (_dir16Flag) {
+		terminate(); // terminate 1
+		return;
+	}
+
+	if (_targetItem != 0 && _solidObject) {
+		Item *target = getItem(_targetItem);
+		if (target)
+			target->getLocation(_targetX, _targetY, _targetZ);
+	}
+
+	Point3 npcpt;
+	npc->getLocation(npcpt);
+
+	if (_targetX == npcpt.x && _targetY == npcpt.y) {
+		terminate(); // _destpt.z != npcpt.z
+		return;
+	}
+	const Direction lastdir = _nextDir;
+	_nextDir = nextDirFromPoint(npcpt);
+	_lastDir = lastdir;
+	if (_nextDir == dir_current) {
+	   terminate(); //0
+		return;
+	}
+
+	if (_nextDir == dir_invalid) {
+		_dir16Flag = true;
+	} else {
+	   if (_currentStep == _maxSteps) {
+			terminate(); //0
+			return;
+		}
+	}
+
+	Direction newdir;
+	if (!_dir16Flag) {
+		newdir = _nextDir;
+	} else {
+		newdir = _nextDir2;
+	}
+
+	uint16 turnpid = npc->turnTowardDir(newdir);
+	Animation::Sequence anim = npc->isInCombat() ? Animation::advanceSmallWeapon : Animation::walk;
+	uint16 animpid = npc->doAnim(anim, newdir);
+	if (turnpid)
+		Kernel::get_instance()->getProcess(animpid)->waitFor(turnpid);
+	waitFor(animpid);
+	_currentStep += 1;
+}
+
+void CruPathfinderProcess::saveData(Common::WriteStream *ws) {
+	Process::saveData(ws);
+
+	ws->writeUint16LE(_targetItem);
+	ws->writeUint16LE(static_cast<uint16>(_targetX));
+	ws->writeUint16LE(static_cast<uint16>(_targetY));
+	ws->writeUint16LE(static_cast<uint16>(_targetZ));
+	ws->writeUint16LE(static_cast<uint16>(_currentDistance));
+	ws->writeByte(_randomFlag ? 1 : 0);
+	ws->writeByte(_nextTurn ? 1 : 0);
+	ws->writeByte(_turnAtEnd ? 1 : 0);
+	ws->writeByte(_lastDir);
+	ws->writeByte(_nextDir);
+	ws->writeByte(_nextDir2);
+	ws->writeByte(_solidObject ? 1 : 0);
+	ws->writeByte(_directPathBlocked ? 1 : 0);
+	ws->writeByte(_noShotAvailable ? 1 : 0);
+	ws->writeByte(_dir16Flag ? 1 : 0);
+	ws->writeUint16LE(static_cast<uint16>(_currentStep));
+	ws->writeUint16LE(static_cast<uint16>(_maxSteps));
+	ws->writeUint16LE(static_cast<uint16>(_stopDistance));
+}
+
+bool CruPathfinderProcess::loadData(Common::ReadStream *rs, uint32 version) {
+	if (!Process::loadData(rs, version)) return false;
+
+	_targetItem = rs->readUint16LE();
+	_targetX = rs->readUint16LE();
+	_targetY = rs->readUint16LE();
+	_targetZ = rs->readUint16LE();
+	_currentDistance = rs->readUint16LE();
+	_randomFlag = rs->readByte();
+	_nextTurn = rs->readByte();
+	_turnAtEnd = rs->readByte();
+	_lastDir = static_cast<Direction>(rs->readByte());
+	_nextDir = static_cast<Direction>(rs->readByte());
+	_nextDir2 = static_cast<Direction>(rs->readByte());
+	_solidObject = rs->readByte();
+	_directPathBlocked = rs->readByte();
+	_noShotAvailable = rs->readByte();
+	_dir16Flag = rs->readByte();
+	_currentStep = rs->readUint16LE();
+	_maxSteps = rs->readUint16LE();
+	_stopDistance = rs->readUint16LE();
+
+	return true;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/actors/cru_pathfinder_process.h b/engines/ultima/ultima8/world/actors/cru_pathfinder_process.h
new file mode 100644
index 0000000000..ea59e6ed1f
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/cru_pathfinder_process.h
@@ -0,0 +1,84 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WORLD_ACTORS_CRU_PATHFINDERPROCESS_H
+#define WORLD_ACTORS_CRU_PATHFINDERPROCESS_H
+
+#include "ultima/ultima8/kernel/process.h"
+#include "ultima/ultima8/misc/direction.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+class Actor;
+class Item;
+
+/**
+ * A simplified pathfinder used in Crusader for the AttackProcess.
+ *
+ * The code and variable names for this are not very well written as
+ * they are are based on the disassembly.
+ */
+class CruPathfinderProcess : public Process {
+public:
+	CruPathfinderProcess();
+	CruPathfinderProcess(Actor *actor, Item *item, int maxsteps, int stopdistance, bool turnatend);
+	CruPathfinderProcess(Actor *actor, int32 x, int32 y, int32 z, int maxsteps, int stopdistance, bool turnatend);
+	~CruPathfinderProcess() override;
+
+	ENABLE_RUNTIME_CLASSTYPE()
+
+	void run() override;
+	void terminate() override;
+
+	bool loadData(Common::ReadStream *rs, uint32 version);
+	void saveData(Common::WriteStream *ws) override;
+
+private:
+
+	Direction nextDirFromPoint(struct Point3 &npcpt);
+
+	int32 _targetX, _targetY, _targetZ;
+	ObjId _targetItem;
+	int _currentDistance;
+	bool _randomFlag;
+	bool _nextTurn;
+	bool _turnAtEnd;
+
+	Direction _lastDir;
+	Direction _nextDir;
+	Direction _nextDir2;
+
+	bool _solidObject;
+	bool _directPathBlocked;
+	bool _noShotAvailable;
+	bool _dir16Flag;
+
+	unsigned int _currentStep;
+	unsigned int _maxSteps;
+	int _stopDistance;
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima8/world/actors/pathfinder_process.h b/engines/ultima/ultima8/world/actors/pathfinder_process.h
index f42bc7b862..41e0dedea8 100644
--- a/engines/ultima/ultima8/world/actors/pathfinder_process.h
+++ b/engines/ultima/ultima8/world/actors/pathfinder_process.h
@@ -44,8 +44,6 @@ public:
 	void run() override;
 	void terminate() override;
 
-//	virtual void terminate();
-
 	bool loadData(Common::ReadStream *rs, uint32 version);
 	void saveData(Common::WriteStream *ws) override;
 


Commit: 96f2381926e442b8cf33ac041e65dabe044b44f5
    https://github.com/scummvm/scummvm/commit/96f2381926e442b8cf33ac041e65dabe044b44f5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00

Commit Message:
ULTIMA8: Improve const correctness

Changed paths:
    engines/ultima/ultima8/ultima8.cpp
    engines/ultima/ultima8/world/item.cpp
    engines/ultima/ultima8/world/item.h


diff --git a/engines/ultima/ultima8/ultima8.cpp b/engines/ultima/ultima8/ultima8.cpp
index 7764488879..e52b3000a3 100644
--- a/engines/ultima/ultima8/ultima8.cpp
+++ b/engines/ultima/ultima8/ultima8.cpp
@@ -71,6 +71,7 @@
 #include "ultima/ultima8/world/actors/pathfinder_process.h"
 #include "ultima/ultima8/world/actors/u8_avatar_mover_process.h"
 #include "ultima/ultima8/world/actors/cru_avatar_mover_process.h"
+#include "ultima/ultima8/world/actors/cru_pathfinder_process.h"
 #include "ultima/ultima8/world/actors/resurrection_process.h"
 #include "ultima/ultima8/world/actors/clear_feign_death_process.h"
 #include "ultima/ultima8/world/actors/loiter_process.h"
@@ -224,6 +225,8 @@ bool Ultima8Engine::startup() {
 		ProcessLoader<QuickAvatarMoverProcess>::load);
 	_kernel->addProcessLoader("PathfinderProcess",
 		ProcessLoader<PathfinderProcess>::load);
+	_kernel->addProcessLoader("CruPathfinderProcess",
+		ProcessLoader<CruPathfinderProcess>::load);
 	_kernel->addProcessLoader("SpriteProcess",
 		ProcessLoader<SpriteProcess>::load);
 	_kernel->addProcessLoader("CameraProcess",
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index b52b0369ce..b2c957af68 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1300,7 +1300,7 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
 	return spriteprocpid;
 }
 
-uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff) {
+uint16 Item::fireDistance(const Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff) {
 	if (!other)
 		return 0;
 
@@ -1413,7 +1413,7 @@ uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, in
 	return dist / 32;
 }
 
-int32 Item::getTargetZRelativeToAttackerZ(int32 otherz) {
+int32 Item::getTargetZRelativeToAttackerZ(int32 otherz) const {
 	int32 tsx, tsy, tsz;
 	getFootpadData(tsx, tsy, tsz);
 
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index 82a9cb010a..41b0a13087 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -395,7 +395,7 @@ public:
 
 	//! get the distance (in map tiles) if we were to fire in this direction to "other"
 	//! and could hit, otherwise return 0.
-	uint16 fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff);
+	uint16 fireDistance(const Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff);
 
 	//! get damage points, used in Crusader for item damage.
 	uint8 getDamagePoints() const {
@@ -662,7 +662,7 @@ private:
 
 	//! Get the right Z which an attacker should aim for, given the attacker's z.
 	//! (Crusader only)
-	int32 getTargetZRelativeToAttackerZ(int32 attackerz);
+	int32 getTargetZRelativeToAttackerZ(int32 attackerz) const;
 
 public:
 	enum statusflags {


Commit: 19648041c7c2e83bafea999e1fadd8034b4e291d
    https://github.com/scummvm/scummvm/commit/19648041c7c2e83bafea999e1fadd8034b4e291d
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00

Commit Message:
ULTIMA8: Remove dead code

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


diff --git a/engines/ultima/ultima8/games/game_data.cpp b/engines/ultima/ultima8/games/game_data.cpp
index abcdf15d61..9c1aac50a2 100644
--- a/engines/ultima/ultima8/games/game_data.cpp
+++ b/engines/ultima/ultima8/games/game_data.cpp
@@ -542,10 +542,6 @@ void GameData::loadRemorseData() {
 	ConfigFileManager *config = ConfigFileManager::get_instance();
 	// Load weapon, armour info
 	config->readConfigFile("data/remorseweapons.ini", "weapons");
-#if 0
-	config->readConfigFile("data/u8armour.ini", "armour");
-	config->readConfigFile("data/u8monsters.ini", "monsters");
-#endif
 	config->readConfigFile("data/remorse.ini", "game");
 
 	// Load typeflags


Commit: 36b42f92fe1c659d8e8b0bb39a0c71edd0063cc3
    https://github.com/scummvm/scummvm/commit/36b42f92fe1c659d8e8b0bb39a0c71edd0063cc3
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00

Commit Message:
ULTIMA8: Get Crusader inventory shape dyanmically as it can change

Changed paths:
    engines/ultima/ultima8/gumps/cru_inventory_gump.cpp
    engines/ultima/ultima8/gumps/cru_inventory_gump.h


diff --git a/engines/ultima/ultima8/gumps/cru_inventory_gump.cpp b/engines/ultima/ultima8/gumps/cru_inventory_gump.cpp
index ced54b8744..0c6cd18f5d 100644
--- a/engines/ultima/ultima8/gumps/cru_inventory_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_inventory_gump.cpp
@@ -32,18 +32,14 @@
 namespace Ultima {
 namespace Ultima8 {
 
-static const int INVENTORY_GUMP_SHAPE = 5;
 static const int INVENTORY_TEXT_FONT = 12;
 
 DEFINE_RUNTIME_CLASSTYPE_CODE(CruInventoryGump)
-CruInventoryGump::CruInventoryGump() : CruStatGump(), _inventoryShape(nullptr),
-	_inventoryItemGump(nullptr), _inventoryText(nullptr) {
-
+CruInventoryGump::CruInventoryGump() : CruStatGump(), _inventoryItemGump(nullptr), _inventoryText(nullptr) {
 }
 
 CruInventoryGump::CruInventoryGump(Shape *shape, int x)
-	: CruStatGump(shape, x), _inventoryShape(nullptr), _inventoryItemGump(nullptr),
-		_inventoryText(nullptr) {
+	: CruStatGump(shape, x), _inventoryItemGump(nullptr), _inventoryText(nullptr) {
 	_frameNum = 0;
 }
 
@@ -59,11 +55,6 @@ void CruInventoryGump::InitGump(Gump *newparent, bool take_focus) {
 		return;
 	}
 
-	_inventoryShape = gumpshapes->getShape(INVENTORY_GUMP_SHAPE);
-	if (!_inventoryShape || !_inventoryShape->getFrame(0)) {
-		warning("failed to init stat gump: no inventory shape");
-		return;
-	}
 	_inventoryItemGump = new Gump();
 	_inventoryItemGump->InitGump(this, false);
 	// we'll set the shape for this gump later.
@@ -119,8 +110,19 @@ void CruInventoryGump::PaintThis(RenderSurface *surf, int32 lerp_factor, bool sc
 		if (!item) {
 			_inventoryItemGump->SetShape(0, 0);
 		} else {
-			uint16 frame = getDisplayFrameForShape(item->getShape());
-			_inventoryItemGump->SetShape(_inventoryShape, frame);
+			GumpShapeArchive *gumpshapes = GameData::get_instance()->getGumps();
+			if (!gumpshapes) {
+				warning("failed to paint stat gump: no gump shape archive");
+				return;
+			}
+
+			const ShapeInfo *shapeinfo = item->getShapeInfo();
+			if (!shapeinfo->_weaponInfo) {
+				warning("no weapon info for active inventory item %d", item->getShape());
+				return;
+			}
+			Shape *invshape = gumpshapes->getShape(shapeinfo->_weaponInfo->_displayGumpShape);
+			_inventoryItemGump->SetShape(invshape, shapeinfo->_weaponInfo->_displayGumpFrame);
 			_inventoryItemGump->UpdateDimsFromShape();
 			_inventoryItemGump->setRelativePosition(CENTER);
 
diff --git a/engines/ultima/ultima8/gumps/cru_inventory_gump.h b/engines/ultima/ultima8/gumps/cru_inventory_gump.h
index c074085dbb..f69a7941d9 100644
--- a/engines/ultima/ultima8/gumps/cru_inventory_gump.h
+++ b/engines/ultima/ultima8/gumps/cru_inventory_gump.h
@@ -52,7 +52,6 @@ public:
 	void saveData(Common::WriteStream *ws) override;
 
 private:
-	Shape *_inventoryShape;
 	Gump *_inventoryItemGump;
 	TextWidget *_inventoryText;
 };


Commit: 52a40f33afaaa8a0c0b1dfdc2759c61c4d0d45e6
    https://github.com/scummvm/scummvm/commit/52a40f33afaaa8a0c0b1dfdc2759c61c4d0d45e6
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00

Commit Message:
ULTIMA8: Also show bombs in cru inventory

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


diff --git a/engines/ultima/ultima8/world/actors/main_actor.cpp b/engines/ultima/ultima8/world/actors/main_actor.cpp
index b72169f0d5..81c90e9622 100644
--- a/engines/ultima/ultima8/world/actors/main_actor.cpp
+++ b/engines/ultima/ultima8/world/actors/main_actor.cpp
@@ -677,6 +677,7 @@ void MainActor::nextWeapon() {
 void MainActor::nextInvItem() {
 	Std::vector<Item *> items;
 	getItemsWithShapeFamily(items, ShapeInfo::SF_CRUINVITEM, true);
+	getItemsWithShapeFamily(items, ShapeInfo::SF_CRUBOMB, true);
 	_activeInvItem = getIdOfNextItemInList(items, _activeInvItem);
 }
 


Commit: 3b49490597eb9ac0023bafab3d961177fd9678fd
    https://github.com/scummvm/scummvm/commit/3b49490597eb9ac0023bafab3d961177fd9678fd
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:56:56+09:00

Commit Message:
ULTIMA8: Refactor isBusy logic to Actor

Changed paths:
    engines/ultima/ultima8/world/actors/actor.cpp
    engines/ultima/ultima8/world/actors/actor.h
    engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
    engines/ultima/ultima8/world/actors/attack_process.cpp
    engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
    engines/ultima/ultima8/world/actors/guard_process.cpp
    engines/ultima/ultima8/world/actors/pace_process.cpp
    engines/ultima/ultima8/world/actors/surrender_process.cpp


diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 42ce0b2236..1331eb6c72 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -512,6 +512,11 @@ uint16 Actor::doAnim(Animation::Sequence anim, Direction dir, unsigned int steps
 	return Kernel::get_instance()->addProcess(p);
 }
 
+bool Actor::isBusy() const {
+	uint32 count = Kernel::get_instance()->getNumProcesses(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
+	return count != 0;
+}
+
 bool Actor::hasAnim(Animation::Sequence anim) {
 	AnimationTracker tracker;
 
@@ -1270,7 +1275,7 @@ ProcId Actor::killAllButFallAnims(bool death) {
 
 	if (death) {
 		// if dead, we want to kill everything but animations
-		kernel->killProcessesNotOfType(_objId, 0xF0, true);
+		kernel->killProcessesNotOfType(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE, true);
 	} else {
 		// otherwise, need to focus on combat, so kill everything else
 		killAllButCombatProcesses();
@@ -2108,11 +2113,9 @@ uint32 Actor::I_areEnemiesNear(const uint8 *args, unsigned int /*argsize*/) {
 }
 
 uint32 Actor::I_isBusy(const uint8 *args, unsigned int /*argsize*/) {
-	ARG_UC_PTR(ptr);
-	uint16 id = UCMachine::ptrToObject(ptr);
+	ARG_ACTOR_FROM_PTR(actor);
 
-	uint32 count = Kernel::get_instance()->getNumProcesses(id, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
-	if (count > 0)
+	if (actor->isBusy())
 		return 1;
 	else
 		return 0;
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 8da4011f2f..e8cbe9c637 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -248,6 +248,9 @@ public:
 	//! Get the number of directions supported by a given animation
 	DirectionMode animDirMode(Animation::Sequence anim) const;
 
+	//! True if the actor is currently doing an animation.
+	bool isBusy() const;
+
 	//! overrides the standard item collideMove so we  can notify nearby objects.
 	int32 collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
 	                  ObjId *hititem = 0, uint8 *dirs = 0) override;
diff --git a/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp b/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
index 88b14b82e5..3e5598befc 100644
--- a/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
@@ -23,7 +23,6 @@
 #include "ultima/ultima8/world/actors/actor_bark_notify_process.h"
 #include "ultima/ultima8/kernel/delay_process.h"
 #include "ultima/ultima8/world/actors/actor.h"
-#include "ultima/ultima8/world/actors/actor_anim_process.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/world/get_object.h"
 
@@ -57,7 +56,7 @@ void ActorBarkNotifyProcess::run() {
 	Animation::Sequence lastanim = a->getLastAnim();
 	if (lastanim != Animation::stand && lastanim != Animation::talk)
 		doAnim = false;
-	else if (Kernel::get_instance()->getNumProcesses(_itemNum, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE) > 0)
+	else if (a->isBusy())
 		// if busy, don't do talk animation
 		doAnim = false;
 
diff --git a/engines/ultima/ultima8/world/actors/attack_process.cpp b/engines/ultima/ultima8/world/actors/attack_process.cpp
index aa407ebffa..6ba2905787 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.cpp
+++ b/engines/ultima/ultima8/world/actors/attack_process.cpp
@@ -29,7 +29,6 @@
 #include "ultima/ultima8/kernel/delay_process.h"
 #include "ultima/ultima8/usecode/uc_list.h"
 #include "ultima/ultima8/world/actors/actor.h"
-#include "ultima/ultima8/world/actors/actor_anim_process.h"
 #include "ultima/ultima8/world/current_map.h"
 #include "ultima/ultima8/world/get_object.h"
 #include "ultima/ultima8/world/world.h"
@@ -516,8 +515,7 @@ void AttackProcess::genericAttack() {
 	Actor *a = getActor(_itemNum);
 	assert(a);
 
-	if (Kernel::get_instance()->getNumProcesses(_itemNum, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE)
-		|| a->hasActorFlags(Actor::ACT_PATHFINDING)) {
+	if (a->isBusy() || a->hasActorFlags(Actor::ACT_PATHFINDING)) {
 		return;
 	}
 
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
index fca71f8b2e..83e4d7bb66 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
@@ -40,17 +40,15 @@ AvatarMoverProcess::~AvatarMoverProcess() {
 }
 
 void AvatarMoverProcess::run() {
-	Kernel *kernel = Kernel::get_instance();
+	MainActor *avatar = getMainActor();
+	assert(avatar);
 
 	// busy, so don't move
-	if (kernel->getNumProcesses(1, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE) > 0) {
+	if (avatar->isBusy()) {
 		_idleTime = 0;
 		return;
 	}
 
-	MainActor *avatar = getMainActor();
-	assert(avatar);
-
 	if (avatar->getLastAnim() == Animation::hang) {
 		handleHangingMode();
 		return;
diff --git a/engines/ultima/ultima8/world/actors/guard_process.cpp b/engines/ultima/ultima8/world/actors/guard_process.cpp
index 676e582288..73de3fb143 100644
--- a/engines/ultima/ultima8/world/actors/guard_process.cpp
+++ b/engines/ultima/ultima8/world/actors/guard_process.cpp
@@ -50,8 +50,7 @@ void GuardProcess::run() {
 	}
 
 	// Do nothing if busy
-	int activeanim = Kernel::get_instance()->getNumProcesses(a->getObjId(), ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
-	if (activeanim > 0)
+	if (a->isBusy())
 		return;
 
 	Actor *mainactor = getMainActor();
diff --git a/engines/ultima/ultima8/world/actors/pace_process.cpp b/engines/ultima/ultima8/world/actors/pace_process.cpp
index 675ef4b790..7708d088aa 100644
--- a/engines/ultima/ultima8/world/actors/pace_process.cpp
+++ b/engines/ultima/ultima8/world/actors/pace_process.cpp
@@ -22,7 +22,6 @@
 
 #include "ultima/ultima8/world/actors/pace_process.h"
 #include "ultima/ultima8/world/actors/main_actor.h"
-#include "ultima/ultima8/world/actors/actor_anim_process.h"
 #include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/kernel/delay_process.h"
@@ -76,7 +75,7 @@ void PaceProcess::run() {
 	if (maybeStartDefaultActivity1(a))
 		return;
 
-	if (kernel->getNumProcesses(a->getObjId(), ActorAnimProcess::ACTOR_ANIM_PROC_TYPE)) {
+	if (a->isBusy()) {
 		return;
 	}
 
diff --git a/engines/ultima/ultima8/world/actors/surrender_process.cpp b/engines/ultima/ultima8/world/actors/surrender_process.cpp
index 3229bfcb4d..72363791cf 100644
--- a/engines/ultima/ultima8/world/actors/surrender_process.cpp
+++ b/engines/ultima/ultima8/world/actors/surrender_process.cpp
@@ -23,7 +23,6 @@
 #include "ultima/ultima8/audio/audio_process.h"
 #include "ultima/ultima8/world/actors/surrender_process.h"
 #include "ultima/ultima8/world/actors/main_actor.h"
-#include "ultima/ultima8/world/actors/actor_anim_process.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/world/get_object.h"
 
@@ -62,16 +61,10 @@ void SurrenderProcess::run() {
 		return;
 	}
 
-	// do nothing while we are not in the fast area
-	if (!a->hasFlags(Item::FLG_FASTAREA))
+	// do nothing while we are not in the fast area or busy
+	if (!a->hasFlags(Item::FLG_FASTAREA) || a->isBusy())
 		return;
 
-	int animating = Kernel::get_instance()->getNumProcesses(_itemNum, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE);
-	if (animating) {
-		// already busy.
-		return;
-	}
-
 	a->setActorFlag(Actor::ACT_SURRENDERED);
 
 	Direction curdir = a->getDir();


Commit: 1de427262f612baf7e1c2158879613b39f6977bd
    https://github.com/scummvm/scummvm/commit/1de427262f612baf7e1c2158879613b39f6977bd
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:59:40+09:00

Commit Message:
ULTIMA8: Update crusader stance after changing weapons

Changed paths:
    engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
    engines/ultima/ultima8/world/actors/main_actor.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 2d1af824e7..a33223ce2a 100644
--- a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -236,11 +236,11 @@ void CruAvatarMoverProcess::handleCombatMode() {
 		idleanim = Animation::stopRunningAndDrawSmallWeapon;
 	}
 
-	// not doing anything in particular? stand.  Always do the anim here as we
-	// may need to switch from small wpn to large wpn
-	Animation::Sequence nextanim = Animation::checkWeapon(idleanim, lastanim);
-	waitFor(avatar->doAnim(nextanim, direction));
-
+	// Not doing anything in particular? stand.
+	if (lastanim != idleanim) {
+		Animation::Sequence nextanim = Animation::checkWeapon(idleanim, lastanim);
+		waitFor(avatar->doAnim(nextanim, direction));
+	}
 }
 
 void CruAvatarMoverProcess::handleNormalMode() {
@@ -330,7 +330,7 @@ void CruAvatarMoverProcess::handleNormalMode() {
 		return;
 
 	// doing another animation?
-	if (Kernel::get_instance()->getNumProcesses(1, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE))
+	if (avatar->isBusy())
 		return;
 
 	// not doing anything in particular? stand
diff --git a/engines/ultima/ultima8/world/actors/main_actor.cpp b/engines/ultima/ultima8/world/actors/main_actor.cpp
index 81c90e9622..ca99520249 100644
--- a/engines/ultima/ultima8/world/actors/main_actor.cpp
+++ b/engines/ultima/ultima8/world/actors/main_actor.cpp
@@ -44,6 +44,7 @@
 #include "ultima/ultima8/world/fire_type.h"
 #include "ultima/ultima8/world/sprite_process.h"
 #include "ultima/ultima8/world/actors/avatar_gravity_process.h"
+#include "ultima/ultima8/world/actors/actor_anim_process.h"
 #include "ultima/ultima8/audio/music_process.h"
 #include "ultima/ultima8/world/actors/anim_action.h"
 
@@ -672,6 +673,16 @@ void MainActor::nextWeapon() {
 	Std::vector<Item *> weapons;
 	getItemsWithShapeFamily(weapons, ShapeInfo::SF_CRUWEAPON, true);
 	_activeWeapon = getIdOfNextItemInList(weapons, _activeWeapon);
+
+	// Update combat stance in case we switched big/small weapon.
+	if (_lastAnim == Animation::combatStand) {
+		if (isBusy()) {
+			// Corner case - need to stop active "stand"
+			// animation to correct it.
+			Kernel::get_instance()->killProcesses(_objId, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE, true);
+		}
+		doAnim(Animation::combatStand, dir_current);
+	}
 }
 
 void MainActor::nextInvItem() {


Commit: 6322e399ec9d97570cba97eeaa50e650fad2a9b5
    https://github.com/scummvm/scummvm/commit/6322e399ec9d97570cba97eeaa50e650fad2a9b5
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-03-28T12:59:43+09:00

Commit Message:
ULTIMA8: Fix fade on Crusader health/energy gumps

Changed paths:
    engines/ultima/ultima8/graphics/palette.cpp
    engines/ultima/ultima8/graphics/palette.h
    engines/ultima/ultima8/gumps/cru_energy_gump.cpp
    engines/ultima/ultima8/gumps/cru_health_gump.cpp


diff --git a/engines/ultima/ultima8/graphics/palette.cpp b/engines/ultima/ultima8/graphics/palette.cpp
index 466893e7ef..8593cde8aa 100644
--- a/engines/ultima/ultima8/graphics/palette.cpp
+++ b/engines/ultima/ultima8/graphics/palette.cpp
@@ -63,5 +63,23 @@ void Palette::load(Common::ReadStream &rs) {
 	_transform = Transform_None;
 }
 
+void Palette::transformRGB(int &r_, int &g_, int &b_) const {
+	const int r = r_;
+	const int g = g_;
+	const int b = b_;
+
+	r_ = (r * _matrix[0] + g * _matrix[1] + b * _matrix[2]  + 255 * _matrix[3]) / 2048;
+	if (r_ < 0) r_ = 0;
+	if (r_ > 0xFF) r_ = 0xFF;
+
+	g_ = (r * _matrix[4] + g * _matrix[5] + b * _matrix[6]  + 255 * _matrix[7]) / 2048;
+	if (g_ < 0) g_ = 0;
+	if (g_ > 0xFF) g_ = 0xFF;
+
+	b_ = (r * _matrix[8] + g * _matrix[9] + b * _matrix[10] + 255 * _matrix[11]) / 2048;
+	if (b_ < 0) b_ = 0;
+	if (b_ > 0xFF) b_ = 0xFF;
+}
+
 } // End of namespace Ultima8
 } // End of namespace Ultima
diff --git a/engines/ultima/ultima8/graphics/palette.h b/engines/ultima/ultima8/graphics/palette.h
index f77a0fd3a6..111140825a 100644
--- a/engines/ultima/ultima8/graphics/palette.h
+++ b/engines/ultima/ultima8/graphics/palette.h
@@ -58,6 +58,10 @@ struct Palette {
 	void load(Common::ReadStream &rs, Common::ReadStream &xformrs);
 	void load(Common::ReadStream &rs);
 
+	// Transform a single set of rgb values based on the current matrix.
+	// Not designed for speed - just useful for one-offs.
+	void transformRGB(int &r, int &g, int &b) const;
+
 	// 256 rgb entries
 	uint8 _palette[768];
 
diff --git a/engines/ultima/ultima8/gumps/cru_energy_gump.cpp b/engines/ultima/ultima8/gumps/cru_energy_gump.cpp
index ffb0bf861b..a5ee5388e0 100644
--- a/engines/ultima/ultima8/gumps/cru_energy_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_energy_gump.cpp
@@ -23,13 +23,16 @@
 #include "ultima/ultima8/gumps/cru_energy_gump.h"
 
 #include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/graphics/palette_manager.h"
 #include "ultima/ultima8/graphics/render_surface.h"
 #include "ultima/ultima8/world/get_object.h"
 
 namespace Ultima {
 namespace Ultima8 {
 
-static const uint32 ENERGY_BAR_COLOR = 0xFF9A0404; // RGB: (0, 48, 113)
+static const uint32 ENERGY_BAR_R = 154;
+static const uint32 ENERGY_BAR_G = 4;
+static const uint32 ENERGY_BAR_B = 4;
 
 DEFINE_RUNTIME_CLASSTYPE_CODE(CruEnergyGump)
 
@@ -61,7 +64,16 @@ void CruEnergyGump::PaintThis(RenderSurface *surf, int32 lerp_factor, bool scale
 	int16 energy = a->getMana();
 	int16 max_energy = a->getMaxMana();
 	int width = max_energy ? ((energy * 67) / max_energy) : 67;
-	surf->Fill32(ENERGY_BAR_COLOR, 34, 7, width, 14);
+	const Palette *gamepal = PaletteManager::get_instance()->getPalette(PaletteManager::Pal_Game);
+	if (!gamepal)
+		return;
+
+	int r = ENERGY_BAR_R;
+	int g = ENERGY_BAR_G;
+	int b = ENERGY_BAR_B;
+	gamepal->transformRGB(r, g, b);
+	uint32 fillcolor = (r << 16) | (g << 8) | b;
+	surf->Fill32(fillcolor, 34, 7, width, 14);
 }
 
 void CruEnergyGump::saveData(Common::WriteStream *ws) {
diff --git a/engines/ultima/ultima8/gumps/cru_health_gump.cpp b/engines/ultima/ultima8/gumps/cru_health_gump.cpp
index 4b948375cd..81007e6dcd 100644
--- a/engines/ultima/ultima8/gumps/cru_health_gump.cpp
+++ b/engines/ultima/ultima8/gumps/cru_health_gump.cpp
@@ -23,13 +23,16 @@
 #include "ultima/ultima8/gumps/cru_health_gump.h"
 
 #include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/graphics/palette_manager.h"
 #include "ultima/ultima8/graphics/render_surface.h"
 #include "ultima/ultima8/world/get_object.h"
 
 namespace Ultima {
 namespace Ultima8 {
 
-static const uint32 HEALTH_BAR_COLOR = 0xFF003071; // RGB = (154, 4, 4)
+static const uint32 HEALTH_BAR_R = 0;
+static const uint32 HEALTH_BAR_G = 48;
+static const uint32 HEALTH_BAR_B = 113;
 
 DEFINE_RUNTIME_CLASSTYPE_CODE(CruHealthGump)
 
@@ -62,7 +65,17 @@ void CruHealthGump::PaintThis(RenderSurface *surf, int32 lerp_factor, bool scale
 	int max_hp = a->getMaxHP();
 	// max width = 67
 	int width = max_hp ? ((current_hp * 67) / max_hp) : 67;
-	surf->Fill32(HEALTH_BAR_COLOR, 34, 7, width, 14);
+
+	const Palette *gamepal = PaletteManager::get_instance()->getPalette(PaletteManager::Pal_Game);
+	if (!gamepal)
+		return;
+
+	int r = HEALTH_BAR_R;
+	int g = HEALTH_BAR_G;
+	int b = HEALTH_BAR_B;
+	gamepal->transformRGB(r, g, b);
+	uint32 fillcolor = (r << 16) | (g << 8) | b;
+	surf->Fill32(fillcolor, 34, 7, width, 14);
 }
 
 void CruHealthGump::saveData(Common::WriteStream *ws) {




More information about the Scummvm-git-logs mailing list