[Scummvm-git-logs] scummvm master -> 52328fc334a0f1adedee7c453a516fe013cc3e6c

mduggan mgithub at guarana.org
Tue Jul 28 05:03:48 UTC 2020


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:
387b525a8e ULTIMA8: Begin refactor to use Direction enum instead of int
38e4ff0c60 ULTIMA8: Refactor to use Direction as enum instead of int
52328fc334 ULTIMA8: More encapsulation of directions, less casts


Commit: 387b525a8e12198f41b7b4ec2c3cd892e35cb009
    https://github.com/scummvm/scummvm/commit/387b525a8e12198f41b7b4ec2c3cd892e35cb009
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-28T14:03:37+09:00

Commit Message:
ULTIMA8: Begin refactor to use Direction enum instead of int

Changed paths:
    engines/ultima/ultima8/misc/direction.h
    engines/ultima/ultima8/world/actors/actor.cpp
    engines/ultima/ultima8/world/actors/actor_anim_process.cpp
    engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
    engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp
    engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
    engines/ultima/ultima8/world/actors/combat_process.cpp
    engines/ultima/ultima8/world/actors/grant_peace_process.cpp
    engines/ultima/ultima8/world/actors/loiter_process.cpp
    engines/ultima/ultima8/world/gravity_process.cpp


