[Scummvm-git-logs] scummvm master -> 3d8b8f01b777b8d987fc45c46b3bc3394c2aac25

mduggan mgithub at guarana.org
Tue Apr 6 12:38:31 UTC 2021


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

Summary:
2ebcd4d57b ULTIMA8: Sanity check last attack timestamp
c26552d208 ULTIMA8: Animate all shapes on the same frame
3d8b8f01b7 ULTIMA8: Implement crusader attack timeouts


Commit: 2ebcd4d57b18e3772201ab731026c993a0b16635
    https://github.com/scummvm/scummvm/commit/2ebcd4d57b18e3772201ab731026c993a0b16635
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-04-06T21:27:24+09:00

Commit Message:
ULTIMA8: Sanity check last attack timestamp

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


diff --git a/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
index 5603c4bd41..eaab2bb8bf 100644
--- a/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
@@ -742,6 +742,14 @@ void U8AvatarMoverProcess::jump(Animation::Sequence action, Direction direction)
 
 bool U8AvatarMoverProcess::canAttack() {
 	MainActor *avatar = getMainActor();
+	const uint32 frameno = Kernel::get_instance()->getFrameNum();
+
+	// Sanity check in case the frame num went backwards - eg, if
+	// frame counting changed after loading a game.
+	if (_lastAttack > frameno) {
+		_lastAttack = frameno;
+	}
+
 	return (Kernel::get_instance()->getFrameNum() > _lastAttack + (25 - avatar->getDex()));
 }
 


Commit: c26552d208b8149f64462cf9148d241325c3dd82
    https://github.com/scummvm/scummvm/commit/c26552d208b8149f64462cf9148d241325c3dd82
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-04-06T21:27:24+09:00

Commit Message:
ULTIMA8: Animate all shapes on the same frame

This is easily noticable on the falls west of town - all parts should animate
together, but they don't match.

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


diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index aeff4bf0f9..988792d0c9 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1680,7 +1680,7 @@ void Item::setupLerp(int32 gametick) {
 	// Animate it, if needed
 	const ShapeInfo *info = getShapeInfo();
 	if (info->_animType &&
-			((gametick % info->_animSpeed) == (_objId % info->_animSpeed)))
+			((gametick % info->_animSpeed) == 0))
 		animateItem();
 
 	// Setup the prev values for lerping