diff --git a/engines/ultima/ultima8/misc/direction.h b/engines/ultima/ultima8/misc/direction.h
index 39fa0af7ac..9f71146c92 100644
--- a/engines/ultima/ultima8/misc/direction.h
+++ b/engines/ultima/ultima8/misc/direction.h
@@ -30,14 +30,15 @@ namespace Ultima8 {
  *  Directions:
  */
 enum Direction {
-	north = 0,
-	northeast = 1,
-	east = 2,
-	southeast = 3,
-	south = 4,
-	southwest = 5,
-	west = 6,
-	northwest = 7
+	dir_north = 0,
+	dir_northeast = 1,
+	dir_east = 2,
+	dir_southeast = 3,
+	dir_south = 4,
+	dir_southwest = 5,
+	dir_west = 6,
+	dir_northwest = 7,
+	dir_current = 16
 };
 
 /*
@@ -60,40 +61,40 @@ static const int y_fact16[] = { -2, -2, -2, -1,  0, +1, +2, +2, +2, +2, +2, +1,
 
 inline Direction Get_direction(int deltay, int deltax) {
 	if (deltax == 0)
-		return deltay > 0 ? northwest : southeast;
+		return deltay > 0 ? dir_northwest : dir_southeast;
 	int dydx = (1024 * deltay) / deltax; // Figure 1024*tan.
 	if (dydx >= 0)
 		if (deltax > 0) // Top-right
-			return dydx <= 424 ? northeast : dydx <= 2472 ? north
-			       : northwest;
+			return dydx <= 424 ? dir_northeast : dydx <= 2472 ? dir_north
+			       : dir_northwest;
 		else            // Bottom-left.
-			return dydx <= 424 ? southwest : dydx <= 2472 ? south
-			       : southeast;
+			return dydx <= 424 ? dir_southwest : dydx <= 2472 ? dir_south
+			       : dir_southeast;
 	else if (deltax > 0) // Bottom-right.
-		return dydx >= -424 ? northeast : dydx >= -2472 ? east
-		       : southeast;
+		return dydx >= -424 ? dir_northeast : dydx >= -2472 ? dir_east
+		       : dir_southeast;
 	else            // Top-left
-		return dydx >= -424 ? southwest : dydx >= -2472 ? west
-		       : northwest;
+		return dydx >= -424 ? dir_southwest : dydx >= -2472 ? dir_west
+		       : dir_northwest;
 }
 
 
 inline Direction Get_WorldDirection(int deltay, int deltax) {
 	if (deltax == 0) {
-		if (deltay == 0) return northeast; // for better compatibility with U8
-		return deltay > 0 ? south : north;
+		if (deltay == 0) return dir_northeast; // for better compatibility with U8
+		return deltay > 0 ? dir_south : dir_north;
 	}
 	int dydx = (1024 * deltay) / deltax;
 
 	if (dydx >= 0)
 		if (deltax > 0) // south-east
-			return dydx <= 424 ? east : dydx <= 2472 ? southeast : south;
+			return dydx <= 424 ? dir_east : dydx <= 2472 ? dir_southeast : dir_south;
 		else            // north-west
-			return dydx <= 424 ? west : dydx <= 2472 ? northwest : north;
+			return dydx <= 424 ? dir_west : dydx <= 2472 ? dir_northwest : dir_north;
 	else if (deltax > 0) // north-east
-		return dydx >= -424 ? east : dydx >= -2472 ? northeast : north;
+		return dydx >= -424 ? dir_east : dydx >= -2472 ? dir_northeast : dir_north;
 	else            // south-west
-		return dydx >= -424 ? west : dydx >= -2472 ? southwest : south;
+		return dydx >= -424 ? dir_west : dydx >= -2472 ? dir_southwest : dir_south;
 }
 
 inline Direction Get_WorldDirectionClosestInRange(int deltay, int deltax, uint16 ndirs, uint16 mindir, uint16 maxdir) {
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index b3a6392c27..46a04e2f4a 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -463,7 +463,7 @@ void Actor::teleport(int newmap, int32 newx, int32 newy, int32 newz) {
 }
 
 uint16 Actor::doAnim(Animation::Sequence anim, int dir, unsigned int steps) {
-	if (dir < 0 || dir > 8) {
+	if (dir < 0 || dir > 16) {
 		perr << "Actor::doAnim: Invalid _direction (" << dir << ")" << Std::endl;
 		return 0;
 	}
@@ -489,9 +489,10 @@ bool Actor::hasAnim(Animation::Sequence anim) {
 
 Animation::Result Actor::tryAnim(Animation::Sequence anim, int dir,
                                  unsigned int steps, PathfindingState *state) {
-	if (dir < 0 || dir > 8) return Animation::FAILURE;
+	if (dir < 0 || dir > 16) return Animation::FAILURE;
 
-	if (dir == 8) dir = getDir();
+	if (dir == dir_current)
+		dir = getDir();
 
 	AnimationTracker tracker;
 	if (!tracker.init(this, anim, dir, state))
@@ -597,7 +598,7 @@ uint16 Actor::setActivityU8(int activity) {
 		return 0;
 	case 2: // stand
 		// NOTE: temporary fall-throughs!
-		return doAnim(Animation::stand, 8);
+		return doAnim(Animation::stand, dir_current);
 
 	default:
 		perr << "Actor::setActivityU8: invalid activity (" << activity << ")"
@@ -616,7 +617,7 @@ uint16 Actor::setActivityCru(int activity) {
 
 	switch (activity) {
 	case 1: // stand
-		return doAnim(Animation::stand, 8);
+		return doAnim(Animation::stand, dir_current);
 	case 3: // pace
 		perr << "Actor::setActivityCru TODO: Implement new PaceProcess(this);" << Std::endl;
 		return Kernel::get_instance()->addProcess(new LoiterProcess(this));
@@ -651,7 +652,7 @@ uint16 Actor::setActivityCru(int activity) {
 	default:
 		perr << "Actor::setActivityCru: invalid activity (" << activity << ")"
 		     << Std::endl;
-		return doAnim(Animation::stand, 8);
+		return doAnim(Animation::stand, dir_current);
 	}
 
 	return 0;
@@ -751,8 +752,8 @@ void Actor::receiveHitCru(uint16 other, int dir, int damage, uint16 damage_type)
 		// TODO: Finish special case for Vargas.  Should not do any damage
 		// if there is a particular anim process running.  Also, check if the
 		// same special case exists in REGRET.
-		doAnim(static_cast<Animation::Sequence>(0x21), getDir());
-		doAnim(static_cast<Animation::Sequence>(0x20), getDir());
+		doAnim(static_cast<Animation::Sequence>(0x21), dir_current);
+		doAnim(static_cast<Animation::Sequence>(0x20), dir_current);
 		_hitPoints -= damage;
 		return;
 	}
@@ -824,7 +825,7 @@ void Actor::receiveHitCru(uint16 other, int dir, int damage, uint16 damage_type)
 		if (damage_type == 0xf || damage_type == 7) {
 			if (shape == 1) {
 				kernel->killProcesses(_objId, 0x204, true);
-				doAnim(static_cast<Animation::Sequence>(0x37), getDir());
+				doAnim(static_cast<Animation::Sequence>(0x37), dir_current);
 			} else if (shape == 0x4e6 || shape == 0x338 || shape == 0x385 || shape == 899) {
 				if (!(getRandom() % 3)) {
 					// Randomly stun the NPC for these damage types.
@@ -915,7 +916,7 @@ void Actor::receiveHitU8(uint16 other, int dir, int damage, uint16 damage_type)
 	if (_objId == 1 && damage > 0) {
 		if ((damage_type & WeaponInfo::DMG_FALLING) && damage >= 6) {
 			// high falling damage knocks you down
-			doAnim(Animation::fallBackwards, 8);
+			doAnim(Animation::fallBackwards, dir_current);
 
 			// TODO: shake head after getting back up when not in combat
 			return;
@@ -927,8 +928,8 @@ void Actor::receiveHitU8(uint16 other, int dir, int damage, uint16 damage_type)
 
 	// if avatar was blocking; do a quick stopBlock/startBlock and play SFX
 	if (_objId == 1 && getLastAnim() == Animation::startBlock) {
-		ProcId anim1pid = doAnim(Animation::stopBlock, 8);
-		ProcId anim2pid = doAnim(Animation::startBlock, 8);
+		ProcId anim1pid = doAnim(Animation::stopBlock, dir_current);
+		ProcId anim2pid = doAnim(Animation::startBlock, dir_current);
 
 		Process *anim1proc = Kernel::get_instance()->getProcess(anim1pid);
 		Process *anim2proc = Kernel::get_instance()->getProcess(anim2pid);
@@ -995,7 +996,7 @@ ProcId Actor::die(uint16 damageType) {
 #endif
 
 	if (!animprocid)
-		animprocid = doAnim(Animation::die, getDir());
+		animprocid = doAnim(Animation::die, dir_current);
 
 
 	MainActor *avatar = getMainActor();
@@ -1029,7 +1030,7 @@ ProcId Actor::die(uint16 damageType) {
 		Process *delayproc = new DelayProcess(timeout);
 		Kernel::get_instance()->addProcess(delayproc);
 
-		ProcId animpid = doAnim(Animation::standUp, 8);
+		ProcId animpid = doAnim(Animation::standUp, dir_current);
 		Process *animproc = Kernel::get_instance()->getProcess(animpid);
 		assert(animproc);
 
@@ -1798,11 +1799,11 @@ uint32 Actor::I_setFeignDeath(const uint8 *args, unsigned int /*argsize*/) {
 
 	actor->setActorFlag(ACT_FEIGNDEATH);
 
-	ProcId animfallpid = actor->doAnim(Animation::die, 8);
+	ProcId animfallpid = actor->doAnim(Animation::die, dir_current);
 	Process *animfallproc = Kernel::get_instance()->getProcess(animfallpid);
 	assert(animfallproc);
 
-	ProcId animstandpid = actor->doAnim(Animation::standUp, 8);
+	ProcId animstandpid = actor->doAnim(Animation::standUp, dir_current);
 	Process *animstandproc = Kernel::get_instance()->getProcess(animstandpid);
 	assert(animstandproc);
 
diff --git a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
index c1cbb5d6c8..d4860eaecf 100644
--- a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
@@ -85,10 +85,10 @@ bool ActorAnimProcess::init() {
 	Actor *actor = getActor(_itemNum);
 	assert(actor);
 
-	if (_dir == 8)
+	if (_dir == dir_current)
 		_dir = actor->getDir();
 
-	if (_dir > 7) {
+	if ((GAME_IS_U8 && _dir > 7) || (GAME_IS_CRUSADER && _dir > 15)) {
 		// invalid direction
 		return false;
 	}
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 ae7d9287fd..571cc1dc95 100644
--- a/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_bark_notify_process.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "ultima/ultima8/misc/pent_include.h"
+#include "ultima/ultima8/misc/direction.h"
 #include "ultima/ultima8/world/actors/actor_bark_notify_process.h"
 #include "ultima/ultima8/gumps/gump.h"
 #include "ultima/ultima8/kernel/delay_process.h"
@@ -70,7 +71,7 @@ void ActorBarkNotifyProcess::run() {
 	ProcId delaypid = Kernel::get_instance()->addProcess(delayproc);
 
 	if (doAnim)
-		a->doAnim(Animation::talk, 8);
+		a->doAnim(Animation::talk, dir_current);
 
 	waitFor(delaypid);
 }
diff --git a/engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp b/engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp
index 0ea9fa44ea..9f90a70287 100644
--- a/engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp
+++ b/engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp
@@ -21,7 +21,7 @@
  */
 
 #include "ultima/ultima8/misc/pent_include.h"
-
+#include "ultima/ultima8/misc/direction.h"
 #include "ultima/ultima8/world/actors/avatar_gravity_process.h"
 #include "ultima/ultima8/world/actors/main_actor.h"
 #include "ultima/ultima8/world/world.h"
@@ -62,7 +62,7 @@ void AvatarGravityProcess::run() {
 		// CHECKME: do we need to perform any other checks?
 
 		if (avatar->getLastAnim() != Animation::hang)
-			avatar->doAnim(Animation::hang, 8);
+			avatar->doAnim(Animation::hang, dir_current);
 
 		return;
 	} else {
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
index 3c6a28c36e..45c4388b95 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
@@ -119,9 +119,9 @@ void AvatarMoverProcess::handleHangingMode() {
 		_mouseButton[0]._lastDown = 0;
 		MainActor *avatar = getMainActor();
 
-		if (avatar->tryAnim(Animation::climb40, 8) == Animation::SUCCESS) {
+		if (avatar->tryAnim(Animation::climb40, dir_current) == Animation::SUCCESS) {
 			avatar->ensureGravityProcess()->terminate();
-			waitFor(avatar->doAnim(Animation::climb40, 8));
+			waitFor(avatar->doAnim(Animation::climb40, dir_current));
 		}
 	}
 }
diff --git a/engines/ultima/ultima8/world/actors/combat_process.cpp b/engines/ultima/ultima8/world/actors/combat_process.cpp
index 32001a53fb..f3474990d3 100644
--- a/engines/ultima/ultima8/world/actors/combat_process.cpp
+++ b/engines/ultima/ultima8/world/actors/combat_process.cpp
@@ -34,6 +34,7 @@
 #include "ultima/ultima8/world/actors/pathfinder_process.h"
 #include "ultima/ultima8/graphics/shape_info.h"
 #include "ultima/ultima8/world/actors/monster_info.h"
+#include "ultima/ultima8/misc/direction.h"
 #include "ultima/ultima8/world/get_object.h"
 #include "ultima/ultima8/world/actors/loiter_process.h"
 #include "ultima/ultima8/world/actors/ambush_process.h"
@@ -120,12 +121,12 @@ void CombatProcess::run() {
 				else
 					idleanim = Animation::idle2;
 			}
-			uint16 idlepid = a->doAnim(idleanim, 8);
+			uint16 idlepid = a->doAnim(idleanim, dir_current);
 			waitFor(idlepid);
 		} else {
 
 			// attack
-			ProcId attackanim = a->doAnim(Animation::attack, 8);
+			ProcId attackanim = a->doAnim(Animation::attack, dir_current);
 
 			// wait a while, depending on dexterity, before attacking again
 			int dex = a->getDex();
@@ -312,10 +313,10 @@ void CombatProcess::waitForTarget() {
 
 		// shift into a tree if nobody is around
 
-		ProcId shift1pid = a->doAnim(static_cast<Animation::Sequence>(20), 8);
+		ProcId shift1pid = a->doAnim(static_cast<Animation::Sequence>(20), dir_current);
 		Process *ambushproc = new AmbushProcess(a);
 		ProcId ambushpid = Kernel::get_instance()->addProcess(ambushproc);
-		ProcId shift2pid = a->doAnim(static_cast<Animation::Sequence>(21), 8);
+		ProcId shift2pid = a->doAnim(static_cast<Animation::Sequence>(21), dir_current);
 		Process *shift2proc = Kernel::get_instance()->getProcess(shift2pid);
 
 		ambushproc->waitFor(shift1pid);
diff --git a/engines/ultima/ultima8/world/actors/grant_peace_process.cpp b/engines/ultima/ultima8/world/actors/grant_peace_process.cpp
index 0ac1393060..70f5d22595 100644
--- a/engines/ultima/ultima8/world/actors/grant_peace_process.cpp
+++ b/engines/ultima/ultima8/world/actors/grant_peace_process.cpp
@@ -199,14 +199,14 @@ uint32 GrantPeaceProcess::I_castGrantPeace(const uint8 *args,
 	Kernel::get_instance()->addProcess(gpp);
 
 	// start casting
-	ProcId anim1 = avatar->doAnim(Animation::cast1, 8);
+	ProcId anim1 = avatar->doAnim(Animation::cast1, dir_current);
 
 	// cast
-	ProcId anim2 = avatar->doAnim(Animation::cast3, 8);
+	ProcId anim2 = avatar->doAnim(Animation::cast3, dir_current);
 	Process *anim2p = Kernel::get_instance()->getProcess(anim2);
 
 	// end casting
-	ProcId anim3 = avatar->doAnim(Animation::cast2, 8);
+	ProcId anim3 = avatar->doAnim(Animation::cast2, dir_current);
 	Process *anim3p = Kernel::get_instance()->getProcess(anim3);
 
 	anim2p->waitFor(anim1);
diff --git a/engines/ultima/ultima8/world/actors/loiter_process.cpp b/engines/ultima/ultima8/world/actors/loiter_process.cpp
index e2731f3f59..72b75e7343 100644
--- a/engines/ultima/ultima8/world/actors/loiter_process.cpp
+++ b/engines/ultima/ultima8/world/actors/loiter_process.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "ultima/ultima8/misc/pent_include.h"
+#include "ultima/ultima8/misc/direction.h"
 #include "ultima/ultima8/world/actors/loiter_process.h"
 #include "ultima/ultima8/world/actors/actor.h"
 #include "ultima/ultima8/world/actors/pathfinder_process.h"
@@ -89,7 +90,7 @@ void LoiterProcess::run() {
 			else
 				idleanim = Animation::idle2;
 		}
-		uint16 idlepid = a->doAnim(idleanim, 8);
+		uint16 idlepid = a->doAnim(idleanim, dir_current);
 		Process *idlep = Kernel::get_instance()->getProcess(idlepid);
 		idlep->waitFor(pfp);
 
diff --git a/engines/ultima/ultima8/world/gravity_process.cpp b/engines/ultima/ultima8/world/gravity_process.cpp
index 9a76cbc3c0..8caeb3c423 100644
--- a/engines/ultima/ultima8/world/gravity_process.cpp
+++ b/engines/ultima/ultima8/world/gravity_process.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "ultima/ultima8/misc/pent_include.h"
+#include "ultima/ultima8/misc/direction.h"
 #include "ultima/ultima8/world/gravity_process.h"
 #include "ultima/ultima8/world/actors/actor.h"
 #include "ultima/ultima8/audio/audio_process.h"
@@ -325,12 +326,12 @@ void GravityProcess::fallStopped() {
 
 			// play land animation, overriding other animations
 			Kernel::get_instance()->killProcesses(_itemNum, 0xF0, false); // CONSTANT!
-			ProcId lpid = actor->doAnim(Animation::land, 8);
+			ProcId lpid = actor->doAnim(Animation::land, dir_current);
 
 			if (actor->isInCombat()) {
 				// need to get back to a combat stance to prevent weapon from
 				// being drawn again
-				ProcId spid = actor->doAnim(Animation::combatStand, 8);
+				ProcId spid = actor->doAnim(Animation::combatStand, dir_current);
 				Process *sp = Kernel::get_instance()->getProcess(spid);
 				sp->waitFor(lpid);
 			}


Commit: 38e4ff0c6095d88a4d3cc07808c2f75ece75ffca
    https://github.com/scummvm/scummvm/commit/38e4ff0c6095d88a4d3cc07808c2f75ece75ffca
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-28T14:03:37+09:00

Commit Message:
ULTIMA8: Refactor to use Direction as enum instead of int

Changed paths:
  A engines/ultima/ultima8/misc/direction_util.h
    engines/ultima/ultima8/games/start_crusader_process.cpp
    engines/ultima/ultima8/kernel/mouse.cpp
    engines/ultima/ultima8/kernel/mouse.h
    engines/ultima/ultima8/misc/direction.h
    engines/ultima/ultima8/world/actors/actor.cpp
    engines/ultima/ultima8/world/actors/actor.h
    engines/ultima/ultima8/world/actors/actor_anim_process.cpp
    engines/ultima/ultima8/world/actors/actor_anim_process.h
    engines/ultima/ultima8/world/actors/animation_tracker.cpp
    engines/ultima/ultima8/world/actors/animation_tracker.h
    engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp
    engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
    engines/ultima/ultima8/world/actors/avatar_mover_process.h
    engines/ultima/ultima8/world/actors/combat_process.cpp
    engines/ultima/ultima8/world/actors/combat_process.h
    engines/ultima/ultima8/world/actors/grant_peace_process.cpp
    engines/ultima/ultima8/world/actors/pathfinder.cpp
    engines/ultima/ultima8/world/actors/pathfinder.h
    engines/ultima/ultima8/world/actors/pathfinder_process.cpp
    engines/ultima/ultima8/world/actors/surrender_process.cpp
    engines/ultima/ultima8/world/actors/targeted_anim_process.cpp
    engines/ultima/ultima8/world/actors/targeted_anim_process.h
    engines/ultima/ultima8/world/current_map.cpp
    engines/ultima/ultima8/world/current_map.h
    engines/ultima/ultima8/world/fire_type.cpp
    engines/ultima/ultima8/world/fireball_process.cpp
    engines/ultima/ultima8/world/item.cpp
    engines/ultima/ultima8/world/item.h
    engines/ultima/ultima8/world/super_sprite_process.cpp
    engines/ultima/ultima8/world/target_reticle_process.cpp
    engines/ultima/ultima8/world/target_reticle_process.h
    engines/ultima/ultima8/world/world.cpp


diff --git a/engines/ultima/ultima8/games/start_crusader_process.cpp b/engines/ultima/ultima8/games/start_crusader_process.cpp
index 755ce37e9b..e85a318008 100644
--- a/engines/ultima/ultima8/games/start_crusader_process.cpp
+++ b/engines/ultima/ultima8/games/start_crusader_process.cpp
@@ -108,7 +108,7 @@ void StartCrusaderProcess::run() {
 		miss1egg->assignObjId();
 		miss1egg->callUsecodeEvent_hatch();
 
-		avatar->setDir(2);
+		avatar->setDir(dir_east);
 
 		// TODO: The game actually teleports to egg 0x1f (31) which has another
 		// egg to teleport to egg 99.  Is there any purpose to that?
diff --git a/engines/ultima/ultima8/kernel/mouse.cpp b/engines/ultima/ultima8/kernel/mouse.cpp
index d2a1933305..c349f0e12b 100644
--- a/engines/ultima/ultima8/kernel/mouse.cpp
+++ b/engines/ultima/ultima8/kernel/mouse.cpp
@@ -30,6 +30,7 @@
 #include "ultima/ultima8/gumps/gump.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/misc/rect.h"
 #include "ultima/ultima8/world/get_object.h"
 #include "ultima/ultima8/world/actors/main_actor.h"
@@ -170,7 +171,7 @@ int Mouse::getMouseLength(int mx, int my) {
 	}
 }
 
-int Mouse::getMouseDirectionWorld(int mx, int my) {
+Direction Mouse::getMouseDirectionWorld(int mx, int my) {
 	Rect dims;
 	RenderSurface *screen = Ultima8Engine::get_instance()->getRenderScreen();
 	screen->GetSurfaceDims(dims);
@@ -179,7 +180,7 @@ int Mouse::getMouseDirectionWorld(int mx, int my) {
 	int dx = mx - dims.w / 2;
 	int dy = (dims.h / 2 + (dims.h * 14 / 200)) - my; //! constant
 
-	return Get_direction(dy * 2, dx);
+	return Direction_Get(dy * 2, dx);
 }
 
 int Mouse::getMouseDirectionScreen(int mx, int my) {
diff --git a/engines/ultima/ultima8/kernel/mouse.h b/engines/ultima/ultima8/kernel/mouse.h
index c92fa158a8..953f1c7ee0 100644
--- a/engines/ultima/ultima8/kernel/mouse.h
+++ b/engines/ultima/ultima8/kernel/mouse.h
@@ -28,6 +28,7 @@
 #include "common/stack.h"
 #include "ultima/shared/engine/events.h"
 #include "ultima/ultima8/graphics/texture.h"
+#include "ultima/ultima8/misc/direction.h"
 
 namespace Ultima {
 namespace Ultima8 {
@@ -153,7 +154,7 @@ public:
 	int getMouseDirectionScreen(int mx, int my);
 
 	//! get mouse cursor direction in the world. 0 = up, 1 = up-right, 2 = right, etc...
-	int getMouseDirectionWorld(int mx, int my);
+	Direction getMouseDirectionWorld(int mx, int my);
 
 	//! get current mouse cursor location
 	void getMouseCoords(int32 &mx, int32 &my) const {
diff --git a/engines/ultima/ultima8/misc/direction.h b/engines/ultima/ultima8/misc/direction.h
index 9f71146c92..3812e15310 100644
--- a/engines/ultima/ultima8/misc/direction.h
+++ b/engines/ultima/ultima8/misc/direction.h
@@ -41,100 +41,6 @@ enum Direction {
 	dir_current = 16
 };
 
-/*
- * Tables to map a Direction to x/y deltas
- */
-static const int x_fact[] = {  0, +1, +1, +1,  0, -1, -1, -1 };
-static const int y_fact[] = { -1, -1,  0, +1, +1, +1,  0, -1 };
-
-static const int x_fact16[] = {  0, +1, +2, +2, +2, +2, +2, +1, 0, -1, -2, -2, -2, -2, -2, -1 };
-static const int y_fact16[] = { -2, -2, -2, -1,  0, +1, +2, +2, +2, +2, +2, +1, 0, -1, -2, -2 };
-
-/*
- *  Return the direction for a given slope (0-7).
- *  NOTE:  Assumes cartesian coords, NOT screen coords. (which have y
- *      growing downwards).
- *
- *  NOTE: The returned direction is rotated 45 degrees clockwise! This is
- *  how U8 things should be.
- */
-
-inline Direction Get_direction(int deltay, int deltax) {
-	if (deltax == 0)
-		return deltay > 0 ? dir_northwest : dir_southeast;
-	int dydx = (1024 * deltay) / deltax; // Figure 1024*tan.
-	if (dydx >= 0)
-		if (deltax > 0) // Top-right
-			return dydx <= 424 ? dir_northeast : dydx <= 2472 ? dir_north
-			       : dir_northwest;
-		else            // Bottom-left.
-			return dydx <= 424 ? dir_southwest : dydx <= 2472 ? dir_south
-			       : dir_southeast;
-	else if (deltax > 0) // Bottom-right.
-		return dydx >= -424 ? dir_northeast : dydx >= -2472 ? dir_east
-		       : dir_southeast;
-	else            // Top-left
-		return dydx >= -424 ? dir_southwest : dydx >= -2472 ? dir_west
-		       : dir_northwest;
-}
-
-
-inline Direction Get_WorldDirection(int deltay, int deltax) {
-	if (deltax == 0) {
-		if (deltay == 0) return dir_northeast; // for better compatibility with U8
-		return deltay > 0 ? dir_south : dir_north;
-	}
-	int dydx = (1024 * deltay) / deltax;
-
-	if (dydx >= 0)
-		if (deltax > 0) // south-east
-			return dydx <= 424 ? dir_east : dydx <= 2472 ? dir_southeast : dir_south;
-		else            // north-west
-			return dydx <= 424 ? dir_west : dydx <= 2472 ? dir_northwest : dir_north;
-	else if (deltax > 0) // north-east
-		return dydx >= -424 ? dir_east : dydx >= -2472 ? dir_northeast : dir_north;
-	else            // south-west
-		return dydx >= -424 ? dir_west : dydx >= -2472 ? dir_southwest : dir_south;
-}
-
-inline Direction Get_WorldDirectionClosestInRange(int deltay, int deltax, uint16 ndirs, uint16 mindir, uint16 maxdir) {
-	// TODO: Implement proper 16 directions here.
-	uint32 dir = static_cast<uint32>(Get_WorldDirection(deltay, deltax));
-	if (ndirs == 16) {
-		dir *= 2;
-	}
-
-	if ((dir < mindir) || (dir > maxdir)) {
-		int32 dmin1 = dir - mindir;
-		int32 dmin2 = mindir - dir;
-		if (dmin1 < 0) {
-			dmin1 = dmin1 + ndirs;
-		}
-		if (dmin2 < 0) {
-			dmin2 = dmin2 + ndirs;
-		}
-		int32 dist_to_min = MIN(dmin1, dmin2);
-
-		int dmax1 = dir - maxdir;
-		int dmax2 = maxdir - dir;
-		if (dmax1 < 0) {
-			dmax1 = dmax1 + ndirs;
-		}
-		if (dmax2 < 0) {
-			dmax2 = dmax2 + ndirs;
-		}
-		int32 dist_to_max = MIN(dmax1, dmax2);
-
-		if (dist_to_min < dist_to_max) {
-			return static_cast<Direction>(mindir);
-		} else {
-			return static_cast<Direction>(maxdir);
-		}
-	}
-
-	return static_cast<Direction>(dir);
-}
-
 } // End of namespace Ultima8
 } // End of namespace Ultima
 
diff --git a/engines/ultima/ultima8/misc/direction_util.h b/engines/ultima/ultima8/misc/direction_util.h
new file mode 100644
index 0000000000..994c7683d3
--- /dev/null
+++ b/engines/ultima/ultima8/misc/direction_util.h
@@ -0,0 +1,158 @@
+/* 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 ULTIMA8_MISC_DIRECTIONUTIL_H
+#define ULTIMA8_MISC_DIRECTIONUTIL_H
+
+#include "ultima/ultima8/misc/direction.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+/*
+ * Tables to map a Direction to x/y deltas
+ */
+static const int x_fact[] = {  0, +1, +1, +1,  0, -1, -1, -1 };
+static const int y_fact[] = { -1, -1,  0, +1, +1, +1,  0, -1 };
+
+static const int x_fact16[] = {  0, +1, +2, +2, +2, +2, +2, +1, 0, -1, -2, -2, -2, -2, -2, -1 };
+static const int y_fact16[] = { -2, -2, -2, -1,  0, +1, +2, +2, +2, +2, +2, +1, 0, -1, -2, -2 };
+
+/**
+ *  Return the direction for a given slope (0-7).
+ *  NOTE:  Assumes cartesian coords, NOT screen coords. (which have y
+ *    growing downwards).
+ *
+ *  NOTE: The returned direction is rotated 45 degrees clockwise! This is
+ *  how U8 things should be.
+ */
+inline Direction Direction_Get(int deltay, int deltax) {
+	if (deltax == 0)
+		return deltay > 0 ? dir_northwest : dir_southeast;
+	int dydx = (1024 * deltay) / deltax; // Figure 1024*tan.
+	if (dydx >= 0)
+		if (deltax > 0) // Top-right
+			return dydx <= 424 ? dir_northeast : dydx <= 2472 ? dir_north
+				   : dir_northwest;
+		else			// Bottom-left.
+			return dydx <= 424 ? dir_southwest : dydx <= 2472 ? dir_south
+				   : dir_southeast;
+	else if (deltax > 0) // Bottom-right.
+		return dydx >= -424 ? dir_northeast : dydx >= -2472 ? dir_east
+			   : dir_southeast;
+	else			// Top-left
+		return dydx >= -424 ? dir_southwest : dydx >= -2472 ? dir_west
+			   : dir_northwest;
+}
+
+inline Direction Direction_GetWorldDir(int deltay, int deltax) {
+	if (deltax == 0) {
+		if (deltay == 0) return dir_northeast; // for better compatibility with U8
+		return deltay > 0 ? dir_south : dir_north;
+	}
+	int dydx = (1024 * deltay) / deltax;
+
+	if (dydx >= 0)
+		if (deltax > 0) // south-east
+			return dydx <= 424 ? dir_east : dydx <= 2472 ? dir_southeast : dir_south;
+		else			// north-west
+			return dydx <= 424 ? dir_west : dydx <= 2472 ? dir_northwest : dir_north;
+	else if (deltax > 0) // north-east
+		return dydx >= -424 ? dir_east : dydx >= -2472 ? dir_northeast : dir_north;
+	else			// south-west
+		return dydx >= -424 ? dir_west : dydx >= -2472 ? dir_southwest : dir_south;
+}
+
+inline Direction Direction_GetWorldDirInRange(int deltay, int deltax, uint16 ndirs, uint16 mindir, uint16 maxdir) {
+	// TODO: Implement proper 16 directions here.
+	uint32 dir = static_cast<uint32>(Direction_GetWorldDir(deltay, deltax));
+	if (ndirs == 16) {
+		dir *= 2;
+	}
+
+	if ((dir < mindir) || (dir > maxdir)) {
+		int32 dmin1 = dir - mindir;
+		int32 dmin2 = mindir - dir;
+		if (dmin1 < 0) {
+			dmin1 = dmin1 + ndirs;
+		}
+		if (dmin2 < 0) {
+			dmin2 = dmin2 + ndirs;
+		}
+		int32 dist_to_min = MIN(dmin1, dmin2);
+
+		int dmax1 = dir - maxdir;
+		int dmax2 = maxdir - dir;
+		if (dmax1 < 0) {
+			dmax1 = dmax1 + ndirs;
+		}
+		if (dmax2 < 0) {
+			dmax2 = dmax2 + ndirs;
+		}
+		int32 dist_to_max = MIN(dmax1, dmax2);
+
+		if (dist_to_min < dist_to_max) {
+			return static_cast<Direction>(mindir);
+		} else {
+			return static_cast<Direction>(maxdir);
+		}
+	}
+
+	return static_cast<Direction>(dir);
+}
+
+inline Direction Direction_Invert(Direction dir) {
+	// TODO: support 16 dirs here.
+	assert(dir != dir_current);
+	return static_cast<Direction>((static_cast<int>(dir) + 4) % 8);
+}
+
+//! Return the direction one left (aka counter-clockwise) of the input
+inline Direction Direction_OneLeft(Direction dir) {
+	// TODO: support 16 dirs here.
+	return static_cast<Direction>((static_cast<int>(dir) + 7) % 8);
+}
+
+//! Return the direction one right (aka clockwise) of the input
+inline Direction Direction_OneRight(Direction dir) {
+	// TODO: support 16 dirs here.
+	return static_cast<Direction>((static_cast<int>(dir) + 1) % 8);
+}
+
+inline Direction Direction_TurnByDelta(Direction dir, int delta) {
+	// TODO: support 16 dirs here.
+	return static_cast<Direction>((static_cast<int>(dir) + delta + 8) % 8);
+}
+
+//! Get a turn delta (-1 for left, +1 for right) to turn the fastest
+//! way from one direction to another
+inline int Direction_GetShorterTurnDelta(Direction from, Direction to) {
+	// TODO: Support 16 dirs here.
+	if ((from - to + 8) % 8 < 4)
+		return -1;
+	return 1;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 46a04e2f4a..55aee4e6ee 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -31,6 +31,7 @@
 #include "ultima/ultima8/world/actors/animation_tracker.h"
 #include "ultima/ultima8/world/current_map.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/games/game_data.h"
 #include "ultima/ultima8/graphics/main_shape_archive.h"
 #include "ultima/ultima8/world/actors/anim_action.h"
@@ -69,7 +70,7 @@ DEFINE_RUNTIME_CLASSTYPE_CODE(Actor)
 
 Actor::Actor() : _strength(0), _dexterity(0), _intelligence(0),
 		_hitPoints(0), _mana(0), _alignment(0), _enemyAlignment(0),
-		_lastAnim(Animation::stand), _animFrame(0), _direction(0),
+		_lastAnim(Animation::stand), _animFrame(0), _direction(dir_north),
 		_fallStart(0), _unkByte(0), _actorFlags(0), _combatTactic(0),
 		_homeX(0), _homeY(0), _homeZ(0), _currentActivityNo(0),
 		_lastActivityNo(0) {
@@ -462,7 +463,7 @@ void Actor::teleport(int newmap, int32 newx, int32 newy, int32 newz) {
 		notifyNearbyItems();
 }
 
-uint16 Actor::doAnim(Animation::Sequence anim, int dir, unsigned int steps) {
+uint16 Actor::doAnim(Animation::Sequence anim, Direction dir, unsigned int steps) {
 	if (dir < 0 || dir > 16) {
 		perr << "Actor::doAnim: Invalid _direction (" << dir << ")" << Std::endl;
 		return 0;
@@ -484,10 +485,10 @@ uint16 Actor::doAnim(Animation::Sequence anim, int dir, unsigned int steps) {
 bool Actor::hasAnim(Animation::Sequence anim) {
 	AnimationTracker tracker;
 
-	return tracker.init(this, anim, 0);
+	return tracker.init(this, anim, dir_north);
 }
 
-Animation::Result Actor::tryAnim(Animation::Sequence anim, int dir,
+Animation::Result Actor::tryAnim(Animation::Sequence anim, Direction dir,
                                  unsigned int steps, PathfindingState *state) {
 	if (dir < 0 || dir > 16) return Animation::FAILURE;
 
@@ -545,19 +546,16 @@ Animation::Result Actor::tryAnim(Animation::Sequence anim, int dir,
 	return Animation::END_OFF_LAND;
 }
 
-uint16 Actor::turnTowardDir(uint16 targetdir) {
-	uint16 curdir = _direction;
+uint16 Actor::turnTowardDir(Direction targetdir) {
+	Direction curdir = _direction;
 	if (targetdir == curdir)
 		return 0;
 
-	// TODO; this should support 16 dirs too
-	int stepDelta;
+	int stepDelta = Direction_GetShorterTurnDelta(curdir, targetdir);
 	Animation::Sequence turnanim;
-	if ((curdir - targetdir + 8) % 8 < 4) {
-		stepDelta = -1;
+	if (stepDelta == -1) {
 		turnanim = Animation::lookLeft;
 	} else {
-		stepDelta = 1;
 		turnanim = Animation::lookRight;
 	}
 
@@ -565,7 +563,7 @@ uint16 Actor::turnTowardDir(uint16 targetdir) {
 
 	// Create a sequence of turn animations from
 	// our current direction to the new one
-	for (int dir = curdir; dir != targetdir;) {
+	for (Direction dir = curdir; dir != targetdir; dir = Direction_TurnByDelta(dir, stepDelta)) {
 		ProcId animpid = doAnim(turnanim, dir);
 		if (prevpid) {
 			Process *proc = Kernel::get_instance()->getProcess(animpid);
@@ -574,7 +572,6 @@ uint16 Actor::turnTowardDir(uint16 targetdir) {
 		}
 
 		prevpid = animpid;
-		dir = (dir + stepDelta + 8) % 8;
 	}
 
 	return prevpid;
@@ -730,7 +727,7 @@ void Actor::getHomePosition(int32 &x, int32 &y, int32 &z) const {
 }
 
 
-void Actor::receiveHit(uint16 other, int dir, int damage, uint16 damage_type) {
+void Actor::receiveHit(uint16 other, Direction dir, int damage, uint16 damage_type) {
 	if (GAME_IS_U8) {
 		receiveHitU8(other, dir, damage, damage_type);
 	} else {
@@ -738,7 +735,7 @@ void Actor::receiveHit(uint16 other, int dir, int damage, uint16 damage_type) {
 	}
 }
 
-void Actor::receiveHitCru(uint16 other, int dir, int damage, uint16 damage_type) {
+void Actor::receiveHitCru(uint16 other, Direction dir, int damage, uint16 damage_type) {
 	//
 	// This is a big stack of constants and hard-coded things.
 	// It's like that in the original game.
@@ -843,7 +840,7 @@ void Actor::receiveHitCru(uint16 other, int dir, int damage, uint16 damage_type)
 	}
 }
 
-void Actor::receiveHitU8(uint16 other, int dir, int damage, uint16 damage_type) {
+void Actor::receiveHitU8(uint16 other, Direction dir, int damage, uint16 damage_type) {
 	if (isDead())
 		return; // already dead, so don't bother
 
@@ -1415,7 +1412,7 @@ bool Actor::loadData(Common::ReadStream *rs, uint32 version) {
 	_enemyAlignment = rs->readUint16LE();
 	_lastAnim = static_cast<Animation::Sequence>(rs->readUint16LE());
 	_animFrame = rs->readUint16LE();
-	_direction = rs->readUint16LE();
+	_direction = static_cast<Direction>(rs->readUint16LE());
 	_fallStart = rs->readUint32LE();
 	_actorFlags = rs->readUint32LE();
 	_unkByte = rs->readByte();
@@ -1470,7 +1467,7 @@ uint32 Actor::I_doAnim(const uint8 *args, unsigned int /*argsize*/) {
 
 	if (!actor) return 0;
 
-	return actor->doAnim(static_cast<Animation::Sequence>(anim), dir);
+	return actor->doAnim(static_cast<Animation::Sequence>(anim), static_cast<Direction>(dir));
 }
 
 uint32 Actor::I_getDir(const uint8 *args, unsigned int /*argsize*/) {
@@ -1951,7 +1948,7 @@ uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
 		return 0;
 	}
 
-	newactor->setDir(dir);
+	newactor->setDir(static_cast<Direction>(dir));
 
 	int32 x, y, z;
 	item->getLocation(x, y, z);
@@ -2140,8 +2137,8 @@ uint32 Actor::I_turnToward(const uint8 *args, unsigned int /*argsize*/) {
 	ARG_UINT16(dir);
 	ARG_UINT16(unk);
 
-	// TODO: This is hacked to be the 8 dir version..
-	return actor->turnTowardDir(dir / 2);
+	// FIXME: This is hacked to be the 8 dir version..
+	return actor->turnTowardDir(static_cast<Direction>(dir / 2));
 }
 
 
diff --git a/engines/ultima/ultima8/world/actors/actor.h b/engines/ultima/ultima8/world/actors/actor.h
index 9b366c5543..d59f7e3850 100644
--- a/engines/ultima/ultima8/world/actors/actor.h
+++ b/engines/ultima/ultima8/world/actors/actor.h
@@ -110,10 +110,10 @@ public:
 	void setLastAnim(Animation::Sequence anim) {
 		_lastAnim = anim;
 	}
-	uint16 getDir() const {
+	Direction getDir() const {
 		return _direction;
 	}
-	void setDir(uint16 dir) {
+	void setDir(Direction dir) {
 		_direction = dir;
 	}
 	int32 getFallStart() const {
@@ -186,7 +186,7 @@ public:
 	//! receive a hit
 	//! \param damage base damage (or zero to use attacker's default damage)
 	//! \param type damage type (or zero to use attacker's default type)
-	void receiveHit(uint16 other, int dir, int damage, uint16 type) override;
+	void receiveHit(uint16 other, Direction dir, int damage, uint16 type) override;
 
 	//! die
 	//! \param damageType damage type that caused the death
@@ -224,7 +224,7 @@ public:
 
 	//! run the given animation
 	//! \return the PID of the ActorAnimProcess
-	uint16 doAnim(Animation::Sequence anim, int dir, unsigned int steps = 0);
+	uint16 doAnim(Animation::Sequence anim, Direction dir, unsigned int steps = 0);
 
 	//! check if this actor has a specific animation
 	bool hasAnim(Animation::Sequence anim);
@@ -234,9 +234,9 @@ public:
 	//! state will be updated to after the animation. If unsuccessful,
 	//! the contents of state are undefined.
 	//! \param anim Action to try
-	//! \param dir _direction to walk in
+	//! \param dir direction to walk in
 	//! \param state the state to start from, or 0 to use the current state
-	Animation::Result tryAnim(Animation::Sequence anim, int dir, unsigned int steps = 0, PathfindingState *state = 0);
+	Animation::Result tryAnim(Animation::Sequence anim, Direction dir, unsigned int steps = 0, PathfindingState *state = 0);
 
 	//! overrides the standard item collideMove so we  can notify nearby objects.
 	int32 collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
@@ -244,7 +244,7 @@ public:
 
 	//! Turn one step toward the given direction. If the current direction is already the same,
 	//! do nothing. Returns an anim process or 0 if no move needed.
-	uint16 turnTowardDir(uint16 dir);
+	uint16 turnTowardDir(Direction dir);
 
 	//! create an actor, assign objid, make it ethereal and load monster stats.
 	static Actor *createActor(uint32 shape, uint32 frame);
@@ -362,7 +362,7 @@ protected:
 
 	Animation::Sequence _lastAnim;
 	uint16 _animFrame;
-	uint16 _direction;
+	Direction _direction;
 
 	int32 _fallStart;
 
@@ -398,8 +398,8 @@ protected:
 	bool loadMonsterStatsU8();
 	bool loadMonsterStatsCru();
 
-	void receiveHitU8(uint16 other, int dir, int damage, uint16 type);
-	void receiveHitCru(uint16 other, int dir, int damage, uint16 type);
+	void receiveHitU8(uint16 other, Direction dir, int damage, uint16 type);
+	void receiveHitCru(uint16 other, Direction dir, int damage, uint16 type);
 };
 
 } // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
index d4860eaecf..89b6de61cf 100644
--- a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
@@ -29,6 +29,7 @@
 #include "ultima/ultima8/world/actors/anim_action.h"
 #include "ultima/ultima8/world/actors/main_actor.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/world/world.h"
 #include "ultima/ultima8/world/gravity_process.h"
 #include "ultima/ultima8/kernel/kernel.h"
@@ -61,13 +62,13 @@ static const int watchactor = WATCHACTOR;
 DEFINE_RUNTIME_CLASSTYPE_CODE(ActorAnimProcess)
 
 ActorAnimProcess::ActorAnimProcess() : Process(), _tracker(nullptr),
-	_dir(0), _action(Animation::walk), _steps(0), _firstFrame(true),
+	_dir(dir_north), _action(Animation::walk), _steps(0), _firstFrame(true),
 	_currentStep(0), _repeatCounter(0), _animAborted(false),
 	_attackedSomething(false) {
 }
 
 ActorAnimProcess::ActorAnimProcess(Actor *actor, Animation::Sequence action,
-                                   uint32 dir, uint32 steps) :
+                                   Direction dir, uint32 steps) :
 		_dir(dir), _action(action), _steps(steps), _tracker(nullptr),
 		_firstFrame(true), _currentStep(0), _repeatCounter(0),
 		_animAborted(false), _attackedSomething(false)  {
@@ -279,7 +280,7 @@ void ActorAnimProcess::run() {
 				_attackedSomething = true;
 				Item *hit_item = getItem(hit);
 				assert(hit_item);
-				hit_item->receiveHit(_itemNum, (_dir + 4) % 8, 0, 0);
+				hit_item->receiveHit(_itemNum, Direction_Invert(_dir), 0, 0);
 				doHitSpecial(hit_item);
 			}
 		}
@@ -405,7 +406,7 @@ void ActorAnimProcess::doSpecial() {
 				return;
 			}
 			ghoul->move(x, y, z);
-			ghoul->doAnim(Animation::standUp, 0);
+			ghoul->doAnim(Animation::standUp, dir_north);
 			hostile = ghoul;
 		}
 
@@ -664,7 +665,7 @@ bool ActorAnimProcess::loadData(Common::ReadStream *rs, uint32 version) {
 	_firstFrame = (rs->readByte() != 0);
 	_animAborted = (rs->readByte() != 0);
 	_attackedSomething = (rs->readByte() != 0);
-	_dir = rs->readByte();
+	_dir = static_cast<Direction>(rs->readByte());
 	_action = static_cast<Animation::Sequence>(rs->readUint16LE());
 	_steps = rs->readUint16LE();
 	_repeatCounter = rs->readUint16LE();
diff --git a/engines/ultima/ultima8/world/actors/actor_anim_process.h b/engines/ultima/ultima8/world/actors/actor_anim_process.h
index aadd056cf1..220591bb9f 100644
--- a/engines/ultima/ultima8/world/actors/actor_anim_process.h
+++ b/engines/ultima/ultima8/world/actors/actor_anim_process.h
@@ -24,6 +24,7 @@
 #define WORLD_ACTORS_ACTORANIMPROCESS_H
 
 #include "ultima/ultima8/kernel/process.h"
+#include "ultima/ultima8/misc/direction.h"
 #include "ultima/ultima8/world/actors/animation.h"
 
 namespace Ultima {
@@ -38,7 +39,7 @@ class ActorAnimProcess : public Process {
 public:
 	ActorAnimProcess();
 	//! note: this probably needs some more parameters
-	ActorAnimProcess(Actor *actor, Animation::Sequence action, uint32 dir,
+	ActorAnimProcess(Actor *actor, Animation::Sequence action, Direction dir,
 	                 uint32 steps = 0);
 
 	// p_dynamic_cast stuff
@@ -69,7 +70,7 @@ protected:
 	void doHitSpecial(Item *hit);
 
 	Animation::Sequence _action;
-	uint32 _dir;
+	Direction _dir;
 	uint32 _steps;
 
 	AnimationTracker *_tracker;
diff --git a/engines/ultima/ultima8/world/actors/animation_tracker.cpp b/engines/ultima/ultima8/world/actors/animation_tracker.cpp
index d5982078e5..c54384631c 100644
--- a/engines/ultima/ultima8/world/actors/animation_tracker.cpp
+++ b/engines/ultima/ultima8/world/actors/animation_tracker.cpp
@@ -30,6 +30,7 @@
 #include "ultima/ultima8/graphics/anim_dat.h"
 #include "ultima/ultima8/world/actors/anim_action.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/graphics/shape_info.h"
 #include "ultima/ultima8/usecode/uc_list.h"
 #include "ultima/ultima8/world/loop_script.h"
@@ -47,7 +48,7 @@ static const int watchactor = WATCHACTOR;
 
 AnimationTracker::AnimationTracker() : _firstFrame(true), _done(false),
 	_blocked(false), _unsupported(false), _hitObject(0), _mode(NormalMode),
-	_actor(0), _dir(0), _animAction(nullptr), _x(0), _y(0), _z(0),
+	_actor(0), _dir(dir_north), _animAction(nullptr), _x(0), _y(0), _z(0),
 	_prevX(0), _prevY(0), _prevZ(0), _startX(0), _startY(0), _startZ(0),
 	_targetDx(0), _targetDy(0), _targetDz(0), _targetOffGroundLeft(0),
 	_firstStep(false), _shapeFrame(0), _currentFrame(0), _startFrame(0),
@@ -59,7 +60,7 @@ AnimationTracker::~AnimationTracker() {
 
 
 bool AnimationTracker::init(const Actor *actor, Animation::Sequence action,
-                            uint32 dir, const PathfindingState *state) {
+                            Direction dir, const PathfindingState *state) {
 	assert(actor);
 	_actor = actor->getObjId();
 	uint32 shape = actor->getShape();
@@ -137,7 +138,7 @@ bool AnimationTracker::stepFrom(int32 x_, int32 y_, int32 z_) {
 	return step();
 }
 
-void AnimationTracker::evaluateMaxAnimTravel(int32 &max_endx, int32 &max_endy, uint32 dir_) {
+void AnimationTracker::evaluateMaxAnimTravel(int32 &max_endx, int32 &max_endy, Direction dir) {
 	max_endx = _x;
 	max_endy = _y;
 
@@ -153,10 +154,10 @@ void AnimationTracker::evaluateMaxAnimTravel(int32 &max_endx, int32 &max_endy, u
 		testframe = getNextFrame(_currentFrame);
 
 	for (;;) {
-		AnimFrame &f = _animAction->frames[dir_][testframe];
+		AnimFrame &f = _animAction->frames[dir][testframe];
 		// determine movement for this frame
-		int32 dx = 4 * x_fact[dir_] * f._deltaDir;
-		int32 dy = 4 * y_fact[dir_] * f._deltaDir;
+		int32 dx = 4 * x_fact[dir] * f._deltaDir;
+		int32 dy = 4 * y_fact[dir] * f._deltaDir;
 		max_endx += dx;
 		max_endy += dy;
 		testframe = getNextFrame(testframe);
@@ -629,7 +630,7 @@ bool AnimationTracker::load(Common::ReadStream *rs, uint32 version) {
 	_currentFrame = rs->readUint32LE();
 
 	_actor = rs->readUint16LE();
-	_dir = rs->readByte();
+	_dir = static_cast<Direction>(rs->readByte());
 
 	uint32 shapenum = rs->readUint32LE();
 	uint32 action = rs->readUint32LE();
diff --git a/engines/ultima/ultima8/world/actors/animation_tracker.h b/engines/ultima/ultima8/world/actors/animation_tracker.h
index efcc9557a3..7cf8ebf919 100644
--- a/engines/ultima/ultima8/world/actors/animation_tracker.h
+++ b/engines/ultima/ultima8/world/actors/animation_tracker.h
@@ -41,12 +41,12 @@ public:
 	//! initialize the AnimationTracker for the given actor, action, dir
 	//! if state is non-zero, start from that state instead of the Actor's
 	//! current state
-	bool init(const Actor *actor, Animation::Sequence action, uint32 dir,
+	bool init(const Actor *actor, Animation::Sequence action, Direction dir,
 	          const PathfindingState *state = 0);
 
 	//! evaluate the maximum distance the actor will travel if the current
 	//! animation runs to completion by incremental calls to step
-	void evaluateMaxAnimTravel(int32 &max_endx, int32 &max_endy, uint32 dir_);
+	void evaluateMaxAnimTravel(int32 &max_endx, int32 &max_endy, Direction dir_);
 
 	//! do a single step of the animation
 	//! returns true if everything ok, false if not
@@ -122,7 +122,7 @@ private:
 	unsigned int _currentFrame;
 
 	ObjId _actor;
-	unsigned int _dir;
+	Direction _dir;
 
 	AnimAction *_animAction;
 
diff --git a/engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp b/engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp
index 9f90a70287..3188e0ef49 100644
--- a/engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp
+++ b/engines/ultima/ultima8/world/actors/avatar_gravity_process.cpp
@@ -55,7 +55,7 @@ void AvatarGravityProcess::run() {
 
 	// right mouse button down, so see if we can cling to a ledge
 	MainActor *avatar = getMainActor();
-	int32 direction = avatar->getDir();
+	Direction direction = avatar->getDir();
 	if (avatar->tryAnim(Animation::climb40, direction) == Animation::SUCCESS) {
 
 		// we can, so perform a hang animation
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
index 45c4388b95..e0f7d8817d 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
@@ -35,6 +35,7 @@
 #include "ultima/ultima8/audio/music_process.h"
 #include "ultima/ultima8/world/get_object.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 
 namespace Ultima {
 namespace Ultima8 {
@@ -130,14 +131,14 @@ void AvatarMoverProcess::handleCombatMode() {
 	Mouse *mouse = Mouse::get_instance();
 	MainActor *avatar = getMainActor();
 	Animation::Sequence lastanim = avatar->getLastAnim();
-	int32 direction = avatar->getDir();
+	Direction direction = avatar->getDir();
 	bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
 
 	int32 mx, my;
 	mouse->getMouseCoords(mx, my);
 	unsigned int mouselength = mouse->getMouseLength(mx, my);
 
-	int32 mousedir = mouse->getMouseDirectionWorld(mx, my);
+	Direction mousedir = mouse->getMouseDirectionWorld(mx, my);
 
 	// never idle when in combat
 	_idleTime = 0;
@@ -255,7 +256,7 @@ void AvatarMoverProcess::handleCombatMode() {
 			return;
 
 		//!! TODO: check if you can actually take this step
-		int32 nextdir = mousedir;
+		Direction nextdir = mousedir;
 		Animation::Sequence nextanim;
 
 		if (lastanim == Animation::run) {
@@ -292,11 +293,11 @@ void AvatarMoverProcess::handleCombatMode() {
 	//  if we are trying to move, allow change direction only after move occurs to avoid spinning
 	if (moving || !hasMovementFlags(MOVE_FORWARD | MOVE_BACK)) {
 		if (hasMovementFlags(MOVE_TURN_LEFT)) {
-			direction = (direction + 7) % 8;
+			direction = Direction_OneLeft(direction);
 		}
 
 		if (hasMovementFlags(MOVE_TURN_RIGHT)) {
-			direction = (direction + 1) % 8;
+			direction = Direction_OneRight(direction);
 		}
 	}
 
@@ -343,7 +344,7 @@ void AvatarMoverProcess::handleCombatMode() {
 	}
 
 	if (x != 0 || y != 0) {
-		int32 nextdir =  Get_direction(y, x);
+		Direction nextdir = Direction_Get(y, x);
 
 		if (checkTurn(nextdir, true))
 			return;
@@ -390,14 +391,14 @@ void AvatarMoverProcess::handleNormalMode() {
 	Mouse *mouse = Mouse::get_instance();
 	MainActor *avatar = getMainActor();
 	Animation::Sequence lastanim = avatar->getLastAnim();
-	int32 direction = avatar->getDir();
+	Direction direction = avatar->getDir();
 	bool stasis = guiapp->isAvatarInStasis();
 	bool combatRun = avatar->hasActorFlags(Actor::ACT_COMBATRUN);
 
 	int32 mx, my;
 	mouse->getMouseCoords(mx, my);
 	unsigned int mouselength = mouse->getMouseLength(mx, my);
-	int32 mousedir = mouse->getMouseDirectionWorld(mx, my);
+	Direction mousedir = mouse->getMouseDirectionWorld(mx, my);
 
 	// Store current idle time. (Also see end of function.)
 	uint32 currentIdleTime = _idleTime;
@@ -623,11 +624,11 @@ void AvatarMoverProcess::handleNormalMode() {
 	//  if we are trying to move, allow change direction only after move occurs to avoid spinning
 	if (moving || !hasMovementFlags(MOVE_FORWARD | MOVE_BACK)) {
 		if (hasMovementFlags(MOVE_TURN_LEFT)) {
-			direction = (direction + 7) % 8;
+			direction = Direction_OneLeft(direction);
 		}
 
 		if (hasMovementFlags(MOVE_TURN_RIGHT)) {
-			direction = (direction + 1) % 8;
+			direction = Direction_OneRight(direction);
 		}
 	}
 
@@ -650,7 +651,7 @@ void AvatarMoverProcess::handleNormalMode() {
 	}
 
 	if (hasMovementFlags(MOVE_BACK)) {
-		step(nextanim, (direction + 4) % 8);
+		step(nextanim, Direction_Invert(direction));
 
 		// flip to move forward once turned
 		setMovementFlag(MOVE_FORWARD);
@@ -673,7 +674,7 @@ void AvatarMoverProcess::handleNormalMode() {
 	}
 
 	if (x != 0 || y != 0) {
-		direction = Get_direction(y, x);
+		direction = Direction_Get(y, x);
 		step(nextanim, direction);
 		return;
 	}
@@ -721,7 +722,7 @@ void AvatarMoverProcess::handleNormalMode() {
 	}
 }
 
-void AvatarMoverProcess::step(Animation::Sequence action, int direction,
+void AvatarMoverProcess::step(Animation::Sequence action, Direction direction,
                               bool adjusted) {
 	assert(action == Animation::step || action == Animation::walk ||
 	       action == Animation::run);
@@ -731,13 +732,13 @@ void AvatarMoverProcess::step(Animation::Sequence action, int direction,
 
 	Animation::Result res = avatar->tryAnim(action, direction);
 
-	int stepdir = direction;
+	Direction stepdir = direction;
 
 	if (res == Animation::FAILURE ||
 	        (action == Animation::step && res == Animation::END_OFF_LAND)) {
 		debug(6, "Step: end off land dir %d, try other dir", stepdir);
-		int altdir1 = (stepdir + 1) % 8;
-		int altdir2 = (stepdir + 7) % 8;
+		Direction altdir1 = Direction_OneRight(stepdir);
+		Direction altdir2 = Direction_OneLeft(stepdir);
 
 		res = avatar->tryAnim(action, altdir1);
 		if (res == Animation::FAILURE ||
@@ -793,7 +794,7 @@ void AvatarMoverProcess::step(Animation::Sequence action, int direction,
 	waitFor(avatar->doAnim(action, stepdir));
 }
 
-void AvatarMoverProcess::jump(Animation::Sequence action, int direction) {
+void AvatarMoverProcess::jump(Animation::Sequence action, Direction direction) {
 	MainActor *avatar = getMainActor();
 
 	// running jump
@@ -845,21 +846,18 @@ void AvatarMoverProcess::jump(Animation::Sequence action, int direction) {
 	}
 }
 
-void AvatarMoverProcess::turnToDirection(int direction) {
+void AvatarMoverProcess::turnToDirection(Direction direction) {
 	MainActor *avatar = getMainActor();
 	bool combatRun = avatar->hasActorFlags(Actor::ACT_COMBATRUN);
-	int curdir = avatar->getDir();
-	int stepDelta;
+	Direction curdir = avatar->getDir();
 	bool combat = avatar->isInCombat() && !combatRun;
-	Animation::Sequence turnanim;
 	Animation::Sequence standanim = Animation::stand;
 
-	// note curdir-direction can be negative, hence + 8 % 8
-	if ((curdir - direction + 8) % 8 < 4) {
-		stepDelta = -1;
+	int stepDelta = Direction_GetShorterTurnDelta(curdir, direction);
+	Animation::Sequence turnanim;
+	if (stepDelta == -1) {
 		turnanim = Animation::lookLeft;
 	} else {
-		stepDelta = 1;
 		turnanim = Animation::lookRight;
 	}
 
@@ -872,7 +870,7 @@ void AvatarMoverProcess::turnToDirection(int direction) {
 
 	// Create a sequence of turn animations from
 	// our current direction to the new one
-	for (int dir = curdir; dir != direction;) {
+	for (Direction dir = curdir; dir != direction; dir = Direction_TurnByDelta(dir, stepDelta)) {
 		ProcId animpid = avatar->doAnim(turnanim, dir);
 
 		if (prevpid) {
@@ -882,8 +880,6 @@ void AvatarMoverProcess::turnToDirection(int direction) {
 		}
 
 		prevpid = animpid;
-
-		dir = (dir + stepDelta + 8) % 8;
 	}
 
 	ProcId animpid = avatar->doAnim(standanim, direction);
@@ -897,9 +893,9 @@ void AvatarMoverProcess::turnToDirection(int direction) {
 	waitFor(animpid);
 }
 
-bool AvatarMoverProcess::checkTurn(int direction, bool moving) {
+bool AvatarMoverProcess::checkTurn(Direction direction, bool moving) {
 	MainActor *avatar = getMainActor();
-	int curdir = avatar->getDir();
+	Direction curdir = avatar->getDir();
 	bool combat = avatar->isInCombat() && !avatar->hasActorFlags(Actor::ACT_COMBATRUN);
 
 	// Note: don't need to turn if moving backward in combat stance
@@ -938,7 +934,7 @@ bool AvatarMoverProcess::canAttack() {
 
 void AvatarMoverProcess::tryAttack() {
 	MainActor *avatar = getMainActor();
-	uint16 dir = avatar->getDir();
+	Direction dir = avatar->getDir();
 	if (!avatar->isInCombat()) {
 		avatar->setInCombat();
 		waitFor(avatar->doAnim(Animation::readyWeapon, dir));
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.h b/engines/ultima/ultima8/world/actors/avatar_mover_process.h
index 681b3e1b95..494d0a8669 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.h
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.h
@@ -88,10 +88,10 @@ private:
 	void handleCombatMode();
 	void handleNormalMode();
 
-	void step(Animation::Sequence action, int direction, bool adjusted = false);
-	void jump(Animation::Sequence action, int direction);
-	void turnToDirection(int direction);
-	bool checkTurn(int direction, bool moving);
+	void step(Animation::Sequence action, Direction direction, bool adjusted = false);
+	void jump(Animation::Sequence action, Direction direction);
+	void turnToDirection(Direction direction);
+	bool checkTurn(Direction direction, bool moving);
 	bool canAttack();
 
 	uint32 _lastFrame;
diff --git a/engines/ultima/ultima8/world/actors/combat_process.cpp b/engines/ultima/ultima8/world/actors/combat_process.cpp
index f3474990d3..cfce2a20ea 100644
--- a/engines/ultima/ultima8/world/actors/combat_process.cpp
+++ b/engines/ultima/ultima8/world/actors/combat_process.cpp
@@ -35,6 +35,7 @@
 #include "ultima/ultima8/graphics/shape_info.h"
 #include "ultima/ultima8/world/actors/monster_info.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/world/get_object.h"
 #include "ultima/ultima8/world/actors/loiter_process.h"
 #include "ultima/ultima8/world/actors/ambush_process.h"
@@ -91,7 +92,7 @@ void CombatProcess::run() {
 		_combatMode = CM_WAITING;
 	}
 
-	int targetdir = getTargetDirection();
+	Direction targetdir = getTargetDirection();
 	if (a->getDir() != targetdir) {
 		turnToDirection(targetdir);
 		return;
@@ -235,28 +236,27 @@ ObjId CombatProcess::seekTarget() {
 	return 0;
 }
 
-int CombatProcess::getTargetDirection() {
+Direction CombatProcess::getTargetDirection() {
 	Actor *a = getActor(_itemNum);
 	Actor *t = getActor(_target);
 	if (!a || !t)
-		return 0; // shouldn't happen
+		return dir_north; // shouldn't happen
 
 	return a->getDirToItemCentre(*t);
 }
 
-void CombatProcess::turnToDirection(int direction) {
+void CombatProcess::turnToDirection(Direction direction) {
 	Actor *a = getActor(_itemNum);
 	if (!a)
 		return;
-	int curdir = a->getDir();
-	int step = 1;
-	if ((curdir - direction + 8) % 8 < 4) step = -1;
+	Direction curdir = a->getDir();
+	int stepDelta = Direction_GetShorterTurnDelta(curdir, direction);
 	Animation::Sequence turnanim = Animation::combatStand;
 
 	ProcId prevpid = 0;
 	bool done = false;
 
-	for (int dir = curdir; !done;) {
+	for (Direction dir = curdir; !done;	dir = Direction_TurnByDelta(dir, stepDelta)) {
 		ProcId animpid = a->doAnim(turnanim, dir);
 
 		if (dir == direction) done = true;
@@ -268,8 +268,6 @@ void CombatProcess::turnToDirection(int direction) {
 		}
 
 		prevpid = animpid;
-
-		dir = (dir + step + 8) % 8;
 	}
 
 	if (prevpid) waitFor(prevpid);
diff --git a/engines/ultima/ultima8/world/actors/combat_process.h b/engines/ultima/ultima8/world/actors/combat_process.h
index ff944c2786..a3cca3dc23 100644
--- a/engines/ultima/ultima8/world/actors/combat_process.h
+++ b/engines/ultima/ultima8/world/actors/combat_process.h
@@ -24,6 +24,7 @@
 #define WORLD_ACTORS_COMBATPROCESS_H
 
 #include "ultima/ultima8/kernel/process.h"
+#include "ultima/ultima8/misc/direction.h"
 
 namespace Ultima {
 namespace Ultima8 {
@@ -55,9 +56,9 @@ protected:
 	bool isValidTarget(Actor *target_);
 	bool isEnemy(Actor *target_);
 	bool inAttackRange();
-	int getTargetDirection();
+	Direction getTargetDirection();
 
-	void turnToDirection(int direction);
+	void turnToDirection(Direction direction);
 	void waitForTarget();
 
 	ObjId _target;
diff --git a/engines/ultima/ultima8/world/actors/grant_peace_process.cpp b/engines/ultima/ultima8/world/actors/grant_peace_process.cpp
index 70f5d22595..1bd74b2183 100644
--- a/engines/ultima/ultima8/world/actors/grant_peace_process.cpp
+++ b/engines/ultima/ultima8/world/actors/grant_peace_process.cpp
@@ -112,7 +112,7 @@ void GrantPeaceProcess::run() {
 
 			// undead?
 			if (t->getDefenseType() & WeaponInfo::DMG_UNDEAD) {
-				t->receiveHit(_itemNum, 8, target->getHP(),
+				t->receiveHit(_itemNum, dir_current, target->getHP(),
 				              (WeaponInfo::DMG_MAGIC |
 				               WeaponInfo::DMG_PIERCE |
 				               WeaponInfo::DMG_FIRE));
@@ -153,7 +153,7 @@ void GrantPeaceProcess::run() {
 								   Actor::ACT_IMMORTAL |
 								   Actor::ACT_INVINCIBLE)) {
 			if (getRandom() % 10 == 0) {
-				target->receiveHit(_itemNum, 8, target->getHP(),
+				target->receiveHit(_itemNum, dir_current, target->getHP(),
 				                   (WeaponInfo::DMG_MAGIC |
 				                    WeaponInfo::DMG_PIERCE |
 				                    WeaponInfo::DMG_FIRE));
diff --git a/engines/ultima/ultima8/world/actors/pathfinder.cpp b/engines/ultima/ultima8/world/actors/pathfinder.cpp
index 1fbfa51fb5..4adf390a45 100644
--- a/engines/ultima/ultima8/world/actors/pathfinder.cpp
+++ b/engines/ultima/ultima8/world/actors/pathfinder.cpp
@@ -21,6 +21,8 @@
  */
 
 #include "ultima/ultima8/misc/pent_include.h"
+#include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/world/actors/pathfinder.h"
 #include "ultima/ultima8/world/actors/actor.h"
 #include "ultima/ultima8/world/actors/animation_tracker.h"
@@ -431,8 +433,10 @@ void Pathfinder::expandNode(PathNode *node) {
 	if (_actor->isInCombat())
 		walkanim = Animation::advance;
 
-	// try walking in all 8 directions
-	for (uint32 dir = 0; dir < 8; ++dir) {
+	// try walking in all 8 directions - TODO: should this support 16 dirs?
+	Direction dir = dir_north;
+	for (int i = 0; i < 8; i++) {
+		dir = Direction_OneRight(dir);
 		state = node->state;
 		state._lastAnim = walkanim;
 		state._direction = dir;
diff --git a/engines/ultima/ultima8/world/actors/pathfinder.h b/engines/ultima/ultima8/world/actors/pathfinder.h
index 59a3df6e5b..d3d99ac1d0 100644
--- a/engines/ultima/ultima8/world/actors/pathfinder.h
+++ b/engines/ultima/ultima8/world/actors/pathfinder.h
@@ -24,7 +24,7 @@
 #define ULTIMA8_WORLD_ACTORS_PATHFINDER_H
 
 #include "ultima/shared/std/containers.h"
-#include "ultima/shared/std/containers.h"
+#include "ultima/ultima8/misc/direction.h"
 #include "ultima/ultima8/world/actors/animation.h"
 
 namespace Ultima {
@@ -34,12 +34,12 @@ class Actor;
 class Item;
 
 struct PathfindingState {
-	PathfindingState() : _x(0), _y(0), _z(0),  _direction(0),
+	PathfindingState() : _x(0), _y(0), _z(0),  _direction(dir_north),
 		_lastAnim(Animation::walk), _flipped(false),
 		_firstStep(true), _combat(false) {};
 	int32 _x, _y, _z;
 	Animation::Sequence _lastAnim;
-	uint32 _direction;
+	Direction _direction;
 	bool _flipped;
 	bool _firstStep;
 	bool _combat;
@@ -52,7 +52,7 @@ struct PathfindingState {
 
 struct PathfindingAction {
 	Animation::Sequence _action;
-	uint32 _direction;
+	Direction _direction;
 	uint32 _steps;
 };
 
diff --git a/engines/ultima/ultima8/world/actors/pathfinder_process.cpp b/engines/ultima/ultima8/world/actors/pathfinder_process.cpp
index 96e2876fac..1646a62fa6 100644
--- a/engines/ultima/ultima8/world/actors/pathfinder_process.cpp
+++ b/engines/ultima/ultima8/world/actors/pathfinder_process.cpp
@@ -268,7 +268,7 @@ bool PathfinderProcess::loadData(Common::ReadStream *rs, uint32 version) {
 	_path.resize(pathsize);
 	for (unsigned int i = 0; i < pathsize; ++i) {
 		_path[i]._action = static_cast<Animation::Sequence>(rs->readUint16LE());
-		_path[i]._direction = rs->readUint16LE();
+		_path[i]._direction = static_cast<Direction>(rs->readUint16LE());
 	}
 
 	return true;
diff --git a/engines/ultima/ultima8/world/actors/surrender_process.cpp b/engines/ultima/ultima8/world/actors/surrender_process.cpp
index d23f8f90f7..cfd2497440 100644
--- a/engines/ultima/ultima8/world/actors/surrender_process.cpp
+++ b/engines/ultima/ultima8/world/actors/surrender_process.cpp
@@ -21,6 +21,8 @@
  */
 
 #include "ultima/ultima8/misc/pent_include.h"
+#include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/audio/audio_process.h"
 #include "ultima/ultima8/world/actors/surrender_process.h"
 #include "ultima/ultima8/world/actors/actor.h"
@@ -76,20 +78,20 @@ void SurrenderProcess::run() {
 		return;
 	}
 
-	int16 curdir = a->getDir();
-	int16 direction = a->getDirToItemCentre(*main);
+	Direction curdir = a->getDir();
+	Direction direction = a->getDirToItemCentre(*main);
 
 	if (curdir != direction) {
-		int stepDelta;
 		Animation::Sequence turnanim;
-		if ((curdir - direction + 8) % 8 < 4) {
-			stepDelta = -1;
+		Direction nextdir;
+		if (Direction_GetShorterTurnDelta(curdir, direction) == -1) {
+			nextdir = Direction_OneLeft(curdir);
 			turnanim = Animation::lookLeft;
 		} else {
-			stepDelta = 1;
+			nextdir = Direction_OneRight(curdir);
 			turnanim = Animation::lookRight;
 		}
-		ProcId animpid = a->doAnim(turnanim, curdir + stepDelta);
+		ProcId animpid = a->doAnim(turnanim, nextdir);
 		waitFor(animpid);
 		return;
 	}
diff --git a/engines/ultima/ultima8/world/actors/targeted_anim_process.cpp b/engines/ultima/ultima8/world/actors/targeted_anim_process.cpp
index 74c3755d56..e4d1bccba9 100644
--- a/engines/ultima/ultima8/world/actors/targeted_anim_process.cpp
+++ b/engines/ultima/ultima8/world/actors/targeted_anim_process.cpp
@@ -35,7 +35,7 @@ TargetedAnimProcess::TargetedAnimProcess() : ActorAnimProcess(),
 		_x(0), _y(0), _z(0) {
 }
 
-TargetedAnimProcess::TargetedAnimProcess(Actor *actor_, Animation::Sequence action_, uint32 dir_, int32 coords[3]) : ActorAnimProcess(actor_, action_, dir_),
+TargetedAnimProcess::TargetedAnimProcess(Actor *actor_, Animation::Sequence action_, Direction dir_, int32 coords[3]) : ActorAnimProcess(actor_, action_, dir_),
 		_x(coords[0]), _y(coords[1]), _z(coords[2]) {
 }
 
diff --git a/engines/ultima/ultima8/world/actors/targeted_anim_process.h b/engines/ultima/ultima8/world/actors/targeted_anim_process.h
index fdd8f780d4..82500a9069 100644
--- a/engines/ultima/ultima8/world/actors/targeted_anim_process.h
+++ b/engines/ultima/ultima8/world/actors/targeted_anim_process.h
@@ -34,7 +34,7 @@ class TargetedAnimProcess : public ActorAnimProcess {
 public:
 	TargetedAnimProcess();
 	//! note: this probably needs some more parameters
-	TargetedAnimProcess(Actor *actor, Animation::Sequence action, uint32 dir,
+	TargetedAnimProcess(Actor *actor, Animation::Sequence action, Direction dir,
 	                    int32 coords[3]);
 
 	// p_dynamic_cast stuff
diff --git a/engines/ultima/ultima8/world/current_map.cpp b/engines/ultima/ultima8/world/current_map.cpp
index 7dc266a7f8..0cbe688be3 100644
--- a/engines/ultima/ultima8/world/current_map.cpp
+++ b/engines/ultima/ultima8/world/current_map.cpp
@@ -29,7 +29,6 @@
 #include "ultima/ultima8/world/actors/actor.h"
 #include "ultima/ultima8/world/world.h"
 #include "ultima/ultima8/world/world_point.h"
-#include "ultima/ultima8/misc/rect.h"
 #include "ultima/ultima8/world/container.h"
 #include "ultima/ultima8/usecode/uc_list.h"
 #include "ultima/ultima8/usecode/uc_machine.h"
@@ -42,6 +41,8 @@
 #include "ultima/ultima8/ultima8.h"
 #include "ultima/ultima8/gumps/game_map_gump.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
+#include "ultima/ultima8/misc/rect.h"
 #include "ultima/ultima8/world/get_object.h"
 
 namespace Ultima {
@@ -310,7 +311,7 @@ void CurrentMap::removeTargetItem(const Item *item) {
 }
 
 
-Item *CurrentMap::findBestTargetItem(int32 x, int32 y, uint8 dir) {
+Item *CurrentMap::findBestTargetItem(int32 x, int32 y, Direction dir) {
 	// "best" means:
 	// Shape info SI_OCCL
 	// isNPC
@@ -337,7 +338,7 @@ Item *CurrentMap::findBestTargetItem(int32 x, int32 y, uint8 dir) {
 
 		int32 ix, iy, iz;
 		item->getLocation(ix, iy, iz);
-		Direction itemdir = Get_WorldDirection(iy - y, ix - x);
+		Direction itemdir = Direction_GetWorldDir(iy - y, ix - x);
 		if (itemdir != dir)
 			continue;
 
diff --git a/engines/ultima/ultima8/world/current_map.h b/engines/ultima/ultima8/world/current_map.h
index 9b6350cbf3..d4ec9a82d4 100644
--- a/engines/ultima/ultima8/world/current_map.h
+++ b/engines/ultima/ultima8/world/current_map.h
@@ -25,6 +25,7 @@
 
 #include "ultima/shared/std/containers.h"
 #include "ultima/ultima8/usecode/intrinsics.h"
+#include "ultima/ultima8/misc/direction.h"
 
 namespace Ultima {
 namespace Ultima8 {
@@ -75,7 +76,7 @@ public:
 	//! Remove an item from the list of possible targets (in Crusader)
 	void removeTargetItem(const Item *item);
 	//! Find the best target item in the given direction
-	Item *findBestTargetItem(int32 x, int32 y, uint8 dir);
+	Item *findBestTargetItem(int32 x, int32 y, Direction dir);
 
 	//! Update the fast area for the cameras position
 	void updateFastArea(int32 from_x, int32 from_y, int32 from_z, int32 to_x, int32 to_y, int32 to_z);
diff --git a/engines/ultima/ultima8/world/fire_type.cpp b/engines/ultima/ultima8/world/fire_type.cpp
index e18bcd74c6..6e181b852f 100644
--- a/engines/ultima/ultima8/world/fire_type.cpp
+++ b/engines/ultima/ultima8/world/fire_type.cpp
@@ -196,7 +196,7 @@ void FireType::applySplashDamageAround(const Point3 &pt, int damage, const Item
 			if (splashrange)
 				splashitemdamage /= splashrange;
 		}
-		int splashdir = src->getDirToItemCentre(pt);
+		Direction splashdir = src->getDirToItemCentre(pt);
 		splashitem->receiveHit(0, splashdir, splashitemdamage, _typeNo);
 	}
 }
diff --git a/engines/ultima/ultima8/world/fireball_process.cpp b/engines/ultima/ultima8/world/fireball_process.cpp
index 8440053e19..ce4cdf56b3 100644
--- a/engines/ultima/ultima8/world/fireball_process.cpp
+++ b/engines/ultima/ultima8/world/fireball_process.cpp
@@ -28,6 +28,7 @@
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/world/item_factory.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/world/weapon_info.h"
 #include "ultima/ultima8/world/get_object.h"
 
@@ -99,7 +100,7 @@ void FireballProcess::run() {
 	dx = tx - x;
 	dy = ty - y;
 
-	int targetdir = item->getDirToItemCentre(*t);
+	Direction targetdir = item->getDirToItemCentre(*t);
 
 	if (_xSpeed == 0 && _ySpeed == 0 && dx / 64 == 0 && dy / 64 == 0) {
 		_xSpeed += 2 * x_fact[targetdir];
@@ -130,7 +131,7 @@ void FireballProcess::run() {
 	}
 
 	Item *tailitem = getItem(_tail[2]);
-	tailitem->setFrame(Get_WorldDirection(_ySpeed, _xSpeed));
+	tailitem->setFrame(Direction_GetWorldDir(_ySpeed, _xSpeed));
 	tailitem->move(x, y, z);
 
 	_tail[2] = _tail[1];
@@ -141,7 +142,7 @@ void FireballProcess::run() {
 		Actor *hit = getActor(hititem);
 		if (hit) {
 			// hit an actor: deal damage and explode
-			hit->receiveHit(0, 8 - targetdir, 5 + (getRandom() % 5),
+			hit->receiveHit(0, Direction_Invert(targetdir), 5 + (getRandom() % 5),
 			                WeaponInfo::DMG_FIRE);
 			terminate();
 			return;
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index b6c7a12ae1..4c9518482d 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -43,6 +43,7 @@
 #include "ultima/ultima8/world/fire_type.h"
 #include "ultima/ultima8/usecode/uc_stack.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/gumps/bark_gump.h"
 #include "ultima/ultima8/gumps/ask_gump.h"
 #include "ultima/ultima8/gumps/gump_notify_process.h"
@@ -621,21 +622,21 @@ bool Item::canExistAt(int32 x_, int32 y_, int32 z_, bool needsupport) const {
 	return valid && (!needsupport || support);
 }
 
-int Item::getDirToItemCentre(const Item &item2) const {
+Direction Item::getDirToItemCentre(const Item &item2) const {
 	int32 xv, yv, zv;
 	getCentre(xv, yv, zv);
 
 	int32 i2x, i2y, i2z;
 	item2.getCentre(i2x, i2y, i2z);
 
-	return Get_WorldDirection(i2y - yv, i2x - xv);
+	return Direction_GetWorldDir(i2y - yv, i2x - xv);
 }
 
-int Item::getDirToItemCentre(const Point3 &pt) const {
+Direction Item::getDirToItemCentre(const Point3 &pt) const {
 	int32 xv, yv, zv;
 	getCentre(xv, yv, zv);
 
-	return Get_WorldDirection(pt.y - yv, pt.x - xv);
+	return Direction_GetWorldDir(pt.y - yv, pt.x - xv);
 }
 
 
@@ -1152,7 +1153,7 @@ int32 Item::collideMove(int32 dx, int32 dy, int32 dz, bool teleport, bool force,
 	return 0;
 }
 
-uint16 Item::fireWeapon(int32 x, int32 y, int32 z, int dir, int firetype, char someflag) {
+uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, char someflag) {
 	int32 ix, iy, iz;
 	getLocation(ix, iy, iz);
 
@@ -1179,7 +1180,7 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, int dir, int firetype, char s
 		Item *block = getItem(blocker->getObjId());
 		Point3 blockpt;
 		block->getLocation(blockpt);
-		int damagedir = Get_WorldDirection(blockpt.y - iy, blockpt.x - ix);
+		Direction damagedir = Direction_GetWorldDir(blockpt.y - iy, blockpt.x - ix);
 		block->receiveHit(getObjId(), damagedir, damage, firetype);
 		int splashdamage = firetypedat->getRandomDamage();
 		firetypedat->applySplashDamageAround(blockpt, splashdamage, block, this);
@@ -1918,7 +1919,7 @@ void Item::explode(int explosion_type, bool destroy_item, bool cause_damage) {
 		if (getRange(*item, true) > 160) continue; // check vertical distance
 
 		item->getLocation(xv, yv, zv);
-		int dir = Get_WorldDirection(xv - xv, yv - yv); //!! CHECKME
+		Direction dir = Direction_GetWorldDir(xv - xv, yv - yv); //!! CHECKME
 		item->receiveHit(0, dir, 6 + (getRandom() % 6),
 		                 WeaponInfo::DMG_BLUNT | WeaponInfo::DMG_FIRE);
 	}
@@ -1933,14 +1934,14 @@ uint16 Item::getDamageType() const {
 	return 0;
 }
 
-void Item::receiveHit(uint16 other, int dir, int damage, uint16 type) {
+void Item::receiveHit(uint16 other, Direction dir, int damage, uint16 type) {
 	if (GAME_IS_U8)
 		receiveHitU8(other, dir, damage, type);
 	else
 		receiveHitCru(other, dir, damage, type);
 }
 
-void Item::receiveHitU8(uint16 other, int dir, int damage, uint16 type) {
+void Item::receiveHitU8(uint16 other, Direction dir, int damage, uint16 type) {
 	// first, check if the item has a 'gotHit' usecode event
 	if (callUsecodeEvent_gotHit(other, 0)) //!! TODO: what should the 0 be??
 		return;
@@ -1969,7 +1970,7 @@ void Item::receiveHitU8(uint16 other, int dir, int damage, uint16 type) {
 }
 
 
-void Item::receiveHitCru(uint16 other, int dir, int damage, uint16 type) {
+void Item::receiveHitCru(uint16 other, Direction dir, int damage, uint16 type) {
 	damage = scaleReceivedDamageCru(damage, type);
 	const ShapeInfo *shapeInfo = getShapeInfo();
 	if (!shapeInfo)
@@ -3275,7 +3276,7 @@ uint32 Item::I_getDirToCoords(const uint8 *args, unsigned int /*argsize*/) {
 	int32 ix, iy, iz;
 	item->getLocationAbsolute(ix, iy, iz);
 
-	uint32 retval = static_cast<uint32>(Get_WorldDirection(y - iy, x - ix));
+	uint32 retval = static_cast<uint32>(Direction_GetWorldDir(y - iy, x - ix));
 	if (GAME_IS_CRUSADER)
 		retval *= 2;
 	return retval;
@@ -3295,7 +3296,7 @@ uint32 Item::I_getDirFromCoords(const uint8 *args, unsigned int /*argsize*/) {
 	int32 ix, iy, iz;
 	item->getLocationAbsolute(ix, iy, iz);
 
-	uint32 retval = static_cast<uint32>(Get_WorldDirection(iy - y, ix - x));
+	uint32 retval = static_cast<uint32>(Direction_GetWorldDir(iy - y, ix - x));
 	if (GAME_IS_CRUSADER)
 		retval *= 2;
 	return retval;
@@ -3313,7 +3314,7 @@ uint32 Item::I_getDirToItem(const uint8 *args, unsigned int /*argsize*/) {
 	int32 i2x, i2y, i2z;
 	item2->getLocationAbsolute(i2x, i2y, i2z);
 
-	uint32 retval = static_cast<uint32>(Get_WorldDirection(i2y - iy, i2x - ix));
+	uint32 retval = static_cast<uint32>(Direction_GetWorldDir(i2y - iy, i2x - ix));
 	if (GAME_IS_CRUSADER)
 		retval *= 2;
 	return retval;
@@ -3331,7 +3332,7 @@ uint32 Item::I_getDirFromItem(const uint8 *args, unsigned int /*argsize*/) {
 	int32 i2x, i2y, i2z;
 	item2->getLocationAbsolute(i2x, i2y, i2z);
 
-	uint32 retval = static_cast<uint32>((Get_WorldDirection(i2y - iy, i2x - ix) + 4) % 8);
+	uint32 retval = static_cast<uint32>(Direction_Invert(Direction_GetWorldDir(i2y - iy, i2x - ix)));
 	if (GAME_IS_CRUSADER)
 		retval *= 2;
 	return retval;
@@ -3347,7 +3348,7 @@ uint32 Item::I_getDirFromTo16(const uint8 *args, unsigned int /*argsize*/) {
 		return 16;
 
 	// TODO: Implement proper 16 directions here.
-	uint32 retval = static_cast<uint32>(Get_WorldDirection(y2 - y1, x2 - x1));
+	uint32 retval = static_cast<uint32>(Direction_GetWorldDir(y2 - y1, x2 - x1));
 	return retval * 2;
 }
 
@@ -3360,7 +3361,7 @@ uint32 Item::I_getClosestDirectionInRange(const uint8 *args, unsigned int /*args
 	ARG_UINT16(mindir);
 	ARG_UINT16(maxdir);
 
-	return Get_WorldDirectionClosestInRange(y2 - y1, x2 - x1, ndirs, mindir, maxdir);
+	return Direction_GetWorldDirInRange(y2 - y1, x2 - x1, ndirs, mindir, maxdir);
 }
 
 uint32 Item::I_hurl(const uint8 *args, unsigned int /*argsize*/) {
@@ -3489,7 +3490,7 @@ uint32 Item::I_receiveHit(const uint8 *args, unsigned int /*argsize*/) {
 	ARG_UINT16(type); // hit type
 	if (!item) return 0;
 
-	item->receiveHit(other, dir, damage, type);
+	item->receiveHit(other, static_cast<Direction>(dir), damage, type);
 
 	return 0;
 }
@@ -3628,7 +3629,7 @@ uint32 Item::I_fireWeapon(const uint8 *args, unsigned int /*argsize*/) {
 
 	if (!item) return 0;
 
-	return item->fireWeapon(x * 2, y * 2, z, dir, firetype, unkflag);
+	return item->fireWeapon(x * 2, y * 2, z, static_cast<Direction>(dir), firetype, unkflag);
 }
 
 } // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index eb65793009..c4467c6932 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -29,6 +29,7 @@
 #include "ultima/ultima8/usecode/intrinsics.h"
 #include "ultima/ultima8/misc/box.h"
 #include "ultima/ultima8/misc/point3.h"
+#include "ultima/ultima8/misc/direction.h"
 
 namespace Ultima {
 namespace Ultima8 {
@@ -292,10 +293,10 @@ public:
 
 	//! Get direction from centre to another item's centre.
 	//! Undefined if either item is contained or equipped.
-	int getDirToItemCentre(const Item &item2) const;
+	Direction getDirToItemCentre(const Item &item2) const;
 
 	//! Same as above, but from a fixed point.
-	int getDirToItemCentre(const Point3 &pt) const;
+	Direction getDirToItemCentre(const Point3 &pt) const;
 
 	//! get 'distance' to other item. This is the maximum of the differences
 	//! between the x, y (and possibly z) coordinates of the items.
@@ -384,10 +385,10 @@ public:
 	//! \param dir The direction the hit is coming from (or inverse? CHECKME!)
 	//! \param damage The force of the hit. Zero for default
 	//! \param type The type of damage done. Zero for default
-	virtual void receiveHit(ObjId other, int dir, int damage, uint16 type);
+	virtual void receiveHit(ObjId other, Direction dir, int damage, uint16 type);
 
 	//! fire the given weapon type in the given direction from location x, y, z.
-	uint16 fireWeapon(int32 x, int32 y, int32 z, int dir, int firetype, char someflag);
+	uint16 fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, char someflag);
 
 	//! get damage points, used in Crusader for item damage.
 	uint8 getDamagePoints() const {
@@ -643,10 +644,10 @@ private:
 	void animateItem();
 
 	//! The U8 version of receiveHit
-	void receiveHitU8(ObjId other, int dir, int damage, uint16 type);
+	void receiveHitU8(ObjId other, Direction dir, int damage, uint16 type);
 
 	//! The Crusader version of receiveHit
-	void receiveHitCru(ObjId other, int dir, int damage, uint16 type);
+	void receiveHitCru(ObjId other, Direction dir, int damage, uint16 type);
 
 public:
 	enum statusflags {
diff --git a/engines/ultima/ultima8/world/super_sprite_process.cpp b/engines/ultima/ultima8/world/super_sprite_process.cpp
index ae49b3ef5b..564da41698 100644
--- a/engines/ultima/ultima8/world/super_sprite_process.cpp
+++ b/engines/ultima/ultima8/world/super_sprite_process.cpp
@@ -29,6 +29,7 @@
 #include "ultima/ultima8/kernel/core_app.h"
 #include "ultima/ultima8/kernel/delay_process.h"
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/usecode/uc_list.h"
 #include "ultima/ultima8/world/loop_script.h"
 #include "ultima/ultima8/world/current_map.h"
@@ -199,7 +200,7 @@ void SuperSpriteProcess::run() {
 
 		if (_fireType == 9 && !_expired) {
 			if (_nowpt.x != newpt.x || _nowpt.y != newpt.y) {
-				uint8 dir = Get_WorldDirection(_nowpt.y - newpt.y, _nowpt.x - newpt.x);
+				Direction dir = Direction_GetWorldDir(_nowpt.y - newpt.y, _nowpt.x - newpt.x);
 				Item *item;
 				if (_itemNum == 0) {
 					item = getItem(_spriteNo);
@@ -317,7 +318,7 @@ void SuperSpriteProcess::hitAndFinish() {
 		// it should work? See disasm 1138:1384, lines 142 ~ 172
 		// There is some random factor added for non-actor items
 		// which needs checking
-		int dir = Get_WorldDirection(iy - _nowpt.y, ix - _nowpt.x);
+		Direction dir = Direction_GetWorldDir(iy - _nowpt.y, ix - _nowpt.x);
 		item->receiveHit(_itemNum, dir, _damage, _fireType);
 	}
 	makeBulletSplash(pt);
diff --git a/engines/ultima/ultima8/world/target_reticle_process.cpp b/engines/ultima/ultima8/world/target_reticle_process.cpp
index 3badaf9bd2..f60a8ee1bc 100644
--- a/engines/ultima/ultima8/world/target_reticle_process.cpp
+++ b/engines/ultima/ultima8/world/target_reticle_process.cpp
@@ -42,7 +42,7 @@ TargetReticleProcess *TargetReticleProcess::_instance = nullptr;
 DEFINE_RUNTIME_CLASSTYPE_CODE(TargetReticleProcess)
 
 TargetReticleProcess::TargetReticleProcess() : Process(), _reticleEnabled(true),
-		_lastUpdate(0), _reticleSpriteProcess(0), _lastTargetDir(0x10), _lastTargetItem(0) {
+		_lastUpdate(0), _reticleSpriteProcess(0), _lastTargetDir(dir_current), _lastTargetItem(0) {
 	_instance = this;
 }
 
@@ -83,7 +83,7 @@ bool TargetReticleProcess::findTargetItem() {
 	if (!mainactor || !currentmap)
 		return false;
 
-	int dir = mainactor->getDir();
+	Direction dir = mainactor->getDir();
 
 	int32 x, y, z;
 	mainactor->getCentre(x, y, z);
@@ -171,7 +171,7 @@ void TargetReticleProcess::clearSprite() {
 		}
 	}
 	_lastTargetItem = 0;
-	_lastTargetDir = 0x10;
+	_lastTargetDir = dir_current;
 }
 
 void TargetReticleProcess::toggle() {
diff --git a/engines/ultima/ultima8/world/target_reticle_process.h b/engines/ultima/ultima8/world/target_reticle_process.h
index 6838579eb1..d16942b282 100644
--- a/engines/ultima/ultima8/world/target_reticle_process.h
+++ b/engines/ultima/ultima8/world/target_reticle_process.h
@@ -74,7 +74,7 @@ private:
     bool _reticleEnabled;
 	int32 _lastUpdate;
 	uint16 _reticleSpriteProcess;
-	uint16 _lastTargetDir;
+	Direction _lastTargetDir;
 	uint16 _lastTargetItem;
 
 	static TargetReticleProcess *_instance;
diff --git a/engines/ultima/ultima8/world/world.cpp b/engines/ultima/ultima8/world/world.cpp
index 537005a18b..99e1a88675 100644
--- a/engines/ultima/ultima8/world/world.cpp
+++ b/engines/ultima/ultima8/world/world.cpp
@@ -280,7 +280,7 @@ void World::loadItemCachNPCData(Common::SeekableReadStream *itemcach, Common::Se
 		actor->setDex(npcds->readByte()); // 0x01: dexterity
 		actor->setInt(npcds->readByte()); // 0x02: intelligence
 		actor->setHP(npcds->readByte());  // 0x03: hitpoints
-		actor->setDir(npcds->readByte()); // 0x04: direction
+		actor->setDir(static_cast<Direction>(npcds->readByte())); // 0x04: direction
 		uint16 la = npcds->readUint16LE();    // 0x05,0x06: last anim
 		actor->setLastAnim(static_cast<Animation::Sequence>(la));
 		npcds->skip(1); // 0x07: high byte of framenum


Commit: 52328fc334a0f1adedee7c453a516fe013cc3e6c
    https://github.com/scummvm/scummvm/commit/52328fc334a0f1adedee7c453a516fe013cc3e6c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-07-28T14:03:37+09:00

Commit Message:
ULTIMA8: More encapsulation of directions, less casts

Changed paths:
    engines/ultima/ultima8/misc/direction_util.h
    engines/ultima/ultima8/world/actors/actor.cpp
    engines/ultima/ultima8/world/item.cpp
    engines/ultima/ultima8/world/world.cpp


diff --git a/engines/ultima/ultima8/misc/direction_util.h b/engines/ultima/ultima8/misc/direction_util.h
index 994c7683d3..102f33fa8d 100644
--- a/engines/ultima/ultima8/misc/direction_util.h
+++ b/engines/ultima/ultima8/misc/direction_util.h
@@ -24,6 +24,7 @@
 #define ULTIMA8_MISC_DIRECTIONUTIL_H
 
 #include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/ultima8.h"
 
 namespace Ultima {
 namespace Ultima8 {
@@ -121,9 +122,19 @@ inline Direction Direction_GetWorldDirInRange(int deltay, int deltax, uint16 ndi
 }
 
 inline Direction Direction_Invert(Direction dir) {
-	// TODO: support 16 dirs here.
 	assert(dir != dir_current);
-	return static_cast<Direction>((static_cast<int>(dir) + 4) % 8);
+	// TODO: Will need to add more cases for 16 dir support.
+	switch (dir) {
+		case dir_north:		return dir_south;
+		case dir_northeast:	return dir_southwest;
+		case dir_east:		return dir_west;
+		case dir_southeast:	return dir_northwest;
+		case dir_south:		return dir_north;
+		case dir_southwest:	return dir_northeast;
+		case dir_west:		return dir_east;
+		case dir_northwest:	return dir_southeast;
+		default:			return dir_north;
+	}
 }
 
 //! Return the direction one left (aka counter-clockwise) of the input
@@ -139,8 +150,7 @@ inline Direction Direction_OneRight(Direction dir) {
 }
 
 inline Direction Direction_TurnByDelta(Direction dir, int delta) {
-	// TODO: support 16 dirs here.
-	return static_cast<Direction>((static_cast<int>(dir) + delta + 8) % 8);
+	return delta == 1 ? Direction_OneRight(dir) : Direction_OneLeft(dir);
 }
 
 //! Get a turn delta (-1 for left, +1 for right) to turn the fastest
@@ -152,6 +162,24 @@ inline int Direction_GetShorterTurnDelta(Direction from, Direction to) {
 	return 1;
 }
 
+inline int Direction_ToUsecodeDir(Direction dir) {
+	// TODO: Will need changing when we support 16 dirs
+	if (GAME_IS_U8) {
+		return static_cast<int32>(dir);
+	} else {
+		return static_cast<int32>(dir) * 2;
+	}
+}
+
+inline Direction Direction_FromUsecodeDir(int dir) {
+	// TODO: Will need changing when we support 16 dirs
+	if (GAME_IS_U8) {
+		return static_cast<Direction>(dir);
+	} else {
+		return static_cast<Direction>(dir / 2);
+	}
+}
+
 } // End of namespace Ultima8
 } // End of namespace Ultima
 
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 55aee4e6ee..10c7a43fb0 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -1467,7 +1467,7 @@ uint32 Actor::I_doAnim(const uint8 *args, unsigned int /*argsize*/) {
 
 	if (!actor) return 0;
 
-	return actor->doAnim(static_cast<Animation::Sequence>(anim), static_cast<Direction>(dir));
+	return actor->doAnim(static_cast<Animation::Sequence>(anim), Direction_FromUsecodeDir(dir));
 }
 
 uint32 Actor::I_getDir(const uint8 *args, unsigned int /*argsize*/) {
@@ -1948,7 +1948,7 @@ uint32 Actor::I_createActorCru(const uint8 *args, unsigned int /*argsize*/) {
 		return 0;
 	}
 
-	newactor->setDir(static_cast<Direction>(dir));
+	newactor->setDir(Direction_FromUsecodeDir(dir));
 
 	int32 x, y, z;
 	item->getLocation(x, y, z);
@@ -2137,8 +2137,7 @@ uint32 Actor::I_turnToward(const uint8 *args, unsigned int /*argsize*/) {
 	ARG_UINT16(dir);
 	ARG_UINT16(unk);
 
-	// FIXME: This is hacked to be the 8 dir version..
-	return actor->turnTowardDir(static_cast<Direction>(dir / 2));
+	return actor->turnTowardDir(Direction_FromUsecodeDir(dir));
 }
 
 
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 4c9518482d..22109dfb79 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -3276,10 +3276,7 @@ uint32 Item::I_getDirToCoords(const uint8 *args, unsigned int /*argsize*/) {
 	int32 ix, iy, iz;
 	item->getLocationAbsolute(ix, iy, iz);
 
-	uint32 retval = static_cast<uint32>(Direction_GetWorldDir(y - iy, x - ix));
-	if (GAME_IS_CRUSADER)
-		retval *= 2;
-	return retval;
+	return Direction_ToUsecodeDir(Direction_GetWorldDir(y - iy, x - ix));
 }
 
 uint32 Item::I_getDirFromCoords(const uint8 *args, unsigned int /*argsize*/) {
@@ -3296,10 +3293,7 @@ uint32 Item::I_getDirFromCoords(const uint8 *args, unsigned int /*argsize*/) {
 	int32 ix, iy, iz;
 	item->getLocationAbsolute(ix, iy, iz);
 
-	uint32 retval = static_cast<uint32>(Direction_GetWorldDir(iy - y, ix - x));
-	if (GAME_IS_CRUSADER)
-		retval *= 2;
-	return retval;
+	return Direction_ToUsecodeDir(Direction_GetWorldDir(iy - y, ix - x));
 }
 
 uint32 Item::I_getDirToItem(const uint8 *args, unsigned int /*argsize*/) {
@@ -3314,10 +3308,7 @@ uint32 Item::I_getDirToItem(const uint8 *args, unsigned int /*argsize*/) {
 	int32 i2x, i2y, i2z;
 	item2->getLocationAbsolute(i2x, i2y, i2z);
 
-	uint32 retval = static_cast<uint32>(Direction_GetWorldDir(i2y - iy, i2x - ix));
-	if (GAME_IS_CRUSADER)
-		retval *= 2;
-	return retval;
+	return Direction_ToUsecodeDir(Direction_GetWorldDir(i2y - iy, i2x - ix));
 }
 
 uint32 Item::I_getDirFromItem(const uint8 *args, unsigned int /*argsize*/) {
@@ -3332,10 +3323,7 @@ uint32 Item::I_getDirFromItem(const uint8 *args, unsigned int /*argsize*/) {
 	int32 i2x, i2y, i2z;
 	item2->getLocationAbsolute(i2x, i2y, i2z);
 
-	uint32 retval = static_cast<uint32>(Direction_Invert(Direction_GetWorldDir(i2y - iy, i2x - ix)));
-	if (GAME_IS_CRUSADER)
-		retval *= 2;
-	return retval;
+	return Direction_ToUsecodeDir(Direction_Invert(Direction_GetWorldDir(i2y - iy, i2x - ix)));
 }
 
 uint32 Item::I_getDirFromTo16(const uint8 *args, unsigned int /*argsize*/) {
@@ -3347,9 +3335,7 @@ uint32 Item::I_getDirFromTo16(const uint8 *args, unsigned int /*argsize*/) {
 	if (x1 == x2 && y1 == y2)
 		return 16;
 
-	// TODO: Implement proper 16 directions here.
-	uint32 retval = static_cast<uint32>(Direction_GetWorldDir(y2 - y1, x2 - x1));
-	return retval * 2;
+	return Direction_ToUsecodeDir(Direction_GetWorldDir(y2 - y1, x2 - x1));
 }
 
 uint32 Item::I_getClosestDirectionInRange(const uint8 *args, unsigned int /*argsize*/) {
@@ -3361,7 +3347,7 @@ uint32 Item::I_getClosestDirectionInRange(const uint8 *args, unsigned int /*args
 	ARG_UINT16(mindir);
 	ARG_UINT16(maxdir);
 
-	return Direction_GetWorldDirInRange(y2 - y1, x2 - x1, ndirs, mindir, maxdir);
+	return Direction_ToUsecodeDir(Direction_GetWorldDirInRange(y2 - y1, x2 - x1, ndirs, mindir, maxdir));
 }
 
 uint32 Item::I_hurl(const uint8 *args, unsigned int /*argsize*/) {
@@ -3490,7 +3476,7 @@ uint32 Item::I_receiveHit(const uint8 *args, unsigned int /*argsize*/) {
 	ARG_UINT16(type); // hit type
 	if (!item) return 0;
 
-	item->receiveHit(other, static_cast<Direction>(dir), damage, type);
+	item->receiveHit(other, Direction_FromUsecodeDir(dir), damage, type);
 
 	return 0;
 }
@@ -3629,7 +3615,7 @@ uint32 Item::I_fireWeapon(const uint8 *args, unsigned int /*argsize*/) {
 
 	if (!item) return 0;
 
-	return item->fireWeapon(x * 2, y * 2, z, static_cast<Direction>(dir), firetype, unkflag);
+	return item->fireWeapon(x * 2, y * 2, z, Direction_FromUsecodeDir(dir), firetype, unkflag);
 }
 
 } // End of namespace Ultima8
diff --git a/engines/ultima/ultima8/world/world.cpp b/engines/ultima/ultima8/world/world.cpp
index 99e1a88675..4ecfb8b8f0 100644
--- a/engines/ultima/ultima8/world/world.cpp
+++ b/engines/ultima/ultima8/world/world.cpp
@@ -32,6 +32,7 @@
 #include "ultima/ultima8/world/loop_script.h"
 #include "ultima/ultima8/usecode/uc_list.h"
 #include "ultima/ultima8/misc/id_man.h"
+#include "ultima/ultima8/misc/direction_util.h"
 #include "ultima/ultima8/games/game_data.h"
 #include "ultima/ultima8/kernel/kernel.h"
 #include "ultima/ultima8/kernel/object_manager.h"
@@ -280,7 +281,7 @@ void World::loadItemCachNPCData(Common::SeekableReadStream *itemcach, Common::Se
 		actor->setDex(npcds->readByte()); // 0x01: dexterity
 		actor->setInt(npcds->readByte()); // 0x02: intelligence
 		actor->setHP(npcds->readByte());  // 0x03: hitpoints
-		actor->setDir(static_cast<Direction>(npcds->readByte())); // 0x04: direction
+		actor->setDir(Direction_FromUsecodeDir(npcds->readByte())); // 0x04: direction
 		uint16 la = npcds->readUint16LE();    // 0x05,0x06: last anim
 		actor->setLastAnim(static_cast<Animation::Sequence>(la));
 		npcds->skip(1); // 0x07: high byte of framenum




More information about the Scummvm-git-logs mailing list