@@ -1713,7 +1713,7 @@ void Item::animateItem() {
 	int anim_data = info->_animData;
 	int speed = info->_animSpeed;
 
-	if ((static_cast<int>(_lastSetup) % speed * 2) != (_objId % speed * 2) && info->_animType != 1)
+	if ((static_cast<int>(_lastSetup) % speed * 2) != 0 && info->_animType != 1)
 		return;
 
 	const Shape *shp = getShapeObject();


Commit: 3d8b8f01b777b8d987fc45c46b3bc3394c2aac25
    https://github.com/scummvm/scummvm/commit/3d8b8f01b777b8d987fc45c46b3bc3394c2aac25
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2021-04-06T21:27:24+09:00

Commit Message:
ULTIMA8: Implement crusader attack timeouts

To match the original, add some movement timeouts and a flag that affect the
aim quality of NPCs attacking the player.

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


diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 82305140df..6692a7e148 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -70,7 +70,8 @@ Actor::Actor() : _strength(0), _dexterity(0), _intelligence(0),
 		_fallStart(0), _unkByte(0), _actorFlags(0), _combatTactic(0),
 		_homeX(0), _homeY(0), _homeZ(0), _currentActivityNo(0),
 		_lastActivityNo(0), _activeWeapon(0), _lastTimeWasHit(0),
-		_shieldType(0) {
+		_shieldType(0), _attackMoveStartTime(0), _attackMoveTimeout(0),
+		_attackMoveDodgeFactor(1), _attackAimFlag(false) {
 	_defaultActivity[0] = 0;
 	_defaultActivity[1] = 0;
 	_defaultActivity[2] = 0;
@@ -497,6 +498,47 @@ uint16 Actor::doAnim(Animation::Sequence anim, Direction dir, unsigned int steps
 		} else if (anim != Animation::kneel) {
 			clearActorFlag(ACT_KNEELING);
 		}
+
+		const uint32 frameno = Kernel::get_instance()->getFrameNum();
+		switch(anim) {
+			case Animation::walk:
+			case Animation::retreat: // SmallWeapon
+				_attackMoveStartTime = frameno;
+				_attackMoveTimeout = 120;
+				_attackMoveDodgeFactor = 3;
+				break;
+			case Animation::run:
+			case Animation::combatRollLeft:
+			case Animation::combatRollRight:
+			case Animation::stopRunningAndDrawLargeWeapon:
+			case Animation::stopRunningAndDrawSmallWeapon:
+			case Animation::jumpForward:
+			case Animation::jump:
+			case Animation::slowCombatRollLeft:
+			case Animation::slowCombatRollRight:
+			//case Animation::startRunSmallWeapon:
+			//case Animation::startRunLargeWeapon:
+			case Animation::startRun:
+				_attackMoveStartTime = frameno;
+				_attackMoveTimeout = 120;
+				_attackMoveDodgeFactor = 2;
+				break;
+			case Animation::slideLeft:
+			case Animation::slideRight:
+				_attackMoveStartTime = frameno;
+				_attackMoveTimeout = 60;
+				_attackMoveDodgeFactor = 3;
+				break;
+			case Animation::startKneeling:
+			case Animation::stopKneeling:
+				_attackMoveStartTime = frameno;
+				_attackMoveTimeout = 75;
+				_attackMoveDodgeFactor = 3;
+				break;
+			default:
+				break;
+		}
+
 	}
 
 #if 1
@@ -1662,6 +1704,10 @@ void Actor::saveData(Common::WriteStream *ws) {
 		ws->writeUint16LE(_activeWeapon);
 		ws->writeSint32LE(_lastTimeWasHit);
 		ws->writeByte(_shieldType);
+		ws->writeUint32LE(_attackMoveStartTime);
+		ws->writeUint32LE(_attackMoveTimeout);
+		ws->writeUint16LE(_attackMoveDodgeFactor);
+		ws->writeByte(_attackAimFlag ? 1 : 0);
 	}
 }
 
@@ -1695,6 +1741,10 @@ bool Actor::loadData(Common::ReadStream *rs, uint32 version) {
 		_activeWeapon = rs->readUint16LE();
 		_lastTimeWasHit = rs->readSint32LE();
 		_shieldType = rs->readByte();
+		_attackMoveStartTime = rs->readUint32LE();
+		_attackMoveTimeout = rs->readUint32LE();
+		_attackMoveDodgeFactor = rs->readUint16LE();
+		_attackAimFlag = rs->readByte() != 0;
 	}
 
 	return true;
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 7eacb9a760..2d7de96497 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -300,6 +300,22 @@ public:
 	//! Add the x/y/z fire offsets given the current state of the actor
 	void addFireAnimOffsets(int32 &x, int32 &y, int32 &z);
 
+	uint32 getAttackMoveTimeoutFinish() const {
+		return _attackMoveStartTime + _attackMoveTimeout;
+	}
+
+	uint16 getAttackMoveDodgeFactor() const {
+		return _attackMoveDodgeFactor;
+	}
+
+	bool getAttackAimFlag() const {
+		return _attackAimFlag;
+	}
+
+	void setAttackAimFlag(bool val) {
+		_attackAimFlag = val;
+	}
+
 	ENABLE_RUNTIME_CLASSTYPE()
 
 	INTRINSIC(I_isNPC);
@@ -436,6 +452,18 @@ protected:
 	//! Type of shield (only used in Crusader)
 	uint8 _shieldType;
 
+	//! The frame certain animations last happened (for Crusader).
+	//! Used in calcualting how hard controlled actor is to hit.
+	uint32 _attackMoveStartTime;
+	//! The number of frames the above effect lasts for.
+	uint32 _attackMoveTimeout;
+	//! A spread divisor used by shots targeting the controlled actor when they
+	//! are within the above timeout.
+	uint16 _attackMoveDodgeFactor;
+
+	//! A flag used in Crusader attack process which adjusts the aim accuracy.
+	bool _attackAimFlag;
+
 	//! starts an activity (Ultima 8 version)
 	//! \return processID of process handling the activity or zero
 	uint16 setActivityU8(int activity);
diff --git a/engines/ultima/ultima8/world/actors/attack_process.cpp b/engines/ultima/ultima8/world/actors/attack_process.cpp
index 29862e9009..e656b17a57 100644
--- a/engines/ultima/ultima8/world/actors/attack_process.cpp
+++ b/engines/ultima/ultima8/world/actors/attack_process.cpp
@@ -61,11 +61,6 @@ const uint16 AttackProcess::ATTACK_PROCESS_TYPE = 0x259;
 
 static uint16 someSleepGlobal = 0;
 
-// TODO: Implement me. Set timer for some avatar moves.
-static bool World_FinishedAvatarMoveTimeout() {
-	return true;
-}
-
 static inline int32 randomOf(int32 max) {
 	return (max > 0 ? getRandom() % max : 0);
 }
@@ -98,6 +93,8 @@ _soundTimestamp(0), _fireTimestamp(0) {
 		_dataArray[i] = 0;
 	}
 
+	actor->setAttackAimFlag(false);
+
 	const Item *wpn = getItem(actor->getActiveWeapon());
 	if (wpn) {
 		const uint32 wpnshape = wpn->getShape();
@@ -606,7 +603,7 @@ void AttackProcess::genericAttack() {
 					if (_wpnField8 < 3) {
 						_wpnField8 = 1;
 					} else if ((_doubleDelay && (getRandom() % 2 == 0)) || (getRandom() % 5 == 0)) {
-						// TODO: a->setField0x68(1);
+						a->setAttackAimFlag(true);
 						_wpnField8 *= 4;
 					}
 					_fireTimestamp = now;
@@ -648,8 +645,11 @@ void AttackProcess::genericAttack() {
 		}
 		if (targetdir == curdir) {
 			const uint16 rnd = randomOf(10);
+			const uint32 frameno = Kernel::get_instance()->getFrameNum();
+			const uint32 timeoutfinish = target->getAttackMoveTimeoutFinish();
+
 			if (!onscreen ||
-				(!_field96 && !timer4and5Update(now) && !World_FinishedAvatarMoveTimeout()
+				(!_field96 && !timer4and5Update(now) && frameno < timeoutfinish
 				 && rnd > 2 && (!_isActivityAorB || rnd > 3))) {
 				sleep(0x14);
 				return;
@@ -700,7 +700,7 @@ void AttackProcess::genericAttack() {
 				if (wpn) {
 					_wpnField8 = wpnField8;
 					if (_wpnField8 > 2 && ((_doubleDelay && randomOf(2) == 0) || randomOf(5) == 0)) {
-						// TODO: a->setField0x68(1);
+						a->setAttackAimFlag(true);
 						_wpnField8 *= 4;
 					}
 				}
diff --git a/engines/ultima/ultima8/world/super_sprite_process.cpp b/engines/ultima/ultima8/world/super_sprite_process.cpp
index 105c69f669..9db9ac6b15 100644
--- a/engines/ultima/ultima8/world/super_sprite_process.cpp
+++ b/engines/ultima/ultima8/world/super_sprite_process.cpp
@@ -77,13 +77,27 @@ SuperSpriteProcess::SuperSpriteProcess(int shape, int frame, int sx, int sy, int
 			else
 				rng /= 10;
 		} else {
-			if (dynamic_cast<Actor *>(srcitem) != nullptr) {
-				rng /= 2;
+			Actor *srcnpc = dynamic_cast<Actor *>(srcitem);
+			Actor *controlled = getControlledActor();
+			const uint32 frameno = Kernel::get_instance()->getFrameNum();
+			const uint32 timeoutfinish = controlled ? controlled->getAttackMoveTimeoutFinish() : 0;
+			if (!srcnpc || !srcnpc->getAttackAimFlag()) {
+				if (!srcnpc || frameno < timeoutfinish) {
+					if (!srcnpc && (controlled && controlled->isKneeling())) {
+						rng = rng / 5;
+					} else {
+						const uint16 dodgefactor = controlled ? controlled->getAttackMoveDodgeFactor() : 2;
+						if (!srcnpc) {
+							rng = rng / (dodgefactor * 3);
+						} else {
+							rng = rng / dodgefactor;
+						}
+					}
+				} else {
+					rng = rng / 8;
+				}
 			} else {
-				// TODO: various other flags are checked in the game (around 1138:0bd1)
-				// such as World_FinishedAvatarMoveTimeout() -> 8
-				//  to make it either 5 or 8.  For now just use 5.
-				rng /= 5;
+				rng = rng / 2;
 			}
 		}
 




More information about the Scummvm-git-logs mailing list