[Scummvm-git-logs] scummvm master -> 404371365a81262f9af8796b80301f6ed8b3c5ab
mduggan
mgithub at guarana.org
Thu Dec 24 10:30:07 UTC 2020
This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
2d7d09bd2c ULTIMA8: Return sprite pid from Cruader fireWeapon to better match original.
31907819a0 ULTIMA8: Split Crusader movement to separate class
df46296f02 ULTIMA8: Add 16 dir support for Direction_Get
ebae8ca44b ULTIMA8: Fix crusader firing in a few ways:
bf4f61b356 ULTIMA8: Crusader: Fix robot death and make absolute anims a bit cleaner.
51c8f66d97 ULTIMA8: Provide quick helper functions for mouse
404371365a ULTIMA8: Reduce code duplication in mover procs
Commit: 2d7d09bd2cc8785a0a2aaf2e1d262c2eefaf95c4
https://github.com/scummvm/scummvm/commit/2d7d09bd2cc8785a0a2aaf2e1d262c2eefaf95c4
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-12-24T14:00:15+09:00
Commit Message:
ULTIMA8: Return sprite pid from Cruader fireWeapon to better match original.
Changed paths:
engines/ultima/ultima8/world/item.cpp
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 74962a590f..ccda99b3cd 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1216,7 +1216,7 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
// is clean for both Item and Actor.
const Actor *thisactor = dynamic_cast<Actor *>(this);
if (thisactor) {
- // TODO: Get damage for active inventory item, and do something with
+ // TODO: Get damage for active inventory item, and dirmode of last
// animation here (lines 185~208 of disasm)
}
@@ -1225,6 +1225,7 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
if (this != getControlledActor()) {
target = getControlledActor();
} else {
+ // TODO: this should be dirmode of last animation (above)
target = currentmap->findBestTargetItem(ix, iy, dir, dirmode_8dirs);
}
}
@@ -1263,6 +1264,7 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
// handle differently.
int numshots = firetypedat->getNumShots();
+ uint16 spriteprocpid = 0;
for (int i = 0; i < numshots; i++) {
SuperSpriteProcess *ssp;
CrosshairProcess *chp = CrosshairProcess::get_instance();
@@ -1292,10 +1294,10 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
ix, iy, iz, ssx, ssy, ssz, firetype,
damage, _objId, targetid, someflag);
Kernel::get_instance()->addProcess(ssp);
+ spriteprocpid = ssp->getPid();
}
+ return spriteprocpid;
}
-
- return 0;
}
uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff) {
Commit: 31907819a0f0f8fc66c7e5736e2c71d6f39a391a
https://github.com/scummvm/scummvm/commit/31907819a0f0f8fc66c7e5736e2c71d6f39a391a
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-12-24T14:00:15+09:00
Commit Message:
ULTIMA8: Split Crusader movement to separate class
Currently there is a lot of duplicated code, but this allows the Crusader
movement to be adjusted a lot to match the original without breaking U8
movement.
Changed paths:
A engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
A engines/ultima/ultima8/world/actors/cru_avatar_mover_process.h
A engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
A engines/ultima/ultima8/world/actors/u8_avatar_mover_process.h
engines/ultima/module.mk
engines/ultima/ultima8/misc/direction_util.h
engines/ultima/ultima8/ultima8.cpp
engines/ultima/ultima8/world/actors/animation.cpp
engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
engines/ultima/ultima8/world/actors/avatar_mover_process.h
diff --git a/engines/ultima/module.mk b/engines/ultima/module.mk
index 0b0a1eeb37..ac343490e0 100644
--- a/engines/ultima/module.mk
+++ b/engines/ultima/module.mk
@@ -566,6 +566,7 @@ MODULE_OBJS := \
ultima8/world/actors/avatar_mover_process.o \
ultima8/world/actors/battery_charger_process.o \
ultima8/world/actors/clear_feign_death_process.o \
+ ultima8/world/actors/cru_avatar_mover_process.o \
ultima8/world/actors/cru_healer_process.o \
ultima8/world/actors/combat_dat.o \
ultima8/world/actors/combat_process.o \
@@ -583,7 +584,8 @@ MODULE_OBJS := \
ultima8/world/actors/scheduler_process.o \
ultima8/world/actors/surrender_process.o \
ultima8/world/actors/targeted_anim_process.o \
- ultima8/world/actors/teleport_to_egg_process.o
+ ultima8/world/actors/teleport_to_egg_process.o \
+ ultima8/world/actors/u8_avatar_mover_process.o
# This module can be built as a plugin
ifeq ($(ENABLE_ULTIMA), DYNAMIC_PLUGIN)
diff --git a/engines/ultima/ultima8/misc/direction_util.h b/engines/ultima/ultima8/misc/direction_util.h
index 927f9dab21..75fd8f0875 100644
--- a/engines/ultima/ultima8/misc/direction_util.h
+++ b/engines/ultima/ultima8/misc/direction_util.h
@@ -37,7 +37,7 @@ namespace Ultima8 {
inline int Direction_XFactor(Direction dir) {
static const int _x_fact[] = { 0, +1, +1, +1, 0, -1, -1, -1 };
//static const int _x_fact16[] = { 0, +1, +2, +2, +2, +2, +2, +1, 0, -1, -2, -2, -2, -2, -2, -1 };
- // TODO: AnimPrimativeProcess uses the below table.. what's the other table for?
+ // TODO: AnimPrimitiveProcess uses the below table.. what's the other table for?
// (same for y)
static const int _x_fact16[] = { 0, +1, +1, +2, +1, +2, +1, +1, 0, -1, -1, -2, -1, -2, -1, -1 };
diff --git a/engines/ultima/ultima8/ultima8.cpp b/engines/ultima/ultima8/ultima8.cpp
index e71ad528d9..913c748d3c 100644
--- a/engines/ultima/ultima8/ultima8.cpp
+++ b/engines/ultima/ultima8/ultima8.cpp
@@ -100,7 +100,8 @@
#include "ultima/ultima8/world/snap_process.h"
#include "ultima/ultima8/world/crosshair_process.h"
#include "ultima/ultima8/world/actors/pathfinder_process.h"
-#include "ultima/ultima8/world/actors/avatar_mover_process.h"
+#include "ultima/ultima8/world/actors/u8_avatar_mover_process.h"
+#include "ultima/ultima8/world/actors/cru_avatar_mover_process.h"
#include "ultima/ultima8/world/actors/resurrection_process.h"
#include "ultima/ultima8/world/actors/clear_feign_death_process.h"
#include "ultima/ultima8/world/actors/loiter_process.h"
@@ -237,8 +238,12 @@ bool Ultima8Engine::startup() {
ProcessLoader<ActorAnimProcess>::load);
_kernel->addProcessLoader("TargetedAnimProcess",
ProcessLoader<TargetedAnimProcess>::load);
- _kernel->addProcessLoader("AvatarMoverProcess",
- ProcessLoader<AvatarMoverProcess>::load);
+ _kernel->addProcessLoader("AvatarMoverProcess", // parent class for backward compatibility
+ ProcessLoader<U8AvatarMoverProcess>::load);
+ _kernel->addProcessLoader("U8AvatarMoverProcess",
+ ProcessLoader<U8AvatarMoverProcess>::load);
+ _kernel->addProcessLoader("CruAvatarMoverProcess",
+ ProcessLoader<CruAvatarMoverProcess>::load);
_kernel->addProcessLoader("QuickAvatarMoverProcess",
ProcessLoader<QuickAvatarMoverProcess>::load);
_kernel->addProcessLoader("PathfinderProcess",
@@ -1142,7 +1147,10 @@ bool Ultima8Engine::newGame(int saveSlot) {
CameraProcess::SetCameraProcess(new CameraProcess(1)); // Follow Avatar
debugN(MM_INFO, "Create persistent Processes...\n");
- _avatarMoverProcess = new AvatarMoverProcess();
+ if (GAME_IS_U8)
+ _avatarMoverProcess = new U8AvatarMoverProcess();
+ else
+ _avatarMoverProcess = new CruAvatarMoverProcess();
_kernel->addProcess(_avatarMoverProcess);
_kernel->addProcess(new HealProcess());
diff --git a/engines/ultima/ultima8/world/actors/animation.cpp b/engines/ultima/ultima8/world/actors/animation.cpp
index d8d8776d63..20e4575009 100644
--- a/engines/ultima/ultima8/world/actors/animation.cpp
+++ b/engines/ultima/ultima8/world/actors/animation.cpp
@@ -37,6 +37,7 @@ bool isCombatAnim(const Sequence anim) {
case kick:
case startBlock:
case stopBlock:
+ case fire2:
return true;
default:
return false;
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
index dd0c3cabb2..195fa8d048 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
@@ -40,12 +40,8 @@
namespace Ultima {
namespace Ultima8 {
-// p_dynamic_cast stuff
-DEFINE_RUNTIME_CLASSTYPE_CODE(AvatarMoverProcess)
-
AvatarMoverProcess::AvatarMoverProcess() : Process(),
_lastFrame(0), _lastAttack(0), _idleTime(0),
- _lastHeadShakeAnim(Animation::lookLeft),
_movementFlags(0) {
_type = 1; // CONSTANT! (type 1 = persistent)
}
@@ -63,15 +59,13 @@ void AvatarMoverProcess::run() {
return;
_lastFrame = framenum;
-
- MainActor *avatar = getMainActor();
-
// busy, so don't move
if (kernel->getNumProcesses(1, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE) > 0) {
_idleTime = 0;
return;
}
+ MainActor *avatar = getMainActor();
if (avatar->getLastAnim() == Animation::hang) {
handleHangingMode();
@@ -91,772 +85,24 @@ void AvatarMoverProcess::run() {
handleNormalMode();
}
-void AvatarMoverProcess::handleHangingMode() {
- bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
-
- _idleTime = 0;
-
- if (stasis)
- return;
-
- bool m0clicked = false;
- //bool m1clicked = false;
- if (!_mouseButton[0].isState(MBS_HANDLED) &&
- !_mouseButton[0].curWithinDblClkTimeout()) {
- m0clicked = true;
- _mouseButton[0].setState(MBS_HANDLED);
- }
- if (!_mouseButton[1].isState(MBS_HANDLED) &&
- !_mouseButton[1].curWithinDblClkTimeout()) {
- //m1clicked = true;
- _mouseButton[1].setState(MBS_HANDLED);
- }
-
- // if left mouse is down, try to climb up
-
- if (_mouseButton[0].isState(MBS_DOWN) &&
- (!_mouseButton[0].isState(MBS_HANDLED) || m0clicked)) {
- _mouseButton[0].setState(MBS_HANDLED);
- _mouseButton[0]._lastDown = 0;
- MainActor *avatar = getMainActor();
-
- if (avatar->tryAnim(Animation::climb40, dir_current) == Animation::SUCCESS) {
- avatar->ensureGravityProcess()->terminate();
- waitFor(avatar->doAnim(Animation::climb40, dir_current));
- }
- }
-}
-
-void AvatarMoverProcess::handleCombatMode() {
- Mouse *mouse = Mouse::get_instance();
- MainActor *avatar = getMainActor();
- Animation::Sequence lastanim = avatar->getLastAnim();
- Direction direction = avatar->getDir();
- bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
-
- int32 mx, my;
- mouse->getMouseCoords(mx, my);
- unsigned int mouselength = mouse->getMouseLength(mx, my);
-
- Direction mousedir = mouse->getMouseDirectionWorld(mx, my);
-
- // never idle when in combat
- _idleTime = 0;
-
- // If Avatar has fallen down, stand up.
- if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
- if (!stasis)
- waitFor(avatar->doAnim(Animation::standUp, mousedir));
- return;
- }
-
- // if we were blocking, and no longer holding the mouse, stop
- if (lastanim == Animation::startBlock &&
- !_mouseButton[0].isState(MBS_DOWN)) {
- waitFor(avatar->doAnim(Animation::stopBlock, direction));
- return;
- }
-
- // can't do any new actions if in stasis
- if (stasis)
- return;
-
- bool m0clicked = false;
- bool m1clicked = false;
-
- if (!_mouseButton[0].isState(MBS_HANDLED) &&
- !_mouseButton[0].curWithinDblClkTimeout()) {
- m0clicked = true;
- _mouseButton[0].setState(MBS_HANDLED);
- }
-
- if (!_mouseButton[1].isState(MBS_HANDLED) &&
- !_mouseButton[1].curWithinDblClkTimeout()) {
- m1clicked = true;
- _mouseButton[1].setState(MBS_HANDLED);
- }
-
- if (!_mouseButton[0].isState(MBS_DOWN)) {
- clearMovementFlag(MOVE_MOUSE_DIRECTION);
- }
-
- if (_mouseButton[0].isState(MBS_DOWN) &&
- _mouseButton[0].isState(MBS_HANDLED) && _mouseButton[0]._lastDown > 0) {
- // left click-and-hold = block
- if (lastanim == Animation::startBlock)
- return;
-
-// pout << "AvatarMover: combat block" << Std::endl;
-
- if (checkTurn(mousedir, false))
- return;
-
- waitFor(avatar->doAnim(Animation::startBlock, mousedir));
- return;
- }
-
- if (_mouseButton[0].isUnhandledDoubleClick()) {
- _mouseButton[0].setState(MBS_HANDLED);
- _mouseButton[0]._lastDown = 0;
-
- if (canAttack()) {
- // double left click = attack
-// pout << "AvatarMover: combat attack" << Std::endl;
-
- if (checkTurn(mousedir, true))
- return;
-
- waitFor(avatar->doAnim(Animation::attack, mousedir));
- _lastAttack = _lastFrame;
-
- // attacking gives str/dex
- avatar->accumulateStr(1 + (getRandom() % 2));
- avatar->accumulateDex(2 + (getRandom() % 2));
- }
-
- return;
- }
-
- if (_mouseButton[1].isUnhandledDoubleClick()) {
- _mouseButton[1].setState(MBS_HANDLED);
- _mouseButton[1]._lastDown = 0;
-
- Gump *desktopgump = Ultima8Engine::get_instance()->getDesktopGump();
- if (desktopgump->TraceObjId(mx, my) == 1) {
- // double right click on avatar = toggle combat mode
- avatar->toggleInCombat();
- waitFor(avatar->doAnim(Animation::unreadyWeapon, direction));
- return;
- }
-
- if (canAttack()) {
- // double right click = kick
-// pout << "AvatarMover: combat kick" << Std::endl;
-
- if (checkTurn(mousedir, false))
- return;
-
- waitFor(avatar->doAnim(Animation::kick, mousedir));
- _lastAttack = _lastFrame;
-
- // kicking gives str/dex
- avatar->accumulateStr(1 + (getRandom() % 2));
- avatar->accumulateDex(2 + (getRandom() % 2));
- }
-
- return;
- }
-
- if (_mouseButton[1].isState(MBS_DOWN) && _mouseButton[1].isState(MBS_HANDLED)) {
- // Note: Orginal game allowed a move animation on a single right click.
- // This implementation needs right mouse to be held.
- setMovementFlag(MOVE_MOUSE_DIRECTION);
-
- if (checkTurn(mousedir, true))
- return;
-
- //!! TODO: check if you can actually take this step
- Direction nextdir = mousedir;
- Animation::Sequence nextanim;
-
- if (lastanim == Animation::run) {
- // want to run while in combat mode?
- // first sheath weapon
- nextanim = Animation::readyWeapon;
- } else if (Direction_Invert(direction) == mousedir) {
- nextanim = Animation::retreat;
- nextdir = direction;
- } else {
- nextanim = Animation::advance;
- }
-
- if (mouselength == 2) {
- // Take a step before running
- nextanim = Animation::walk;
- avatar->setActorFlag(Actor::ACT_COMBATRUN);
- avatar->toggleInCombat();
- MusicProcess::get_instance()->playCombatMusic(110); // CONSTANT!!
- }
-
- nextanim = Animation::checkWeapon(nextanim, lastanim);
- waitFor(avatar->doAnim(nextanim, nextdir));
- return;
- }
-
- // if clicked, turn in mouse direction
- if (m0clicked || m1clicked)
- if (checkTurn(mousedir, false))
- return;
-
- bool moving = (lastanim == Animation::advance || lastanim == Animation::retreat);
-
- DirectionMode dirmode = avatar->animDirMode(Animation::combatStand);
-
- // 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_OneLeft(direction, dirmode);
- }
-
- if (hasMovementFlags(MOVE_TURN_RIGHT)) {
- direction = Direction_OneRight(direction, dirmode);
- }
- }
-
- if (hasMovementFlags(MOVE_FORWARD)) {
- Animation::Sequence nextanim = Animation::advance;
-
- if (lastanim == Animation::run) {
- // want to run while in combat mode?
- // first sheath weapon
- nextanim = Animation::readyWeapon;
- }
-
- if (hasMovementFlags(MOVE_RUN)) {
- // Take a step before running
- nextanim = Animation::walk;
- avatar->setActorFlag(Actor::ACT_COMBATRUN);
- avatar->toggleInCombat();
- MusicProcess::get_instance()->playCombatMusic(110); // CONSTANT!!
- }
-
- nextanim = Animation::checkWeapon(nextanim, lastanim);
- waitFor(avatar->doAnim(nextanim, direction));
- return;
- }
-
- if (hasMovementFlags(MOVE_BACK)) {
- waitFor(avatar->doAnim(Animation::retreat, direction));
- return;
- }
-
- int y = 0;
- int x = 0;
- if (hasMovementFlags(MOVE_UP)) {
- y++;
- }
- if (hasMovementFlags(MOVE_DOWN)) {
- y--;
- }
- if (hasMovementFlags(MOVE_LEFT)) {
- x--;
- }
- if (hasMovementFlags(MOVE_RIGHT)) {
- x++;
- }
-
- if (x != 0 || y != 0) {
- Direction nextdir = Direction_Get(y, x, dirmode_8dirs);
-
- if (checkTurn(nextdir, true))
- return;
-
- Animation::Sequence nextanim;
- if (lastanim == Animation::run) {
- // want to run while in combat mode?
- // first sheath weapon
- nextanim = Animation::readyWeapon;
- } else if (Direction_Invert(direction) == nextdir) {
- nextanim = Animation::retreat;
- nextdir = direction;
- } else {
- nextanim = Animation::advance;
- }
-
- if (hasMovementFlags(MOVE_RUN)) {
- // Take a step before running
- nextanim = Animation::walk;
- avatar->setActorFlag(Actor::ACT_COMBATRUN);
- avatar->toggleInCombat();
- MusicProcess::get_instance()->playCombatMusic(110); // CONSTANT!!
- }
-
- nextanim = Animation::checkWeapon(nextanim, lastanim);
- waitFor(avatar->doAnim(nextanim, nextdir));
- return;
- }
-
- if (checkTurn(direction, false))
- return;
- // not doing anything in particular? stand
- // TODO: make sure falling works properly.
- if (lastanim != Animation::combatStand) {
- Animation::Sequence nextanim = Animation::combatStand;
- nextanim = Animation::checkWeapon(nextanim, lastanim);
- waitFor(avatar->doAnim(nextanim, direction));
- }
-}
-
-void AvatarMoverProcess::handleNormalMode() {
- Ultima8Engine *guiapp = Ultima8Engine::get_instance();
- Mouse *mouse = Mouse::get_instance();
+void AvatarMoverProcess::tryAttack() {
MainActor *avatar = getMainActor();
- Animation::Sequence lastanim = avatar->getLastAnim();
- 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);
- Direction mousedir = mouse->getMouseDirectionWorld(mx, my);
-
- // Store current idle time. (Also see end of function.)
- uint32 currentIdleTime = _idleTime;
- _idleTime = 0;
-
- // User toggled combat while in combatRun
- if (avatar->isInCombat()) {
- avatar->clearActorFlag(Actor::ACT_COMBATRUN);
- avatar->toggleInCombat();
- }
-
- // If Avatar has fallen down, stand up.
- if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
- if (!stasis) {
- waitFor(avatar->doAnim(Animation::standUp, direction));
- }
- return;
- }
-
- // If still in combat stance, sheathe weapon
- if (!stasis && Animation::isCombatAnim(lastanim)) {
- ProcId anim1 = avatar->doAnim(Animation::unreadyWeapon, direction);
- ProcId anim2 = avatar->doAnim(Animation::stand, direction);
- Process *anim2p = Kernel::get_instance()->getProcess(anim2);
- anim2p->waitFor(anim1);
- waitFor(anim2);
-
- return;
- }
-
- bool m0clicked = false;
- bool m1clicked = false;
-
- // check mouse state to see what needs to be done
- if (!_mouseButton[0].isState(MBS_HANDLED) &&
- !_mouseButton[0].curWithinDblClkTimeout()) {
- m0clicked = true;
- _mouseButton[0].setState(MBS_HANDLED);
- }
-
- if (!_mouseButton[1].isState(MBS_HANDLED) &&
- !_mouseButton[1].curWithinDblClkTimeout()) {
- m1clicked = true;
- _mouseButton[1].setState(MBS_HANDLED);
- }
-
- if (!_mouseButton[1].isState(MBS_DOWN)) {
- clearMovementFlag(MOVE_MOUSE_DIRECTION);
- }
-
- if (_mouseButton[1].isState(MBS_DOWN) && _mouseButton[1].isState(MBS_HANDLED)) {
- // Note: Orginal game allowed a move animation on a single right click.
- // This implementation needs right mouse to be held.
- setMovementFlag(MOVE_MOUSE_DIRECTION);
- }
-
- if (!hasMovementFlags(MOVE_ANY_DIRECTION)) {
- // if we were running in combat mode, slow to a walk, draw weapon
- // (even in stasis)
- if (combatRun) {
- avatar = getMainActor();
- avatar->clearActorFlag(Actor::ACT_COMBATRUN);
- avatar->toggleInCombat();
-
- // If we were running, slow to a walk before drawing weapon.
- // Note: Original game did not check last animation and always took an extra walk.
- if (lastanim == Animation::run || lastanim == Animation::runningJump) {
- ProcId walkpid = avatar->doAnim(Animation::walk, direction);
- ProcId drawpid = avatar->doAnim(Animation::readyWeapon, direction);
- Process *drawproc = Kernel::get_instance()->getProcess(drawpid);
- drawproc->waitFor(walkpid);
- waitFor(drawpid);
- return;
- }
-
- waitFor(avatar->doAnim(Animation::readyWeapon, direction));
- return;
- }
-
- // if we were running, slow to a walk before stopping
- // (even in stasis)
- if (lastanim == Animation::run) {
- ProcId walkpid = avatar->doAnim(Animation::walk, direction);
- ProcId standpid = avatar->doAnim(Animation::stand, direction);
- Process *standproc = Kernel::get_instance()->getProcess(standpid);
- standproc->waitFor(walkpid);
- waitFor(standpid);
- return;
- }
-
- // TODO: if we were hanging, fall
- }
-
- // can't do any new actions if in stasis
- if (stasis)
- return;
-
- // both mouse buttons down and not yet handled, check for jump.
- if (!_mouseButton[0].isState(MBS_HANDLED) && !_mouseButton[1].isState(MBS_HANDLED)) {
- // Take action if both were clicked within
- // double-click timeout of each other.
- // notice these are all unsigned.
- uint32 down = _mouseButton[1]._curDown;
- if (_mouseButton[0]._curDown < down) {
- down = down - _mouseButton[0]._curDown;
- } else {
- down = _mouseButton[0]._curDown - down;
- }
-
- if (down < DOUBLE_CLICK_TIMEOUT) {
- // Both buttons pressed within the timeout
- _mouseButton[0].setState(MBS_HANDLED);
- _mouseButton[1].setState(MBS_HANDLED);
- setMovementFlag(MOVE_JUMP);
- }
- }
-
- if ((!_mouseButton[0].isState(MBS_HANDLED) || m0clicked) && hasMovementFlags(MOVE_ANY_DIRECTION | MOVE_STEP)) {
- _mouseButton[0].setState(MBS_HANDLED);
- // We got a left mouse down while already moving in any direction or holding the step button.
- // CHECKME: check what needs to happen when keeping left pressed
- setMovementFlag(MOVE_JUMP);
- }
-
- if (_mouseButton[1].isUnhandledDoubleClick()) {
- Gump *desktopgump = Ultima8Engine::get_instance()->getDesktopGump();
- if (desktopgump->TraceObjId(mx, my) == 1) {
- // double right click on avatar = toggle combat mode
- _mouseButton[1].setState(MBS_HANDLED);
- _mouseButton[1]._lastDown = 0;
-
- avatar->toggleInCombat();
- waitFor(avatar->doAnim(Animation::readyWeapon, direction));
- return;
- }
- }
-
- if (hasMovementFlags(MOVE_JUMP) && hasMovementFlags(MOVE_ANY_DIRECTION)) {
- clearMovementFlag(MOVE_JUMP);
-
- if (hasMovementFlags(MOVE_MOUSE_DIRECTION)) {
- if (checkTurn(mousedir, false))
- return;
- }
-
- Animation::Sequence nextanim = Animation::jump;
- // check if we need to do a running jump
- if (lastanim == Animation::run || lastanim == Animation::runningJump) {
- nextanim = Animation::runningJump;
- }
- else if (avatar->hasActorFlags(Actor::ACT_AIRWALK)) {
- nextanim = Animation::airwalkJump;
- }
- else if ((hasMovementFlags(MOVE_MOUSE_DIRECTION) && mouselength == 0) || hasMovementFlags(MOVE_STEP)) {
- nextanim = Animation::jumpUp;
- }
-
- nextanim = Animation::checkWeapon(nextanim, lastanim);
- waitFor(avatar->doAnim(nextanim, direction));
- return;
- }
-
- if (hasMovementFlags(MOVE_JUMP)) {
- clearMovementFlag(MOVE_JUMP);
-
- if (checkTurn(mousedir, false))
- return;
-
- Animation::Sequence nextanim = Animation::jumpUp;
- if (mouselength > 0) {
- nextanim = Animation::jump;
- }
-
- // check if there's something we can climb up onto here
- Animation::Sequence climbanim = Animation::climb72;
- while (climbanim >= Animation::climb16) {
- if (avatar->tryAnim(climbanim, direction) ==
- Animation::SUCCESS) {
- nextanim = climbanim;
- }
- climbanim = static_cast<Animation::Sequence>(climbanim - 1);
- }
-
- if (nextanim == Animation::jump) {
- jump(Animation::jump, direction);
- }
- else {
- if (nextanim != Animation::jumpUp) {
- // climbing gives str/dex
- avatar->accumulateStr(2 + nextanim - Animation::climb16);
- avatar->accumulateDex(2 * (2 + nextanim - Animation::climb16));
- }
- nextanim = Animation::checkWeapon(nextanim, lastanim);
- waitFor(avatar->doAnim(nextanim, direction));
- }
- return;
- }
-
- if (hasMovementFlags(MOVE_MOUSE_DIRECTION)) {
- Animation::Sequence nextanim = Animation::step;
-
- if (mouselength == 1) {
- nextanim = Animation::walk;
- } else if (mouselength == 2) {
- if (lastanim == Animation::run
- || lastanim == Animation::runningJump
- || lastanim == Animation::walk)
- nextanim = Animation::run;
- else
- nextanim = Animation::walk;
- }
-
- step(nextanim, mousedir);
- return;
- }
-
- if (m1clicked)
- if (checkTurn(mousedir, false))
- return;
-
- bool moving = (lastanim == Animation::step || lastanim == Animation::run || lastanim == Animation::walk);
-
- DirectionMode dirmode = avatar->animDirMode(Animation::step);
-
- // 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_OneLeft(direction, dirmode);
- }
-
- if (hasMovementFlags(MOVE_TURN_RIGHT)) {
- direction = Direction_OneRight(direction, dirmode);
- }
- }
-
- Animation::Sequence nextanim = Animation::walk;
-
- if (hasMovementFlags(MOVE_STEP)) {
- nextanim = Animation::step;
- } else if (hasMovementFlags(MOVE_RUN)) {
- if (lastanim == Animation::run
- || lastanim == Animation::runningJump
- || lastanim == Animation::walk)
- nextanim = Animation::run;
- else
- nextanim = Animation::walk;
- }
-
- if (hasMovementFlags(MOVE_FORWARD)) {
- step(nextanim, direction);
- return;
- }
-
- if (hasMovementFlags(MOVE_BACK)) {
- step(nextanim, Direction_Invert(direction));
-
- // flip to move forward once turned
- setMovementFlag(MOVE_FORWARD);
- return;
- }
-
- int y = 0;
- int x = 0;
- if (hasMovementFlags(MOVE_UP)) {
- y++;
- }
- if (hasMovementFlags(MOVE_DOWN)) {
- y--;
- }
- if (hasMovementFlags(MOVE_LEFT)) {
- x--;
- }
- if (hasMovementFlags(MOVE_RIGHT)) {
- x++;
- }
-
- if (x != 0 || y != 0) {
- direction = Direction_Get(y, x, dirmode_8dirs);
- step(nextanim, direction);
- return;
- }
-
- if (checkTurn(direction, moving))
- return;
-
- // doing another animation?
- if (Kernel::get_instance()->getNumProcesses(1, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE))
- return;
-
- // if we were running, slow to a walk before stopping
- if (lastanim == Animation::run) {
- waitFor(avatar->doAnim(Animation::walk, direction));
- return;
- }
-
- // not doing anything in particular? stand
- if (lastanim != Animation::stand && currentIdleTime == 0) {
- waitFor(avatar->doAnim(Animation::stand, direction));
- return;
- }
-
- // idle
- _idleTime = currentIdleTime + 1;
-
- // currently shaking head?
- if (lastanim == Animation::lookLeft || lastanim == Animation::lookRight) {
- if ((getRandom() % 1500) + 30 < _idleTime) {
- _lastHeadShakeAnim = lastanim;
- waitFor(avatar->doAnim(Animation::stand, direction));
- _idleTime = 1;
- return;
- }
+ Direction dir = avatar->getDir();
+ if (!avatar->isInCombat()) {
+ avatar->setInCombat(0);
+ waitFor(avatar->doAnim(Animation::readyWeapon, dir));
} else {
- if ((getRandom() % 3000) + 150 < _idleTime) {
- if (getRandom() % 5 == 0)
- nextanim = _lastHeadShakeAnim;
- else if (_lastHeadShakeAnim == Animation::lookLeft)
- nextanim = Animation::lookRight;
- else
- nextanim = Animation::lookLeft;
- waitFor(avatar->doAnim(nextanim, direction));
- _idleTime = 1;
- return;
- }
- }
-}
-
-void AvatarMoverProcess::step(Animation::Sequence action, Direction direction,
- bool adjusted) {
- assert(action == Animation::step || action == Animation::walk ||
- action == Animation::run);
-
- MainActor *avatar = getMainActor();
- Animation::Sequence lastanim = avatar->getLastAnim();
-
- Animation::Result res = avatar->tryAnim(action, 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);
- Direction altdir1 = Direction_OneRight(stepdir, dirmode_8dirs);
- Direction altdir2 = Direction_OneLeft(stepdir, dirmode_8dirs);
-
- res = avatar->tryAnim(action, altdir1);
- if (res == Animation::FAILURE ||
- (action == Animation::step && res == Animation::END_OFF_LAND)) {
- debug(6, "Step: end off land dir %d, altdir1 %d failed, try altdir2 %d", stepdir, altdir1, altdir2);
- res = avatar->tryAnim(action, altdir2);
- if (res == Animation::FAILURE ||
- (action == Animation::step && res == Animation::END_OFF_LAND)) {
- // Can't walk in this direction.
- // Try to take a smaller step
-
- if (action == Animation::walk) {
- debug(6, "Step: end off land both altdirs failed, smaller step (step)");
- step(Animation::step, direction, true);
- return;
- } else if (action == Animation::run) {
- debug(6, "Step: end off land both altdirs failed, smaller step (walk)");
- step(Animation::walk, direction, true);
- return;
- }
-
- } else {
- stepdir = altdir2;
+ if (canAttack()) {
+ waitFor(avatar->doAnim(Animation::attack, dir));
+ if (GAME_IS_CRUSADER) {
+ // FIXME: put some real values in here.
+ int32 xs, ys, zs;
+ avatar->getFootpadWorld(xs, ys, zs);
+ avatar->fireWeapon(xs / 2, ys / 2, zs / 2, dir, 1, 1);
}
- } else {
- stepdir = altdir1;
}
-
-
}
-
- if (action == Animation::step && res == Animation::END_OFF_LAND &&
- lastanim != Animation::keepBalance && !adjusted) {
- if (checkTurn(stepdir, false))
- return;
- debug(6, "Step: end off land both altdirs failed, keep balance.");
- waitFor(avatar->doAnim(Animation::keepBalance, stepdir));
- return;
- }
-
- if (action == Animation::step && res == Animation::FAILURE) {
- action = Animation::stand;
- }
-
-
- bool moving = (action == Animation::run || action == Animation::walk);
-
- if (checkTurn(stepdir, moving))
- return;
-
- debug(6, "Step: step ok: action %d dir %d", action, stepdir);
- action = Animation::checkWeapon(action, lastanim);
- waitFor(avatar->doAnim(action, stepdir));
-}
-
-void AvatarMoverProcess::jump(Animation::Sequence action, Direction direction) {
- MainActor *avatar = getMainActor();
-
- // running jump
- if (action == Animation::runningJump) {
- waitFor(avatar->doAnim(action, direction));
- return;
- }
-
- // airwalk
- if (avatar->hasActorFlags(Actor::ACT_AIRWALK) &&
- action == Animation::jump) {
- waitFor(avatar->doAnim(Animation::airwalkJump, direction));
- return;
- }
-
- bool targeting;
- SettingManager::get_instance()->get("targetedjump", targeting);
-
- if (targeting) {
- Mouse *mouse = Mouse::get_instance();
- int32 coords[3];
- int32 mx, my;
- mouse->getMouseCoords(mx, my);
- GameMapGump *gameMap = Ultima8Engine::get_instance()->getGameMapGump();
- // We need the Gump's x/y for TraceCoordinates
- gameMap->ScreenSpaceToGump(mx, my);
- ObjId targetId = gameMap->TraceCoordinates(mx, my, coords);
- Item *target = getItem(targetId);
-
- int32 ax, ay, az;
- avatar->getCentre(ax, ay, az);
-
- int32 xrange = abs(ax - coords[0]);
- int32 yrange = abs(ay - coords[1]);
- int maxrange = avatar->getStr() * 32;
-
- if (target && target->getShapeInfo()->is_land() &&
- xrange < maxrange && yrange < maxrange) {
- // Original also only lets you jump at the Z_FACE
- Process *p = new TargetedAnimProcess(avatar, Animation::jumpUp,
- direction, coords);
- waitFor(Kernel::get_instance()->addProcess(p));
- return;
- }
- // invalid target or out of range
- waitFor(avatar->doAnim(Animation::shakeHead, direction));
- } else {
- waitFor(avatar->doAnim(Animation::jump, direction));
- }
-}
-
-void AvatarMoverProcess::turnToDirection(Direction direction) {
- MainActor *avatar = getMainActor();
- uint16 turnpid = avatar->turnTowardDir(direction);
- if (turnpid)
- waitFor(turnpid);
}
bool AvatarMoverProcess::checkTurn(Direction direction, bool moving) {
@@ -870,9 +116,9 @@ bool AvatarMoverProcess::checkTurn(Direction direction, bool moving) {
Animation::Sequence lastanim = avatar->getLastAnim();
if (moving &&
- (lastanim == Animation::walk || lastanim == Animation::run ||
- lastanim == Animation::combatStand) &&
- (ABS(direction - curdir) + 2) % 16 <= 4) {
+ (lastanim == Animation::walk || lastanim == Animation::run ||
+ lastanim == Animation::combatStand) &&
+ (ABS(direction - curdir) + 2) % 16 <= 4) {
// don't need to explicitly do a turn animation
return false;
}
@@ -890,30 +136,11 @@ bool AvatarMoverProcess::checkTurn(Direction direction, bool moving) {
return false;
}
-bool AvatarMoverProcess::canAttack() {
- MainActor *avatar = getMainActor();
- if (GAME_IS_CRUSADER)
- return avatar->isInCombat();
- return (_lastFrame > _lastAttack + (25 - avatar->getDex()));
-}
-
-void AvatarMoverProcess::tryAttack() {
+void AvatarMoverProcess::turnToDirection(Direction direction) {
MainActor *avatar = getMainActor();
- Direction dir = avatar->getDir();
- if (!avatar->isInCombat()) {
- avatar->setInCombat(0);
- waitFor(avatar->doAnim(Animation::readyWeapon, dir));
- } else {
- if (canAttack()) {
- waitFor(avatar->doAnim(Animation::attack, dir));
- if (GAME_IS_CRUSADER) {
- // FIXME: put some real values in here.
- int32 xs, ys, zs;
- avatar->getFootpadWorld(xs, ys, zs);
- avatar->fireWeapon(xs / 2, ys / 2, zs / 2, dir, 1, 1);
- }
- }
- }
+ uint16 turnpid = avatar->turnTowardDir(direction);
+ if (turnpid)
+ waitFor(turnpid);
}
void AvatarMoverProcess::onMouseDown(int button, int32 mx, int32 my) {
@@ -959,7 +186,6 @@ void AvatarMoverProcess::saveData(Common::WriteStream *ws) {
ws->writeUint32LE(_lastAttack);
ws->writeUint32LE(_idleTime);
- ws->writeUint16LE(static_cast<uint8>(_lastHeadShakeAnim));
}
bool AvatarMoverProcess::loadData(Common::ReadStream *rs, uint32 version) {
@@ -967,7 +193,6 @@ bool AvatarMoverProcess::loadData(Common::ReadStream *rs, uint32 version) {
_lastAttack = rs->readUint32LE();
_idleTime = rs->readUint32LE();
- _lastHeadShakeAnim = static_cast<Animation::Sequence>(rs->readUint16LE());
return true;
}
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.h b/engines/ultima/ultima8/world/actors/avatar_mover_process.h
index 494d0a8669..1d4dd019d2 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.h
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.h
@@ -30,25 +30,23 @@
namespace Ultima {
namespace Ultima8 {
+/**
+ * Base class for mover processes that decide which animation to
+ * do next based on last anim and keyboard / mouse / etc.
+ */
class AvatarMoverProcess : public Process {
public:
AvatarMoverProcess();
~AvatarMoverProcess() override;
- // p_dynamic_cast stuff
- ENABLE_RUNTIME_CLASSTYPE()
-
void run() override;
- void onMouseDown(int button, int32 mx, int32 my);
- void onMouseUp(int button);
-
void resetIdleTime() {
_idleTime = 0;
}
bool loadData(Common::ReadStream *rs, uint32 version);
- void saveData(Common::WriteStream *ws) override;
+ virtual void saveData(Common::WriteStream *ws) override;
bool hasMovementFlags(uint32 flags) const {
return (_movementFlags & flags) != 0;
@@ -60,7 +58,10 @@ public:
_movementFlags &= ~mask;
}
- void tryAttack();
+ void onMouseDown(int button, int32 mx, int32 my);
+ void onMouseUp(int button);
+
+ virtual void tryAttack() = 0;
enum MovementFlags {
MOVE_MOUSE_DIRECTION = 0x001,
@@ -83,16 +84,15 @@ public:
MOVE_ANY_DIRECTION = MOVE_MOUSE_DIRECTION | MOVE_FORWARD | MOVE_BACK | MOVE_LEFT | MOVE_RIGHT | MOVE_UP | MOVE_DOWN
};
-private:
- void handleHangingMode();
- void handleCombatMode();
- void handleNormalMode();
+protected:
+ virtual void handleHangingMode() = 0;
+ virtual void handleCombatMode() = 0;
+ virtual void handleNormalMode() = 0;
+
+ virtual bool canAttack() = 0;
- 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;
@@ -101,8 +101,7 @@ private:
// shake head when idle
uint32 _idleTime;
- Animation::Sequence _lastHeadShakeAnim;
-
+
MButton _mouseButton[2];
uint32 _movementFlags;
diff --git a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
new file mode 100644
index 0000000000..82b0b19c19
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -0,0 +1,450 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ultima/ultima8/misc/pent_include.h"
+#include "ultima/ultima8/world/actors/cru_avatar_mover_process.h"
+#include "ultima/ultima8/world/actors/animation.h"
+#include "ultima/ultima8/ultima8.h"
+#include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/gumps/game_map_gump.h"
+#include "ultima/ultima8/kernel/kernel.h"
+#include "ultima/ultima8/world/actors/actor_anim_process.h"
+#include "ultima/ultima8/world/actors/targeted_anim_process.h"
+#include "ultima/ultima8/world/get_object.h"
+#include "ultima/ultima8/world/current_map.h"
+#include "ultima/ultima8/world/world.h"
+#include "ultima/ultima8/misc/direction.h"
+#include "ultima/ultima8/misc/direction_util.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+// p_dynamic_cast stuff
+DEFINE_RUNTIME_CLASSTYPE_CODE(CruAvatarMoverProcess)
+
+CruAvatarMoverProcess::CruAvatarMoverProcess() : AvatarMoverProcess() {
+}
+
+
+CruAvatarMoverProcess::~CruAvatarMoverProcess() {
+}
+
+
+void CruAvatarMoverProcess::handleHangingMode() {
+ // No hanging in crusader, this shouldn't happen?
+ assert(false);
+}
+
+void CruAvatarMoverProcess::handleCombatMode() {
+ MainActor *avatar = getMainActor();
+ Animation::Sequence lastanim = avatar->getLastAnim();
+ Direction direction = avatar->getDir();
+ bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
+
+ // never idle when in combat
+ _idleTime = 0;
+
+ // If Avatar has fallen down, stand up
+ if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
+ if (!stasis) {
+ waitFor(avatar->doAnim(Animation::standUp, direction));
+ }
+ return;
+ }
+
+ // can't do any new actions if in stasis
+ if (stasis)
+ return;
+
+ bool moving = (lastanim == Animation::advance || lastanim == Animation::retreat);
+
+ DirectionMode dirmode = avatar->animDirMode(Animation::combatStand);
+
+ // 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_OneLeft(direction, dirmode);
+ }
+
+ if (hasMovementFlags(MOVE_TURN_RIGHT)) {
+ direction = Direction_OneRight(direction, dirmode);
+ }
+ }
+
+ if (hasMovementFlags(MOVE_FORWARD)) {
+ Animation::Sequence nextanim;
+ if (hasMovementFlags(MOVE_STEP)) {
+ nextanim = Animation::advance;
+ } else if (hasMovementFlags(MOVE_RUN)) {
+ // Take a step before running
+ avatar->toggleInCombat();
+ if (lastanim != Animation::startRun)
+ nextanim = Animation::startRun;
+ else
+ nextanim = Animation::run;
+ } else {
+ // moving from combat stows weapon
+ nextanim = Animation::walk;
+ avatar->toggleInCombat();
+ }
+
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ step(nextanim, direction);
+ return;
+ }
+
+ if (hasMovementFlags(MOVE_BACK)) {
+ waitFor(avatar->doAnim(Animation::retreat, direction));
+ return;
+ }
+
+ int y = 0;
+ int x = 0;
+ if (hasMovementFlags(MOVE_UP)) {
+ y++;
+ }
+ if (hasMovementFlags(MOVE_DOWN)) {
+ y--;
+ }
+ if (hasMovementFlags(MOVE_LEFT)) {
+ x--;
+ }
+ if (hasMovementFlags(MOVE_RIGHT)) {
+ x++;
+ }
+
+ if (x != 0 || y != 0) {
+ Direction nextdir = Direction_Get(y, x, dirmode_8dirs);
+
+ if (checkTurn(nextdir, true))
+ return;
+
+ Animation::Sequence nextanim;
+ if (lastanim == Animation::run) {
+ // want to run while in combat mode?
+ // first sheath weapon
+ nextanim = Animation::readyWeapon;
+ } else if (Direction_Invert(direction) == nextdir) {
+ nextanim = Animation::retreat;
+ nextdir = direction;
+ }
+
+ if (hasMovementFlags(MOVE_RUN)) {
+ // Take a step before running
+ nextanim = Animation::startRun;
+ avatar->toggleInCombat();
+ }
+
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ step(nextanim, nextdir);
+ return;
+ }
+
+ if (checkTurn(direction, false))
+ return;
+
+ // not doing anything in particular? stand
+ if (lastanim != Animation::combatStand) {
+ Animation::Sequence nextanim = Animation::combatStand;
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+ }
+}
+
+void CruAvatarMoverProcess::handleNormalMode() {
+ Ultima8Engine *guiapp = Ultima8Engine::get_instance();
+ MainActor *avatar = getMainActor();
+ Animation::Sequence lastanim = avatar->getLastAnim();
+ Direction direction = avatar->getDir();
+ bool stasis = guiapp->isAvatarInStasis();
+
+ // Store current idle time. (Also see end of function.)
+ uint32 currentIdleTime = _idleTime;
+ _idleTime = 0;
+
+ // User toggled combat while in combatRun
+ if (avatar->isInCombat()) {
+ avatar->clearActorFlag(Actor::ACT_COMBATRUN);
+ avatar->toggleInCombat();
+ }
+
+ // If Avatar has fallen down do nothing
+ if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
+ if (!stasis) {
+ waitFor(avatar->doAnim(Animation::standUp, direction));
+ }
+ return;
+ }
+
+ // If still in combat stance, sheathe weapon
+ if (!stasis && Animation::isCombatAnim(lastanim)) {
+ ProcId anim1 = avatar->doAnim(Animation::unreadyWeapon, direction);
+ ProcId anim2 = avatar->doAnim(Animation::stand, direction);
+ Process *anim2p = Kernel::get_instance()->getProcess(anim2);
+ anim2p->waitFor(anim1);
+ waitFor(anim2);
+
+ return;
+ }
+
+ if (!hasMovementFlags(MOVE_ANY_DIRECTION)) {
+ // if we were running, slow to a walk before stopping
+ // (even in stasis)
+ if (lastanim == Animation::run) {
+ ProcId walkpid = avatar->doAnim(Animation::walk, direction);
+ ProcId standpid = avatar->doAnim(Animation::stand, direction);
+ Process *standproc = Kernel::get_instance()->getProcess(standpid);
+ standproc->waitFor(walkpid);
+ waitFor(standpid);
+ return;
+ }
+ }
+
+ // can't do any new actions if in stasis
+ if (stasis)
+ return;
+
+ if (hasMovementFlags(MOVE_JUMP) && hasMovementFlags(MOVE_ANY_DIRECTION)) {
+ clearMovementFlag(MOVE_JUMP);
+
+ Animation::Sequence nextanim = Animation::jump;
+ // check if we need to do a running jump
+ if (lastanim == Animation::run || lastanim == Animation::runningJump) {
+ nextanim = Animation::runningJump;
+ }
+ else if (avatar->hasActorFlags(Actor::ACT_AIRWALK)) {
+ nextanim = Animation::airwalkJump;
+ }
+
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+ return;
+ }
+
+ if (hasMovementFlags(MOVE_JUMP)) {
+ clearMovementFlag(MOVE_JUMP);
+
+ Animation::Sequence nextanim = Animation::jumpUp;
+
+ if (nextanim == Animation::jump) {
+ jump(Animation::jump, direction);
+ } else {
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+ }
+ return;
+ }
+
+ bool moving = (lastanim == Animation::step || lastanim == Animation::run || lastanim == Animation::walk);
+
+ DirectionMode dirmode = avatar->animDirMode(Animation::step);
+
+ // 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_OneLeft(direction, dirmode);
+ }
+
+ if (hasMovementFlags(MOVE_TURN_RIGHT)) {
+ direction = Direction_OneRight(direction, dirmode);
+ }
+ }
+
+ Animation::Sequence nextanim = Animation::walk;
+
+ if (hasMovementFlags(MOVE_STEP)) {
+ nextanim = Animation::step;
+ } else if (hasMovementFlags(MOVE_RUN)) {
+ if (lastanim == Animation::run
+ || lastanim == Animation::runningJump
+ || lastanim == Animation::walk)
+ nextanim = Animation::run;
+ else
+ nextanim = Animation::walk;
+ }
+
+ if (hasMovementFlags(MOVE_FORWARD)) {
+ step(nextanim, direction);
+ return;
+ }
+
+ if (hasMovementFlags(MOVE_BACK)) {
+ step(nextanim, Direction_Invert(direction));
+
+ // flip to move forward once turned
+ setMovementFlag(MOVE_FORWARD);
+ return;
+ }
+
+ int y = 0;
+ int x = 0;
+ if (hasMovementFlags(MOVE_UP)) {
+ y++;
+ }
+ if (hasMovementFlags(MOVE_DOWN)) {
+ y--;
+ }
+ if (hasMovementFlags(MOVE_LEFT)) {
+ x--;
+ }
+ if (hasMovementFlags(MOVE_RIGHT)) {
+ x++;
+ }
+
+ if (x != 0 || y != 0) {
+ direction = Direction_Get(y, x, dirmode_8dirs);
+ step(nextanim, direction);
+ return;
+ }
+
+ if (checkTurn(direction, moving))
+ return;
+
+ // doing another animation?
+ if (Kernel::get_instance()->getNumProcesses(1, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE))
+ return;
+
+ // if we were running, slow to a walk before stopping
+ if (lastanim == Animation::run) {
+ waitFor(avatar->doAnim(Animation::walk, direction));
+ return;
+ }
+
+ // not doing anything in particular? stand
+ if (lastanim != Animation::stand && currentIdleTime == 0) {
+ waitFor(avatar->doAnim(Animation::stand, direction));
+ return;
+ }
+
+ // idle
+ _idleTime = currentIdleTime + 1;
+}
+
+void CruAvatarMoverProcess::step(Animation::Sequence action, Direction direction,
+ bool adjusted) {
+ MainActor *avatar = getMainActor();
+ Animation::Sequence lastanim = avatar->getLastAnim();
+
+ Animation::Result res = avatar->tryAnim(action, direction);
+
+ if (res != Animation::SUCCESS) {
+ World *world = World::get_instance();
+ CurrentMap *currentmap = world->getCurrentMap();
+
+ // Search right/left gradually increasing distance to see if we can make the move work.
+
+ Direction dir_right = Direction_TurnByDelta(direction, 4, dirmode_16dirs);
+ Direction dir_left = Direction_TurnByDelta(direction, -4, dirmode_16dirs);
+ Point3 origpt;
+ avatar->getLocation(origpt);
+ static const int ADJUSTMENTS[] = {0x10, 0x10, 0x20, 0x20, 0x30, 0x30,
+ 0x40, 0x40, 0x50, 0x50};
+
+ for (int i = 0; i < ARRAYSIZE(ADJUSTMENTS); i++) {
+ Direction testdir = (i % 2 ? dir_left : dir_right);
+ int32 x = origpt.x + Direction_XFactor(testdir) * ADJUSTMENTS[i];
+ int32 y = origpt.y + Direction_YFactor(testdir) * ADJUSTMENTS[i];
+ int32 z = origpt.z;
+ if (currentmap->isValidPosition(x, y, z, avatar->getShape(), avatar->getObjId(),
+ nullptr, nullptr, nullptr)) {
+ avatar->setLocation(x, y, z);
+ res = avatar->tryAnim(action, direction);
+ if (res == Animation::SUCCESS)
+ break;
+ }
+ }
+
+ if (res != Animation::SUCCESS) {
+ // reset location, couldn't move.
+ avatar->setLocation(origpt.x, origpt.y, origpt.z);
+ }
+ }
+
+ if ((action == Animation::step || action == Animation::advance ||
+ action == Animation::retreat || action == Animation::run ||
+ action == Animation::startRun || action == Animation::walk)
+ && res == Animation::FAILURE) {
+ action = Animation::stand;
+ }
+
+ bool moving = (action == Animation::run || action == Animation::walk);
+
+ if (checkTurn(direction, moving))
+ return;
+
+ debug(6, "Cru avatar step: picked action %d dir %d (test result %d)", action, direction, res);
+ action = Animation::checkWeapon(action, lastanim);
+ waitFor(avatar->doAnim(action, direction));
+}
+
+void CruAvatarMoverProcess::jump(Animation::Sequence action, Direction direction) {
+ MainActor *avatar = getMainActor();
+
+ // running jump
+ if (action == Animation::runningJump) {
+ waitFor(avatar->doAnim(action, direction));
+ return;
+ }
+
+ // airwalk
+ if (avatar->hasActorFlags(Actor::ACT_AIRWALK) &&
+ action == Animation::jump) {
+ waitFor(avatar->doAnim(Animation::airwalkJump, direction));
+ return;
+ }
+
+ waitFor(avatar->doAnim(Animation::jump, direction));
+}
+
+bool CruAvatarMoverProcess::canAttack() {
+ MainActor *avatar = getMainActor();
+ return avatar->isInCombat();
+}
+
+void CruAvatarMoverProcess::tryAttack() {
+ MainActor *avatar = getMainActor();
+ Direction dir = avatar->getDir();
+ if (!avatar->isInCombat()) {
+ avatar->setInCombat(0);
+ waitFor(avatar->doAnim(Animation::readyWeapon, dir));
+ } else {
+ if (canAttack()) {
+ waitFor(avatar->doAnim(Animation::attack, dir));
+ // FIXME: put some real values in here.
+ int32 xs, ys, zs;
+ avatar->getFootpadWorld(xs, ys, zs);
+ avatar->fireWeapon(xs / 2, ys / 2, zs / 2, dir, 1, 1);
+ }
+ }
+}
+
+void CruAvatarMoverProcess::saveData(Common::WriteStream *ws) {
+ AvatarMoverProcess::saveData(ws);
+}
+
+bool CruAvatarMoverProcess::loadData(Common::ReadStream *rs, uint32 version) {
+ if (!AvatarMoverProcess::loadData(rs, version)) return false;
+ return true;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.h b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.h
new file mode 100644
index 0000000000..c10fa99cd4
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.h
@@ -0,0 +1,65 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WORLD_ACTORS_CRUAVATARMOVERPROCESS_H
+#define WORLD_ACTORS_CRUAVATARMOVERPROCESS_H
+
+#include "ultima/ultima8/kernel/process.h"
+#include "ultima/ultima8/world/actors/animation.h"
+#include "ultima/ultima8/world/actors/avatar_mover_process.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+/**
+ * Mover process that replicates the feel of Crusader - moving, combat, jumps, etc.
+ * Tries sliding left and right if movement is blocked. Walking cancels combat.
+ * TODO: Support combat rolls and side-steps.
+ */
+class CruAvatarMoverProcess : public AvatarMoverProcess {
+public:
+ CruAvatarMoverProcess();
+ ~CruAvatarMoverProcess() override;
+
+ // p_dynamic_cast stuff
+ ENABLE_RUNTIME_CLASSTYPE()
+
+ bool loadData(Common::ReadStream *rs, uint32 version);
+ void saveData(Common::WriteStream *ws) override;
+
+ void tryAttack() override;
+
+private:
+ void handleHangingMode() override;
+ void handleCombatMode() override;
+ void handleNormalMode() override;
+ bool canAttack() override;
+
+ void step(Animation::Sequence action, Direction direction, bool adjusted = false);
+ void jump(Animation::Sequence action, Direction direction);
+
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
diff --git a/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
new file mode 100644
index 0000000000..5e6ffdc7d3
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
@@ -0,0 +1,848 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "ultima/ultima8/misc/pent_include.h"
+#include "ultima/ultima8/world/actors/u8_avatar_mover_process.h"
+#include "ultima/ultima8/world/actors/animation.h"
+#include "ultima/ultima8/ultima8.h"
+#include "ultima/ultima8/world/actors/main_actor.h"
+#include "ultima/ultima8/gumps/game_map_gump.h"
+#include "ultima/ultima8/kernel/kernel.h"
+#include "ultima/ultima8/world/actors/actor_anim_process.h"
+#include "ultima/ultima8/world/actors/targeted_anim_process.h"
+#include "ultima/ultima8/world/actors/avatar_gravity_process.h"
+#include "ultima/ultima8/graphics/shape_info.h"
+#include "ultima/ultima8/conf/setting_manager.h"
+#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 {
+
+// p_dynamic_cast stuff
+DEFINE_RUNTIME_CLASSTYPE_CODE(U8AvatarMoverProcess)
+
+U8AvatarMoverProcess::U8AvatarMoverProcess() : AvatarMoverProcess(),
+ _lastHeadShakeAnim(Animation::lookLeft) {
+}
+
+
+U8AvatarMoverProcess::~U8AvatarMoverProcess() {
+}
+
+void U8AvatarMoverProcess::handleHangingMode() {
+ bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
+
+ _idleTime = 0;
+
+ if (stasis)
+ return;
+
+ bool m0clicked = false;
+ //bool m1clicked = false;
+ if (!_mouseButton[0].isState(MBS_HANDLED) &&
+ !_mouseButton[0].curWithinDblClkTimeout()) {
+ m0clicked = true;
+ _mouseButton[0].setState(MBS_HANDLED);
+ }
+ if (!_mouseButton[1].isState(MBS_HANDLED) &&
+ !_mouseButton[1].curWithinDblClkTimeout()) {
+ //m1clicked = true;
+ _mouseButton[1].setState(MBS_HANDLED);
+ }
+
+ // if left mouse is down, try to climb up
+
+ if (_mouseButton[0].isState(MBS_DOWN) &&
+ (!_mouseButton[0].isState(MBS_HANDLED) || m0clicked)) {
+ _mouseButton[0].setState(MBS_HANDLED);
+ _mouseButton[0]._lastDown = 0;
+ MainActor *avatar = getMainActor();
+
+ if (avatar->tryAnim(Animation::climb40, dir_current) == Animation::SUCCESS) {
+ avatar->ensureGravityProcess()->terminate();
+ waitFor(avatar->doAnim(Animation::climb40, dir_current));
+ }
+ }
+}
+
+void U8AvatarMoverProcess::handleCombatMode() {
+ Mouse *mouse = Mouse::get_instance();
+ MainActor *avatar = getMainActor();
+ Animation::Sequence lastanim = avatar->getLastAnim();
+ Direction direction = avatar->getDir();
+ bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
+
+ int32 mx, my;
+ mouse->getMouseCoords(mx, my);
+ unsigned int mouselength = mouse->getMouseLength(mx, my);
+
+ Direction mousedir = mouse->getMouseDirectionWorld(mx, my);
+
+ // never idle when in combat
+ _idleTime = 0;
+
+ // If Avatar has fallen down, stand up.
+ if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
+ if (!stasis)
+ waitFor(avatar->doAnim(Animation::standUp, mousedir));
+ return;
+ }
+
+ // if we were blocking, and no longer holding the mouse, stop
+ if (lastanim == Animation::startBlock &&
+ !_mouseButton[0].isState(MBS_DOWN)) {
+ waitFor(avatar->doAnim(Animation::stopBlock, direction));
+ return;
+ }
+
+ // can't do any new actions if in stasis
+ if (stasis)
+ return;
+
+ bool m0clicked = false;
+ bool m1clicked = false;
+
+ if (!_mouseButton[0].isState(MBS_HANDLED) &&
+ !_mouseButton[0].curWithinDblClkTimeout()) {
+ m0clicked = true;
+ _mouseButton[0].setState(MBS_HANDLED);
+ }
+
+ if (!_mouseButton[1].isState(MBS_HANDLED) &&
+ !_mouseButton[1].curWithinDblClkTimeout()) {
+ m1clicked = true;
+ _mouseButton[1].setState(MBS_HANDLED);
+ }
+
+ if (!_mouseButton[0].isState(MBS_DOWN)) {
+ clearMovementFlag(MOVE_MOUSE_DIRECTION);
+ }
+
+ if (_mouseButton[0].isState(MBS_DOWN) &&
+ _mouseButton[0].isState(MBS_HANDLED) && _mouseButton[0]._lastDown > 0) {
+ // left click-and-hold = block
+ if (lastanim == Animation::startBlock)
+ return;
+
+// pout << "AvatarMover: combat block" << Std::endl;
+
+ if (checkTurn(mousedir, false))
+ return;
+
+ waitFor(avatar->doAnim(Animation::startBlock, mousedir));
+ return;
+ }
+
+ if (_mouseButton[0].isUnhandledDoubleClick()) {
+ _mouseButton[0].setState(MBS_HANDLED);
+ _mouseButton[0]._lastDown = 0;
+
+ if (canAttack()) {
+ // double left click = attack
+// pout << "AvatarMover: combat attack" << Std::endl;
+
+ if (checkTurn(mousedir, true))
+ return;
+
+ waitFor(avatar->doAnim(Animation::attack, mousedir));
+ _lastAttack = _lastFrame;
+
+ // attacking gives str/dex
+ avatar->accumulateStr(1 + (getRandom() % 2));
+ avatar->accumulateDex(2 + (getRandom() % 2));
+ }
+
+ return;
+ }
+
+ if (_mouseButton[1].isUnhandledDoubleClick()) {
+ _mouseButton[1].setState(MBS_HANDLED);
+ _mouseButton[1]._lastDown = 0;
+
+ Gump *desktopgump = Ultima8Engine::get_instance()->getDesktopGump();
+ if (desktopgump->TraceObjId(mx, my) == 1) {
+ // double right click on avatar = toggle combat mode
+ avatar->toggleInCombat();
+ waitFor(avatar->doAnim(Animation::unreadyWeapon, direction));
+ return;
+ }
+
+ if (canAttack()) {
+ // double right click = kick
+// pout << "AvatarMover: combat kick" << Std::endl;
+
+ if (checkTurn(mousedir, false))
+ return;
+
+ waitFor(avatar->doAnim(Animation::kick, mousedir));
+ _lastAttack = _lastFrame;
+
+ // kicking gives str/dex
+ avatar->accumulateStr(1 + (getRandom() % 2));
+ avatar->accumulateDex(2 + (getRandom() % 2));
+ }
+
+ return;
+ }
+
+ if (_mouseButton[1].isState(MBS_DOWN) && _mouseButton[1].isState(MBS_HANDLED)) {
+ // Note: Orginal game allowed a move animation on a single right click.
+ // This implementation needs right mouse to be held.
+ setMovementFlag(MOVE_MOUSE_DIRECTION);
+
+ if (checkTurn(mousedir, true))
+ return;
+
+ //!! TODO: check if you can actually take this step
+ Direction nextdir = mousedir;
+ Animation::Sequence nextanim;
+
+ if (lastanim == Animation::run) {
+ // want to run while in combat mode?
+ // first sheath weapon
+ nextanim = Animation::readyWeapon;
+ } else if (Direction_Invert(direction) == mousedir) {
+ nextanim = Animation::retreat;
+ nextdir = direction;
+ } else {
+ nextanim = Animation::advance;
+ }
+
+ if (mouselength == 2) {
+ // Take a step before running
+ nextanim = Animation::walk;
+ avatar->setActorFlag(Actor::ACT_COMBATRUN);
+ avatar->toggleInCombat();
+ MusicProcess::get_instance()->playCombatMusic(110); // CONSTANT!!
+ }
+
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, nextdir));
+ return;
+ }
+
+ // if clicked, turn in mouse direction
+ if (m0clicked || m1clicked)
+ if (checkTurn(mousedir, false))
+ return;
+
+ bool moving = (lastanim == Animation::advance || lastanim == Animation::retreat);
+
+ DirectionMode dirmode = avatar->animDirMode(Animation::combatStand);
+
+ // 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_OneLeft(direction, dirmode);
+ }
+
+ if (hasMovementFlags(MOVE_TURN_RIGHT)) {
+ direction = Direction_OneRight(direction, dirmode);
+ }
+ }
+
+ if (hasMovementFlags(MOVE_FORWARD)) {
+ Animation::Sequence nextanim = Animation::advance;
+
+ if (lastanim == Animation::run) {
+ // want to run while in combat mode?
+ // first sheath weapon
+ nextanim = Animation::readyWeapon;
+ }
+
+ if (hasMovementFlags(MOVE_RUN)) {
+ // Take a step before running
+ nextanim = Animation::walk;
+ avatar->setActorFlag(Actor::ACT_COMBATRUN);
+ avatar->toggleInCombat();
+ MusicProcess::get_instance()->playCombatMusic(110); // CONSTANT!!
+ }
+
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+ return;
+ }
+
+ if (hasMovementFlags(MOVE_BACK)) {
+ waitFor(avatar->doAnim(Animation::retreat, direction));
+ return;
+ }
+
+ int y = 0;
+ int x = 0;
+ if (hasMovementFlags(MOVE_UP)) {
+ y++;
+ }
+ if (hasMovementFlags(MOVE_DOWN)) {
+ y--;
+ }
+ if (hasMovementFlags(MOVE_LEFT)) {
+ x--;
+ }
+ if (hasMovementFlags(MOVE_RIGHT)) {
+ x++;
+ }
+
+ if (x != 0 || y != 0) {
+ Direction nextdir = Direction_Get(y, x, dirmode_8dirs);
+
+ if (checkTurn(nextdir, true))
+ return;
+
+ Animation::Sequence nextanim;
+ if (lastanim == Animation::run) {
+ // want to run while in combat mode?
+ // first sheath weapon
+ nextanim = Animation::readyWeapon;
+ } else if (Direction_Invert(direction) == nextdir) {
+ nextanim = Animation::retreat;
+ nextdir = direction;
+ } else {
+ nextanim = Animation::advance;
+ }
+
+ if (hasMovementFlags(MOVE_RUN)) {
+ // Take a step before running
+ nextanim = Animation::walk;
+ avatar->setActorFlag(Actor::ACT_COMBATRUN);
+ avatar->toggleInCombat();
+ MusicProcess::get_instance()->playCombatMusic(110); // CONSTANT!!
+ }
+
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, nextdir));
+ return;
+ }
+
+ if (checkTurn(direction, false))
+ return;
+
+ // not doing anything in particular? stand
+ // TODO: make sure falling works properly.
+ if (lastanim != Animation::combatStand) {
+ Animation::Sequence nextanim = Animation::combatStand;
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+ }
+}
+
+void U8AvatarMoverProcess::handleNormalMode() {
+ Ultima8Engine *guiapp = Ultima8Engine::get_instance();
+ Mouse *mouse = Mouse::get_instance();
+ MainActor *avatar = getMainActor();
+ Animation::Sequence lastanim = avatar->getLastAnim();
+ 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);
+ Direction mousedir = mouse->getMouseDirectionWorld(mx, my);
+
+ // Store current idle time. (Also see end of function.)
+ uint32 currentIdleTime = _idleTime;
+ _idleTime = 0;
+
+ // User toggled combat while in combatRun
+ if (avatar->isInCombat()) {
+ avatar->clearActorFlag(Actor::ACT_COMBATRUN);
+ avatar->toggleInCombat();
+ }
+
+ // If Avatar has fallen down, stand up.
+ if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
+ if (!stasis) {
+ waitFor(avatar->doAnim(Animation::standUp, direction));
+ }
+ return;
+ }
+
+ // If still in combat stance, sheathe weapon
+ if (!stasis && Animation::isCombatAnim(lastanim)) {
+ ProcId anim1 = avatar->doAnim(Animation::unreadyWeapon, direction);
+ ProcId anim2 = avatar->doAnim(Animation::stand, direction);
+ Process *anim2p = Kernel::get_instance()->getProcess(anim2);
+ anim2p->waitFor(anim1);
+ waitFor(anim2);
+
+ return;
+ }
+
+ bool m0clicked = false;
+ bool m1clicked = false;
+
+ // check mouse state to see what needs to be done
+ if (!_mouseButton[0].isState(MBS_HANDLED) &&
+ !_mouseButton[0].curWithinDblClkTimeout()) {
+ m0clicked = true;
+ _mouseButton[0].setState(MBS_HANDLED);
+ }
+
+ if (!_mouseButton[1].isState(MBS_HANDLED) &&
+ !_mouseButton[1].curWithinDblClkTimeout()) {
+ m1clicked = true;
+ _mouseButton[1].setState(MBS_HANDLED);
+ }
+
+ if (!_mouseButton[1].isState(MBS_DOWN)) {
+ clearMovementFlag(MOVE_MOUSE_DIRECTION);
+ }
+
+ if (_mouseButton[1].isState(MBS_DOWN) && _mouseButton[1].isState(MBS_HANDLED)) {
+ // Note: Orginal game allowed a move animation on a single right click.
+ // This implementation needs right mouse to be held.
+ setMovementFlag(MOVE_MOUSE_DIRECTION);
+ }
+
+ if (!hasMovementFlags(MOVE_ANY_DIRECTION)) {
+ // if we were running in combat mode, slow to a walk, draw weapon
+ // (even in stasis)
+ if (combatRun) {
+ avatar = getMainActor();
+ avatar->clearActorFlag(Actor::ACT_COMBATRUN);
+ avatar->toggleInCombat();
+
+ // If we were running, slow to a walk before drawing weapon.
+ // Note: Original game did not check last animation and always took an extra walk.
+ if (lastanim == Animation::run || lastanim == Animation::runningJump) {
+ ProcId walkpid = avatar->doAnim(Animation::walk, direction);
+ ProcId drawpid = avatar->doAnim(Animation::readyWeapon, direction);
+ Process *drawproc = Kernel::get_instance()->getProcess(drawpid);
+ drawproc->waitFor(walkpid);
+ waitFor(drawpid);
+ return;
+ }
+
+ waitFor(avatar->doAnim(Animation::readyWeapon, direction));
+ return;
+ }
+
+ // if we were running, slow to a walk before stopping
+ // (even in stasis)
+ if (lastanim == Animation::run) {
+ ProcId walkpid = avatar->doAnim(Animation::walk, direction);
+ ProcId standpid = avatar->doAnim(Animation::stand, direction);
+ Process *standproc = Kernel::get_instance()->getProcess(standpid);
+ standproc->waitFor(walkpid);
+ waitFor(standpid);
+ return;
+ }
+
+ // TODO: if we were hanging, fall
+ }
+
+ // can't do any new actions if in stasis
+ if (stasis)
+ return;
+
+ // both mouse buttons down and not yet handled, check for jump.
+ if (!_mouseButton[0].isState(MBS_HANDLED) && !_mouseButton[1].isState(MBS_HANDLED)) {
+ // Take action if both were clicked within
+ // double-click timeout of each other.
+ // notice these are all unsigned.
+ uint32 down = _mouseButton[1]._curDown;
+ if (_mouseButton[0]._curDown < down) {
+ down = down - _mouseButton[0]._curDown;
+ } else {
+ down = _mouseButton[0]._curDown - down;
+ }
+
+ if (down < DOUBLE_CLICK_TIMEOUT) {
+ // Both buttons pressed within the timeout
+ _mouseButton[0].setState(MBS_HANDLED);
+ _mouseButton[1].setState(MBS_HANDLED);
+ setMovementFlag(MOVE_JUMP);
+ }
+ }
+
+ if ((!_mouseButton[0].isState(MBS_HANDLED) || m0clicked) && hasMovementFlags(MOVE_ANY_DIRECTION | MOVE_STEP)) {
+ _mouseButton[0].setState(MBS_HANDLED);
+ // We got a left mouse down while already moving in any direction or holding the step button.
+ // CHECKME: check what needs to happen when keeping left pressed
+ setMovementFlag(MOVE_JUMP);
+ }
+
+ if (_mouseButton[1].isUnhandledDoubleClick()) {
+ Gump *desktopgump = Ultima8Engine::get_instance()->getDesktopGump();
+ if (desktopgump->TraceObjId(mx, my) == 1) {
+ // double right click on avatar = toggle combat mode
+ _mouseButton[1].setState(MBS_HANDLED);
+ _mouseButton[1]._lastDown = 0;
+
+ avatar->toggleInCombat();
+ waitFor(avatar->doAnim(Animation::readyWeapon, direction));
+ return;
+ }
+ }
+
+ if (hasMovementFlags(MOVE_JUMP) && hasMovementFlags(MOVE_ANY_DIRECTION)) {
+ clearMovementFlag(MOVE_JUMP);
+
+ if (hasMovementFlags(MOVE_MOUSE_DIRECTION)) {
+ if (checkTurn(mousedir, false))
+ return;
+ }
+
+ Animation::Sequence nextanim = Animation::jump;
+ // check if we need to do a running jump
+ if (lastanim == Animation::run || lastanim == Animation::runningJump) {
+ nextanim = Animation::runningJump;
+ }
+ else if (avatar->hasActorFlags(Actor::ACT_AIRWALK)) {
+ nextanim = Animation::airwalkJump;
+ }
+ else if ((hasMovementFlags(MOVE_MOUSE_DIRECTION) && mouselength == 0) || hasMovementFlags(MOVE_STEP)) {
+ nextanim = Animation::jumpUp;
+ }
+
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+ return;
+ }
+
+ if (hasMovementFlags(MOVE_JUMP)) {
+ clearMovementFlag(MOVE_JUMP);
+
+ if (checkTurn(mousedir, false))
+ return;
+
+ Animation::Sequence nextanim = Animation::jumpUp;
+ if (mouselength > 0) {
+ nextanim = Animation::jump;
+ }
+
+ // check if there's something we can climb up onto here
+ Animation::Sequence climbanim = Animation::climb72;
+ while (climbanim >= Animation::climb16) {
+ if (avatar->tryAnim(climbanim, direction) ==
+ Animation::SUCCESS) {
+ nextanim = climbanim;
+ }
+ climbanim = static_cast<Animation::Sequence>(climbanim - 1);
+ }
+
+ if (nextanim == Animation::jump) {
+ jump(Animation::jump, direction);
+ }
+ else {
+ if (nextanim != Animation::jumpUp) {
+ // climbing gives str/dex
+ avatar->accumulateStr(2 + nextanim - Animation::climb16);
+ avatar->accumulateDex(2 * (2 + nextanim - Animation::climb16));
+ }
+ nextanim = Animation::checkWeapon(nextanim, lastanim);
+ waitFor(avatar->doAnim(nextanim, direction));
+ }
+ return;
+ }
+
+ if (hasMovementFlags(MOVE_MOUSE_DIRECTION)) {
+ Animation::Sequence nextanim = Animation::step;
+
+ if (mouselength == 1) {
+ nextanim = Animation::walk;
+ } else if (mouselength == 2) {
+ if (lastanim == Animation::run
+ || lastanim == Animation::runningJump
+ || lastanim == Animation::walk)
+ nextanim = Animation::run;
+ else
+ nextanim = Animation::walk;
+ }
+
+ step(nextanim, mousedir);
+ return;
+ }
+
+ if (m1clicked)
+ if (checkTurn(mousedir, false))
+ return;
+
+ bool moving = (lastanim == Animation::step || lastanim == Animation::run || lastanim == Animation::walk);
+
+ DirectionMode dirmode = avatar->animDirMode(Animation::step);
+
+ // 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_OneLeft(direction, dirmode);
+ }
+
+ if (hasMovementFlags(MOVE_TURN_RIGHT)) {
+ direction = Direction_OneRight(direction, dirmode);
+ }
+ }
+
+ Animation::Sequence nextanim = Animation::walk;
+
+ if (hasMovementFlags(MOVE_STEP)) {
+ nextanim = Animation::step;
+ } else if (hasMovementFlags(MOVE_RUN)) {
+ if (lastanim == Animation::run
+ || lastanim == Animation::runningJump
+ || lastanim == Animation::walk)
+ nextanim = Animation::run;
+ else
+ nextanim = Animation::walk;
+ }
+
+ if (hasMovementFlags(MOVE_FORWARD)) {
+ step(nextanim, direction);
+ return;
+ }
+
+ if (hasMovementFlags(MOVE_BACK)) {
+ step(nextanim, Direction_Invert(direction));
+
+ // flip to move forward once turned
+ setMovementFlag(MOVE_FORWARD);
+ return;
+ }
+
+ int y = 0;
+ int x = 0;
+ if (hasMovementFlags(MOVE_UP)) {
+ y++;
+ }
+ if (hasMovementFlags(MOVE_DOWN)) {
+ y--;
+ }
+ if (hasMovementFlags(MOVE_LEFT)) {
+ x--;
+ }
+ if (hasMovementFlags(MOVE_RIGHT)) {
+ x++;
+ }
+
+ if (x != 0 || y != 0) {
+ direction = Direction_Get(y, x, dirmode_8dirs);
+ step(nextanim, direction);
+ return;
+ }
+
+ if (checkTurn(direction, moving))
+ return;
+
+ // doing another animation?
+ if (Kernel::get_instance()->getNumProcesses(1, ActorAnimProcess::ACTOR_ANIM_PROC_TYPE))
+ return;
+
+ // if we were running, slow to a walk before stopping
+ if (lastanim == Animation::run) {
+ waitFor(avatar->doAnim(Animation::walk, direction));
+ return;
+ }
+
+ // not doing anything in particular? stand
+ if (lastanim != Animation::stand && currentIdleTime == 0) {
+ waitFor(avatar->doAnim(Animation::stand, direction));
+ return;
+ }
+
+ // idle
+ _idleTime = currentIdleTime + 1;
+
+ // currently shaking head?
+ if (lastanim == Animation::lookLeft || lastanim == Animation::lookRight) {
+ if ((getRandom() % 1500) + 30 < _idleTime) {
+ _lastHeadShakeAnim = lastanim;
+ waitFor(avatar->doAnim(Animation::stand, direction));
+ _idleTime = 1;
+ return;
+ }
+ } else {
+ if ((getRandom() % 3000) + 150 < _idleTime) {
+ if (getRandom() % 5 == 0)
+ nextanim = _lastHeadShakeAnim;
+ else if (_lastHeadShakeAnim == Animation::lookLeft)
+ nextanim = Animation::lookRight;
+ else
+ nextanim = Animation::lookLeft;
+ waitFor(avatar->doAnim(nextanim, direction));
+ _idleTime = 1;
+ return;
+ }
+ }
+}
+
+void U8AvatarMoverProcess::step(Animation::Sequence action, Direction direction,
+ bool adjusted) {
+ assert(action == Animation::step || action == Animation::walk ||
+ action == Animation::run);
+
+ MainActor *avatar = getMainActor();
+ Animation::Sequence lastanim = avatar->getLastAnim();
+
+ Animation::Result res = avatar->tryAnim(action, 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);
+ Direction altdir1 = Direction_OneRight(stepdir, dirmode_8dirs);
+ Direction altdir2 = Direction_OneLeft(stepdir, dirmode_8dirs);
+
+ res = avatar->tryAnim(action, altdir1);
+ if (res == Animation::FAILURE ||
+ (action == Animation::step && res == Animation::END_OFF_LAND)) {
+ debug(6, "Step: end off land dir %d, altdir1 %d failed, try altdir2 %d", stepdir, altdir1, altdir2);
+ res = avatar->tryAnim(action, altdir2);
+ if (res == Animation::FAILURE ||
+ (action == Animation::step && res == Animation::END_OFF_LAND)) {
+ // Can't walk in this direction.
+ // Try to take a smaller step
+
+ if (action == Animation::walk) {
+ debug(6, "Step: end off land both altdirs failed, smaller step (step)");
+ step(Animation::step, direction, true);
+ return;
+ } else if (action == Animation::run) {
+ debug(6, "Step: end off land both altdirs failed, smaller step (walk)");
+ step(Animation::walk, direction, true);
+ return;
+ }
+
+ } else {
+ stepdir = altdir2;
+ }
+ } else {
+ stepdir = altdir1;
+ }
+ }
+
+ if (action == Animation::step && res == Animation::END_OFF_LAND &&
+ lastanim != Animation::keepBalance && !adjusted) {
+ if (checkTurn(stepdir, false))
+ return;
+ debug(6, "Step: end off land both altdirs failed, keep balance.");
+ waitFor(avatar->doAnim(Animation::keepBalance, stepdir));
+ return;
+ }
+
+ if (action == Animation::step && res == Animation::FAILURE) {
+ action = Animation::stand;
+ }
+
+
+ bool moving = (action == Animation::run || action == Animation::walk);
+
+ if (checkTurn(stepdir, moving))
+ return;
+
+ debug(6, "Step: step ok: action %d dir %d", action, stepdir);
+ action = Animation::checkWeapon(action, lastanim);
+ waitFor(avatar->doAnim(action, stepdir));
+}
+
+void U8AvatarMoverProcess::jump(Animation::Sequence action, Direction direction) {
+ MainActor *avatar = getMainActor();
+
+ // running jump
+ if (action == Animation::runningJump) {
+ waitFor(avatar->doAnim(action, direction));
+ return;
+ }
+
+ // airwalk
+ if (avatar->hasActorFlags(Actor::ACT_AIRWALK) &&
+ action == Animation::jump) {
+ waitFor(avatar->doAnim(Animation::airwalkJump, direction));
+ return;
+ }
+
+ bool targeting;
+ SettingManager::get_instance()->get("targetedjump", targeting);
+
+ if (targeting) {
+ Mouse *mouse = Mouse::get_instance();
+ int32 coords[3];
+ int32 mx, my;
+ mouse->getMouseCoords(mx, my);
+ GameMapGump *gameMap = Ultima8Engine::get_instance()->getGameMapGump();
+ // We need the Gump's x/y for TraceCoordinates
+ gameMap->ScreenSpaceToGump(mx, my);
+ ObjId targetId = gameMap->TraceCoordinates(mx, my, coords);
+ Item *target = getItem(targetId);
+
+ int32 ax, ay, az;
+ avatar->getCentre(ax, ay, az);
+
+ int32 xrange = abs(ax - coords[0]);
+ int32 yrange = abs(ay - coords[1]);
+ int maxrange = avatar->getStr() * 32;
+
+ if (target && target->getShapeInfo()->is_land() &&
+ xrange < maxrange && yrange < maxrange) {
+ // Original also only lets you jump at the Z_FACE
+ Process *p = new TargetedAnimProcess(avatar, Animation::jumpUp,
+ direction, coords);
+ waitFor(Kernel::get_instance()->addProcess(p));
+ return;
+ }
+ // invalid target or out of range
+ waitFor(avatar->doAnim(Animation::shakeHead, direction));
+ } else {
+ waitFor(avatar->doAnim(Animation::jump, direction));
+ }
+}
+
+bool U8AvatarMoverProcess::canAttack() {
+ MainActor *avatar = getMainActor();
+ return (_lastFrame > _lastAttack + (25 - avatar->getDex()));
+}
+
+void U8AvatarMoverProcess::tryAttack() {
+ MainActor *avatar = getMainActor();
+ Direction dir = avatar->getDir();
+ if (!avatar->isInCombat()) {
+ avatar->setInCombat(0);
+ waitFor(avatar->doAnim(Animation::readyWeapon, dir));
+ } else {
+ if (canAttack()) {
+ waitFor(avatar->doAnim(Animation::attack, dir));
+ }
+ }
+}
+
+void U8AvatarMoverProcess::saveData(Common::WriteStream *ws) {
+ AvatarMoverProcess::saveData(ws);
+ // Note: this field used to be the last thing saved in AvatarMoverProcess,
+ // so this relies on it being in the right order here (and loadData) for
+ // backwards compatibility.
+ ws->writeUint16LE(static_cast<uint8>(_lastHeadShakeAnim));
+}
+
+bool U8AvatarMoverProcess::loadData(Common::ReadStream *rs, uint32 version) {
+ if (!AvatarMoverProcess::loadData(rs, version)) return false;
+
+ _lastHeadShakeAnim = static_cast<Animation::Sequence>(rs->readUint16LE());
+
+ return true;
+}
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
diff --git a/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.h b/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.h
new file mode 100644
index 0000000000..81fd454068
--- /dev/null
+++ b/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.h
@@ -0,0 +1,68 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WORLD_ACTORS_U8AVATARMOVERPROCESS_H
+#define WORLD_ACTORS_U8AVATARMOVERPROCESS_H
+
+#include "ultima/ultima8/kernel/process.h"
+#include "ultima/ultima8/world/actors/animation.h"
+#include "ultima/ultima8/world/actors/avatar_mover_process.h"
+
+namespace Ultima {
+namespace Ultima8 {
+
+/**
+ * Mover process that replicates the feel of U8 - moving, combat, jumps, etc.
+ * Tries turning one quarter turn if movement is blocked. Running temporarily
+ * stops combat and plays some special movement.
+ */
+class U8AvatarMoverProcess : public AvatarMoverProcess {
+public:
+ U8AvatarMoverProcess();
+ ~U8AvatarMoverProcess();
+
+ // p_dynamic_cast stuff
+ ENABLE_RUNTIME_CLASSTYPE()
+
+ bool loadData(Common::ReadStream *rs, uint32 version);
+ void saveData(Common::WriteStream *ws) override;
+
+ void tryAttack() override;
+
+protected:
+ void handleHangingMode() override;
+ void handleCombatMode() override;
+ void handleNormalMode() override;
+ bool canAttack() override;
+
+ void step(Animation::Sequence action, Direction direction, bool adjusted = false);
+ void jump(Animation::Sequence action, Direction direction);
+
+private:
+ Animation::Sequence _lastHeadShakeAnim;
+
+};
+
+} // End of namespace Ultima8
+} // End of namespace Ultima
+
+#endif
Commit: df46296f02c70aa2936d0c905d7d805ea3c04be8
https://github.com/scummvm/scummvm/commit/df46296f02c70aa2936d0c905d7d805ea3c04be8
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-12-24T14:00:15+09:00
Commit Message:
ULTIMA8: Add 16 dir support for Direction_Get
Changed paths:
engines/ultima/ultima8/misc/direction_util.h
diff --git a/engines/ultima/ultima8/misc/direction_util.h b/engines/ultima/ultima8/misc/direction_util.h
index 75fd8f0875..02892b47b6 100644
--- a/engines/ultima/ultima8/misc/direction_util.h
+++ b/engines/ultima/ultima8/misc/direction_util.h
@@ -25,6 +25,7 @@
#include "ultima/ultima8/misc/direction.h"
#include "ultima/ultima8/ultima8.h"
+#include "common/math.h"
namespace Ultima {
namespace Ultima8 {
@@ -69,23 +70,46 @@ inline int Direction_YFactor(Direction dir) {
inline Direction Direction_Get(int deltay, int deltax, DirectionMode dirmode) {
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
+
+ if (dirmode == dirmode_8dirs) {
+ 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 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;
+ else // Top-left
+ return dydx >= -424 ? dir_southwest : dydx >= -2472 ? dir_west
+ : dir_northwest;
+ } else {
+ double angle = Common::rad2deg(atan2(deltay, deltax));
+ if (angle < 11.25) return dir_northwest;
+ else if (angle < 33.75) return dir_nnw;
+ else if (angle < 56.25) return dir_north;
+ else if (angle < 78.75) return dir_nne;
+ else if (angle < 101.25) return dir_northeast;
+ else if (angle < 123.75) return dir_ene;
+ else if (angle < 146.25) return dir_east;
+ else if (angle < 168.75) return dir_ese;
+ else if (angle < 191.25) return dir_southeast;
+ else if (angle < 213.75) return dir_sse;
+ else if (angle < 236.25) return dir_south;
+ else if (angle < 258.75) return dir_ssw;
+ else if (angle < 281.25) return dir_southwest;
+ else if (angle < 303.75) return dir_wsw;
+ else if (angle < 326.25) return dir_west;
+ else if (angle < 348.75) return dir_wnw;
+ return dir_northwest;
+ }
}
inline Direction Direction_GetWorldDir(int deltay, int deltax, DirectionMode dirmode) {
+ // TODO: Implement 16 directions here.
if (deltax == 0) {
if (deltay == 0) return dir_northeast; // for better compatibility with U8
return deltay > 0 ? dir_south : dir_north;
Commit: ebae8ca44bc1c1cb06b2471bb4e64b8d0570695c
https://github.com/scummvm/scummvm/commit/ebae8ca44bc1c1cb06b2471bb4e64b8d0570695c
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-12-24T14:00:15+09:00
Commit Message:
ULTIMA8: Fix crusader firing in a few ways:
* Remove explicit call to fire, as it is called from animation
* Fix fire z value from anim flags (should be unsigned)
* Use correct starting location in firedistance intrinsic
Changed paths:
engines/ultima/ultima8/world/actors/actor_anim_process.cpp
engines/ultima/ultima8/world/actors/anim_action.h
engines/ultima/ultima8/world/actors/cru_avatar_mover_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/super_sprite_process.h
diff --git a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
index 8673129ac9..9762e5dd9b 100644
--- a/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
+++ b/engines/ultima/ultima8/world/actors/actor_anim_process.cpp
@@ -514,7 +514,7 @@ void ActorAnimProcess::doFireWeaponCru(Actor *a, const AnimFrame *f) {
return;
a->fireWeapon(f->cru_attackx(), f->cru_attacky(), f->cru_attackz(),
- dir_current, wpninfo->_weaponInfo->_damageType, 1);
+ a->getDir(), wpninfo->_weaponInfo->_damageType, 1);
AudioProcess *audioproc = AudioProcess::get_instance();
if (audioproc)
diff --git a/engines/ultima/ultima8/world/actors/anim_action.h b/engines/ultima/ultima8/world/actors/anim_action.h
index 683cd9ae2c..5420eadfc6 100644
--- a/engines/ultima/ultima8/world/actors/anim_action.h
+++ b/engines/ultima/ultima8/world/actors/anim_action.h
@@ -71,7 +71,7 @@ struct AnimFrame {
}
// Note: The next 3 functions each have a 4-bit
- // signed value to unpack from the flags.
+ // value to unpack from the flags. x/y are signed, z is unsigned.
inline int cru_attackx() const {
uint32 rawx = (_flags & 0x00000780) << 5;
int16 signedx = static_cast<int16>(rawx) >> 12;
@@ -84,8 +84,7 @@ struct AnimFrame {
}
inline int cru_attackz() const {
- uint32 rawz = (_flags & 0x0F000000) >> 20;
- return static_cast<int8>(rawz) / 2;
+ return (_flags & 0x0F000000) >> 21;
}
inline bool is_cruattack() const {
diff --git a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
index 82b0b19c19..b96306468c 100644
--- a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -428,11 +428,8 @@ void CruAvatarMoverProcess::tryAttack() {
waitFor(avatar->doAnim(Animation::readyWeapon, dir));
} else {
if (canAttack()) {
+ // Fire event happens from animation
waitFor(avatar->doAnim(Animation::attack, dir));
- // FIXME: put some real values in here.
- int32 xs, ys, zs;
- avatar->getFootpadWorld(xs, ys, zs);
- avatar->fireWeapon(xs / 2, ys / 2, zs / 2, dir, 1, 1);
}
}
}
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index ccda99b3cd..09421a4c87 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -36,6 +36,7 @@
#include "ultima/ultima8/gumps/game_map_gump.h"
#include "ultima/ultima8/graphics/main_shape_archive.h"
#include "ultima/ultima8/graphics/gump_shape_archive.h"
+#include "ultima/ultima8/graphics/anim_dat.h"
#include "ultima/ultima8/graphics/shape.h"
#include "ultima/ultima8/graphics/shape_info.h"
#include "ultima/ultima8/world/item_factory.h"
@@ -67,6 +68,7 @@
#include "ultima/ultima8/world/actors/main_actor.h"
#include "ultima/ultima8/world/missile_tracker.h"
#include "ultima/ultima8/world/crosshair_process.h"
+#include "ultima/ultima8/world/actors/anim_action.h"
namespace Ultima {
namespace Ultima8 {
@@ -1153,7 +1155,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, Direction dir, int firetype, char someflag) {
+uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, char findtarget) {
int32 ix, iy, iz;
getLocation(ix, iy, iz);
@@ -1214,6 +1216,7 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
// HACK: this should be fixed to use inheritence so the behavior
// is clean for both Item and Actor.
+ DirectionMode dirmode = dirmode_8dirs;
const Actor *thisactor = dynamic_cast<Actor *>(this);
if (thisactor) {
// TODO: Get damage for active inventory item, and dirmode of last
@@ -1221,12 +1224,15 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
}
Item *target = nullptr;
- if (someflag) {
+ if (findtarget) {
if (this != getControlledActor()) {
target = getControlledActor();
} else {
// TODO: this should be dirmode of last animation (above)
- target = currentmap->findBestTargetItem(ix, iy, dir, dirmode_8dirs);
+ // for now, hack for avatar
+ if (thisactor->getShape() == 1 && thisactor->isInCombat())
+ dirmode = dirmode_16dirs;
+ target = currentmap->findBestTargetItem(ix, iy, dir, dirmode);
}
}
@@ -1234,29 +1240,8 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
int32 ty = 0;
int32 tz = 0;
if (target) {
- int32 tsx, tsy, tsz;
target->getCentre(tx, ty, tz);
- target->getFootpadData(tsx, tsy, tsz);
-
- tz = target->getZ() + tsz * 8;
-
- if (tsz < 3) {
- if (tsz)
- tz -= 8;
- } else {
- int32 targetz = tz;
- int32 thisz = getZ();
- tz -= 16;
- if (thisz - targetz < -0x2f) {
- tz += 8;
- } else if (thisz - targetz > 0x2f) {
- if (tsz == 6) {
- tz -= 16;
- } else if (tsz >= 7) {
- tz -= 24;
- }
- }
- }
+ tz = target->getTargetZRelativeToAttackerZ(getZ());
}
// TODO: check if we need the equivalent of FUN_1130_0299 here..
@@ -1292,7 +1277,7 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
uint16 targetid = (target ? target->getObjId() : 0);
ssp = new SuperSpriteProcess(BULLET_SPLASH_SHAPE, spriteframe,
ix, iy, iz, ssx, ssy, ssz, firetype,
- damage, _objId, targetid, someflag);
+ damage, _objId, targetid, findtarget);
Kernel::get_instance()->addProcess(ssp);
spriteprocpid = ssp->getPid();
}
@@ -1304,6 +1289,20 @@ uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, in
if (!other)
return 0;
+ //
+ // We pick what animation the actor would do to fire, then
+ // pick the frame(s) where they fire in that anim.
+ //
+ // Then, check if the target can be hit using the attackx/attacky/attackz offsets.
+ // The offsets are checked in priority order:
+ // * First fire frame in anim
+ // * Second fire frame
+ // * if there are no fire frames, use the parameter offsets
+ //
+ int16 xoff2 = 0;
+ int16 yoff2 = 0;
+ int16 zoff2 = 0;
+ bool other_offsets = false;
Actor *a = dynamic_cast<Actor *>(this);
if (a) {
Animation::Sequence anim;
@@ -1327,11 +1326,29 @@ uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, in
anim = Animation::fire2;
}
- // TODO: Get midpoint of frames in anim. For now we ignore it and get the centre below.
+ bool first_offsets = false;
+ const AnimAction *action = GameData::get_instance()->getMainShapes()->getAnim(_shape, static_cast<int32>(anim));
+ for (unsigned int i = 0; i < action->getSize(); i++) {
+ const AnimFrame &frame = action->getFrame(dir, i);
+ if (frame.is_cruattack()) {
+ if (!first_offsets) {
+ xoff = frame.cru_attackx();
+ yoff = frame.cru_attacky();
+ zoff = frame.cru_attackz();
+ first_offsets = true;
+ } else {
+ xoff2 = frame.cru_attackx();
+ yoff2 = frame.cru_attacky();
+ zoff2 = frame.cru_attackz();
+ other_offsets = true;
+ break;
+ }
+ }
+ }
}
- int32 cx, cy, cz;
- getCentre(cx, cy, cz);
+ int32 x, y, z;
+ getLocation(x, y, z);
int32 ox, oy, oz;
other->getLocation(ox, oy, oz);
@@ -1341,37 +1358,70 @@ uint16 Item::fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, in
CurrentMap *cm = World::get_instance()->getCurrentMap();
if (!cm)
return 0;
- const Item *blocker = nullptr;
- bool valid = cm->isValidPosition(cx, cy, cz, BULLET_SPLASH_SHAPE,
- getObjId(), nullptr, nullptr, &blocker);
- if (!valid) {
- if (blocker->getObjId() == other->getObjId())
- dist = MAX(abs(_x - ox), abs(_y - oy));
- } else {
- int32 ocx, ocy, ocz;
- other->getCentre(ocx, ocy, ocz);
- const int32 start[3] = {cx, cy, cz};
- const int32 end[3] = {ocx, ocy, cz};
- const int32 dims[3] = { 2, 2, 2 };
-
- Std::list<CurrentMap::SweepItem> collisions;
- Std::list<CurrentMap::SweepItem>::iterator it;
- cm->sweepTest(start, end, dims, ShapeInfo::SI_SOLID,
- _objId, false, &collisions);
- for (it = collisions.begin(); it != collisions.end(); it++) {
- if (it->_item == getObjId())
- continue;
- if (it->_item != other->getObjId())
+
+ for (int i = 0; i < (other_offsets ? 2 : 1) && dist == 0; i++) {
+ int32 cx = x + (i == 0 ? xoff : xoff2);
+ int32 cy = y + (i == 0 ? yoff : yoff2);
+ int32 cz = z + (i == 0 ? zoff : zoff2);
+ const Item *blocker = nullptr;
+ bool valid = cm->isValidPosition(cx, cy, cz, BULLET_SPLASH_SHAPE,
+ getObjId(), nullptr, nullptr, &blocker);
+ if (!valid) {
+ if (blocker->getObjId() == other->getObjId())
+ dist = MAX(abs(_x - ox), abs(_y - oy));
+ } else {
+ int32 ocx, ocy, ocz;
+ other->getCentre(ocx, ocy, ocz);
+ ocz = other->getTargetZRelativeToAttackerZ(getZ());
+ const int32 start[3] = {cx, cy, cz};
+ const int32 end[3] = {ocx, ocy, ocz};
+ const int32 dims[3] = {2, 2, 2};
+
+ Std::list<CurrentMap::SweepItem> collisions;
+ Std::list<CurrentMap::SweepItem>::iterator it;
+ cm->sweepTest(start, end, dims, ShapeInfo::SI_SOLID,
+ _objId, false, &collisions);
+ for (it = collisions.begin(); it != collisions.end(); it++) {
+ if (it->_item == getObjId())
+ continue;
+ if (it->_item != other->getObjId())
+ break;
+ int32 out[3];
+ it->GetInterpolatedCoords(out, start, end);
+ dist = MAX(abs(_x - out[0]), abs(_y - out[1]));
break;
- int32 out[3];
- it->GetInterpolatedCoords(out, start, end);
- dist = MAX(abs(_x - out[0]), abs(_y - out[1]));
- break;
+ }
}
}
return dist / 32;
}
+int32 Item::getTargetZRelativeToAttackerZ(int32 otherz) {
+ int32 tsx, tsy, tsz;
+ getFootpadData(tsx, tsy, tsz);
+
+ int32 tz = getZ() + tsz * 8;
+
+ if (tsz < 3) {
+ if (tsz)
+ tz -= 8;
+ } else {
+ int32 targetz = tz;
+ tz -= 16;
+ if (otherz - targetz < -0x2f) {
+ tz += 8;
+ } else if (otherz - targetz > 0x2f) {
+ if (tsz == 6) {
+ tz -= 16;
+ } else if (tsz >= 7) {
+ tz -= 24;
+ }
+ }
+ }
+ return tz;
+}
+
+
unsigned int Item::countNearby(uint32 shape, uint16 range) {
CurrentMap *currentmap = World::get_instance()->getCurrentMap();
UCList itemlist(2);
diff --git a/engines/ultima/ultima8/world/item.h b/engines/ultima/ultima8/world/item.h
index eeba0b5314..2b7c74a4b8 100644
--- a/engines/ultima/ultima8/world/item.h
+++ b/engines/ultima/ultima8/world/item.h
@@ -388,9 +388,10 @@ public:
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, Direction dir, int firetype, char someflag);
+ uint16 fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, char findtarget);
- //! get the distance (in map tiles) if we were to fire in this direction
+ //! get the distance (in map tiles) if we were to fire in this direction to "other"
+ //! and could hit, otherwise return 0.
uint16 fireDistance(Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff);
//! get damage points, used in Crusader for item damage.
@@ -656,6 +657,10 @@ private:
//! The Crusader version of receiveHit
void receiveHitCru(ObjId other, Direction dir, int damage, uint16 type);
+ //! Get the right Z which an attacker should aim for, given the attacker's z.
+ //! (Crusader only)
+ int32 getTargetZRelativeToAttackerZ(int32 attackerz);
+
public:
enum statusflags {
FLG_DISPOSABLE = 0x0002, //!< Item is discarded on map change
diff --git a/engines/ultima/ultima8/world/super_sprite_process.cpp b/engines/ultima/ultima8/world/super_sprite_process.cpp
index cfeeefb7ce..91dccd334c 100644
--- a/engines/ultima/ultima8/world/super_sprite_process.cpp
+++ b/engines/ultima/ultima8/world/super_sprite_process.cpp
@@ -57,7 +57,7 @@ SuperSpriteProcess::SuperSpriteProcess() : Process(),
SuperSpriteProcess::SuperSpriteProcess(int shape, int frame, int sx, int sy, int sz,
int dx, int dy, int dz,
uint16 firetype, uint16 damage, uint16 source,
- uint16 target, uint8 spread) :
+ uint16 target, bool inexact) :
_shape(shape), _frame(frame), _startpt(sx, sy, sz), _destpt(dx, dy, dz),
_nextpt(sx, sy, sz), _fireType(firetype), _damage(damage), _source(source),
_target(target), _counter(1), _item0x77(0), _spriteNo(0),
@@ -67,9 +67,9 @@ SuperSpriteProcess::SuperSpriteProcess(int shape, int frame, int sx, int sy, int
const FireType *firetypedat = GameData::get_instance()->getFireType(firetype);
assert(firetypedat);
if (firetypedat->getAccurate()) {
- spread = 0;
+ inexact = false;
}
- if (spread) {
+ if (inexact) {
int rng = _startpt.maxDistXYZ(_destpt);
Item *srcitem = getItem(source);
if (srcitem == getControlledActor()) {
diff --git a/engines/ultima/ultima8/world/super_sprite_process.h b/engines/ultima/ultima8/world/super_sprite_process.h
index a59455e2f4..162284b011 100644
--- a/engines/ultima/ultima8/world/super_sprite_process.h
+++ b/engines/ultima/ultima8/world/super_sprite_process.h
@@ -73,10 +73,11 @@ public:
//! \param dx Dest X coord of the sprite in the world
//! \param dy Dest Y coord of the sprite in the world
//! \param dz Dest Z coord of the sprite in the world
+ //! \param inexact true if the destination is not exactly chosen
//!
SuperSpriteProcess(int shape, int frame, int sx, int sy, int sz,
int dx, int dy, int dz, uint16 firetype,
- uint16 damage, uint16 source, uint16 target, uint8 flag);
+ uint16 damage, uint16 source, uint16 target, bool inexact);
//! The SuperSpriteProcess destructor
~SuperSpriteProcess(void) override;
Commit: bf4f61b35615f628d90e23b6cf558e683d03c549
https://github.com/scummvm/scummvm/commit/bf4f61b35615f628d90e23b6cf558e683d03c549
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-12-24T15:08:51+09:00
Commit Message:
ULTIMA8: Crusader: Fix robot death and make absolute anims a bit cleaner.
Changed paths:
engines/ultima/ultima8/graphics/anim_dat.cpp
engines/ultima/ultima8/world/actors/actor.cpp
engines/ultima/ultima8/world/actors/animation.h
engines/ultima/ultima8/world/item.cpp
diff --git a/engines/ultima/ultima8/graphics/anim_dat.cpp b/engines/ultima/ultima8/graphics/anim_dat.cpp
index cd8f8730c8..4ced82e13b 100644
--- a/engines/ultima/ultima8/graphics/anim_dat.cpp
+++ b/engines/ultima/ultima8/graphics/anim_dat.cpp
@@ -83,12 +83,12 @@ uint32 AnimDat::getActionNumberForSequence(Animation::Sequence action, const Act
//
// We also translate based on weapon. See the function at 1128:2104
//
- // First, if the animation is >= 0x1000 then it's from the usecode -
- // use directly and don't translate.
+ // First, if the animation includes the Animation::crusaderAbsoluteAnimFlag
+ // bitmask then it's from the usecode - use directly and don't translate.
//
const uint32 action_int = static_cast<uint32>(action);
- if (action_int >= 0x1000)
- return action_int - 0x1000;
+ if (action_int & Animation::crusaderAbsoluteAnimFlag)
+ return action_int - Animation::crusaderAbsoluteAnimFlag;
switch (action) {
case Animation::stand:
@@ -119,7 +119,7 @@ uint32 AnimDat::getActionNumberForSequence(Animation::Sequence action, const Act
case Animation::fallBackwards:
return 18;
case Animation::die:
- return 20; // maybe? falls over forwards
+ return 18; // by default fall over backwards. TODO: randomly use 20 for some deaths - fall forwards.
case Animation::advance:
return (smallwpn ? 36 : 44);
case Animation::startKneeling:
diff --git a/engines/ultima/ultima8/world/actors/actor.cpp b/engines/ultima/ultima8/world/actors/actor.cpp
index 8e9285503c..270640b7ae 100644
--- a/engines/ultima/ultima8/world/actors/actor.cpp
+++ b/engines/ultima/ultima8/world/actors/actor.cpp
@@ -1128,20 +1128,22 @@ ProcId Actor::die(uint16 damageType) {
MusicProcess::get_instance()->queueMusic(98);
}
} else if (GAME_IS_CRUSADER) {
- uint16 sfxno;
- static const uint16 FADING_SCREAM_SFX[] = { 0xD9, 0xDA };
- static const uint16 MALE_DEATH_SFX[] = { 0x88, 0x8C, 0x8F };
- static const uint16 FEMALE_DEATH_SFX[] = { 0xD8, 0x10 };
- if (damageType == 0xf) {
- sfxno = FADING_SCREAM_SFX[getRandom() % 2];
- } else {
- if (hasExtFlags(EXT_FEMALE)) {
- sfxno = FEMALE_DEATH_SFX[getRandom() % 2];
+ if (!isRobotCru()) {
+ uint16 sfxno;
+ static const uint16 FADING_SCREAM_SFX[] = { 0xD9, 0xDA };
+ static const uint16 MALE_DEATH_SFX[] = { 0x88, 0x8C, 0x8F };
+ static const uint16 FEMALE_DEATH_SFX[] = { 0xD8, 0x10 };
+ if (damageType == 0xf) {
+ sfxno = FADING_SCREAM_SFX[getRandom() % 2];
} else {
- sfxno = MALE_DEATH_SFX[getRandom() % 3];
+ if (hasExtFlags(EXT_FEMALE)) {
+ sfxno = FEMALE_DEATH_SFX[getRandom() % 2];
+ } else {
+ sfxno = MALE_DEATH_SFX[getRandom() % 3];
+ }
}
+ AudioProcess::get_instance()->playSFX(sfxno, 0x10, _objId, 0, true);
}
- AudioProcess::get_instance()->playSFX(sfxno, 0x10, _objId, 0, true);
}
destroyContents();
@@ -1680,11 +1682,11 @@ uint32 Actor::I_doAnim(const uint8 *args, unsigned int /*argsize*/) {
//
// HACK: In Crusader, we do translation on the animations so we want to remap
- // most of them, but for direct commands from the usecode we add 0x1000 for
+ // most of them, but for direct commands from the usecode we add a bitflag for
// no remapping
//
if (GAME_IS_CRUSADER) {
- anim += 0x1000;
+ anim |= Animation::crusaderAbsoluteAnimFlag;
}
return actor->doAnim(static_cast<Animation::Sequence>(anim), Direction_FromUsecodeDir(dir));
diff --git a/engines/ultima/ultima8/world/actors/animation.h b/engines/ultima/ultima8/world/actors/animation.h
index 739cc36a7b..3469287b73 100644
--- a/engines/ultima/ultima8/world/actors/animation.h
+++ b/engines/ultima/ultima8/world/actors/animation.h
@@ -136,8 +136,10 @@ enum Sequence {
slowCombatRollLeft = 61,
slowCombatRollRight = 62,
finishFiring = 63,
- teleportInReplacement = 0x1020, //!< See notes in Actor::receiveHitCru
- teleportOutReplacement = 0x1021 //!< See notes in Actor::receiveHitCru
+
+ crusaderAbsoluteAnimFlag = 0x1000, //!< Bit mask magic to say we want an exact number, don't do mapping from U8 animation numbers
+ teleportInReplacement = crusaderAbsoluteAnimFlag | teleportIn, //!< See notes in Actor::receiveHitCru
+ teleportOutReplacement = crusaderAbsoluteAnimFlag | teleportOut //!< See notes in Actor::receiveHitCru
};
enum Result {
diff --git a/engines/ultima/ultima8/world/item.cpp b/engines/ultima/ultima8/world/item.cpp
index 09421a4c87..37cdad8185 100644
--- a/engines/ultima/ultima8/world/item.cpp
+++ b/engines/ultima/ultima8/world/item.cpp
@@ -1219,8 +1219,8 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
DirectionMode dirmode = dirmode_8dirs;
const Actor *thisactor = dynamic_cast<Actor *>(this);
if (thisactor) {
- // TODO: Get damage for active inventory item, and dirmode of last
- // animation here (lines 185~208 of disasm)
+ // TODO: Get damage for active inventory item
+ dirmode = thisactor->animDirMode(thisactor->getLastAnim());
}
Item *target = nullptr;
@@ -1228,10 +1228,6 @@ uint16 Item::fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype,
if (this != getControlledActor()) {
target = getControlledActor();
} else {
- // TODO: this should be dirmode of last animation (above)
- // for now, hack for avatar
- if (thisactor->getShape() == 1 && thisactor->isInCombat())
- dirmode = dirmode_16dirs;
target = currentmap->findBestTargetItem(ix, iy, dir, dirmode);
}
}
Commit: 51c8f66d97cfeaeb6e28c44f027b6d97dc58cd75
https://github.com/scummvm/scummvm/commit/51c8f66d97cfeaeb6e28c44f027b6d97dc58cd75
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-12-24T19:02:25+09:00
Commit Message:
ULTIMA8: Provide quick helper functions for mouse
Changed paths:
engines/ultima/ultima8/kernel/mouse.cpp
engines/ultima/ultima8/kernel/mouse.h
diff --git a/engines/ultima/ultima8/kernel/mouse.cpp b/engines/ultima/ultima8/kernel/mouse.cpp
index cd0ff7df30..eb9997592b 100644
--- a/engines/ultima/ultima8/kernel/mouse.cpp
+++ b/engines/ultima/ultima8/kernel/mouse.cpp
@@ -139,7 +139,7 @@ bool Mouse::isMouseDownEvent(Shared::MouseButton button) const {
return _mouseButton[button].isState(MBS_DOWN);
}
-int Mouse::getMouseLength(int mx, int my) {
+int Mouse::getMouseLength(int mx, int my) const {
Rect dims;
RenderSurface *screen = Ultima8Engine::get_instance()->getRenderScreen();
screen->GetSurfaceDims(dims);
@@ -171,7 +171,7 @@ int Mouse::getMouseLength(int mx, int my) {
}
}
-Direction Mouse::getMouseDirectionWorld(int mx, int my) {
+Direction Mouse::getMouseDirectionWorld(int mx, int my) const {
Rect dims;
RenderSurface *screen = Ultima8Engine::get_instance()->getRenderScreen();
screen->GetSurfaceDims(dims);
@@ -183,7 +183,7 @@ Direction Mouse::getMouseDirectionWorld(int mx, int my) {
return Direction_Get(dy * 2, dx, dirmode_8dirs);
}
-Direction Mouse::getMouseDirectionScreen(int mx, int my) {
+Direction Mouse::getMouseDirectionScreen(int mx, int my) const {
return Direction_OneRight(getMouseDirectionWorld(mx, my), dirmode_8dirs);
}
@@ -222,7 +222,7 @@ int Mouse::getMouseFrame() {
}
// Calculate frame based on direction
- Direction mousedir = getMouseDirectionScreen(_mousePos.x, _mousePos.y);
+ Direction mousedir = getMouseDirectionScreen();
int frame = mouseFrameForDir(mousedir);
/** length --- frame offset
@@ -231,7 +231,7 @@ int Mouse::getMouseFrame() {
* 2 16
* combat 25
**/
- int offset = getMouseLength(_mousePos.x, _mousePos.y) * 8;
+ int offset = getMouseLength() * 8;
if (combat && offset != 16) //combat mouse is off if running
offset = 25;
return frame + offset;
diff --git a/engines/ultima/ultima8/kernel/mouse.h b/engines/ultima/ultima8/kernel/mouse.h
index d86946e731..28d8427a9c 100644
--- a/engines/ultima/ultima8/kernel/mouse.h
+++ b/engines/ultima/ultima8/kernel/mouse.h
@@ -150,13 +150,28 @@ public:
bool buttonUp(Shared::MouseButton button);
//! get mouse cursor length. 0 = short, 1 = medium, 2 = long
- int getMouseLength(int mx, int my);
+ int getMouseLength(int mx, int my) const;
+
+ //! get mouse cursor length for the current coordinates
+ int getMouseLength() const {
+ return getMouseLength(_mousePos.x, _mousePos.y);
+ }
//! get mouse cursor direction on the screen. 0 = up, 1 = up-right, 2 = right, etc...
- Direction getMouseDirectionScreen(int mx, int my);
+ Direction getMouseDirectionScreen(int mx, int my) const;
+
+ //! get mouse cursor direction on the screen using the current coordinates.
+ Direction getMouseDirectionScreen() const {
+ return getMouseDirectionScreen(_mousePos.x, _mousePos.y);
+ }
//! get mouse cursor direction in the world. 0 = up, 1 = up-right, 2 = right, etc...
- Direction getMouseDirectionWorld(int mx, int my);
+ Direction getMouseDirectionWorld(int mx, int my) const;
+
+ //! get mouse cursor direction in the world using the current coordinates.
+ Direction getMouseDirectionWorld() const {
+ return getMouseDirectionWorld(_mousePos.x, _mousePos.y);
+ }
//! get current mouse cursor location
void getMouseCoords(int32 &mx, int32 &my) const {
Commit: 404371365a81262f9af8796b80301f6ed8b3c5ab
https://github.com/scummvm/scummvm/commit/404371365a81262f9af8796b80301f6ed8b3c5ab
Author: Matthew Duggan (mgithub at guarana.org)
Date: 2020-12-24T19:15:58+09:00
Commit Message:
ULTIMA8: Reduce code duplication in mover procs
Changed paths:
engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
engines/ultima/ultima8/world/actors/avatar_mover_process.h
engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
index 195fa8d048..a49ee53ff8 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.cpp
@@ -86,25 +86,6 @@ void AvatarMoverProcess::run() {
}
-void AvatarMoverProcess::tryAttack() {
- MainActor *avatar = getMainActor();
- Direction dir = avatar->getDir();
- if (!avatar->isInCombat()) {
- avatar->setInCombat(0);
- waitFor(avatar->doAnim(Animation::readyWeapon, dir));
- } else {
- if (canAttack()) {
- waitFor(avatar->doAnim(Animation::attack, dir));
- if (GAME_IS_CRUSADER) {
- // FIXME: put some real values in here.
- int32 xs, ys, zs;
- avatar->getFootpadWorld(xs, ys, zs);
- avatar->fireWeapon(xs / 2, ys / 2, zs / 2, dir, 1, 1);
- }
- }
- }
-}
-
bool AvatarMoverProcess::checkTurn(Direction direction, bool moving) {
MainActor *avatar = getMainActor();
Direction curdir = avatar->getDir();
@@ -143,6 +124,66 @@ void AvatarMoverProcess::turnToDirection(Direction direction) {
waitFor(turnpid);
}
+void AvatarMoverProcess::slowFromRun(Direction direction) {
+ MainActor *avatar = getMainActor();
+ ProcId walkpid = avatar->doAnim(Animation::walk, direction);
+ ProcId standpid = avatar->doAnim(Animation::stand, direction);
+ Process *standproc = Kernel::get_instance()->getProcess(standpid);
+ standproc->waitFor(walkpid);
+ waitFor(standpid);
+}
+
+void AvatarMoverProcess::putAwayWeapon(Direction direction) {
+ MainActor *avatar = getMainActor();
+ ProcId anim1 = avatar->doAnim(Animation::unreadyWeapon, direction);
+ ProcId anim2 = avatar->doAnim(Animation::stand, direction);
+ Process *anim2p = Kernel::get_instance()->getProcess(anim2);
+ anim2p->waitFor(anim1);
+ waitFor(anim2);
+}
+
+bool AvatarMoverProcess::standUpIfNeeded(Direction direction) {
+ MainActor *avatar = getMainActor();
+ Animation::Sequence lastanim = avatar->getLastAnim();
+ bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
+
+ if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
+ if (!stasis) {
+ waitFor(avatar->doAnim(Animation::standUp, direction));
+ }
+ return true;
+ }
+ return false;
+}
+
+void AvatarMoverProcess::getMovementFlagAxes(int &x, int &y) {
+ y = 0;
+ x = 0;
+ if (hasMovementFlags(MOVE_UP)) {
+ y++;
+ }
+ if (hasMovementFlags(MOVE_DOWN)) {
+ y--;
+ }
+ if (hasMovementFlags(MOVE_LEFT)) {
+ x--;
+ }
+ if (hasMovementFlags(MOVE_RIGHT)) {
+ x++;
+ }
+}
+
+Direction AvatarMoverProcess::getTurnDirForTurnFlags(Direction direction, DirectionMode dirmode) {
+ if (hasMovementFlags(MOVE_TURN_LEFT)) {
+ direction = Direction_OneLeft(direction, dirmode);
+ }
+
+ if (hasMovementFlags(MOVE_TURN_RIGHT)) {
+ direction = Direction_OneRight(direction, dirmode);
+ }
+ return direction;
+}
+
void AvatarMoverProcess::onMouseDown(int button, int32 mx, int32 my) {
int bid = 0;
diff --git a/engines/ultima/ultima8/world/actors/avatar_mover_process.h b/engines/ultima/ultima8/world/actors/avatar_mover_process.h
index 1d4dd019d2..cb523d30e9 100644
--- a/engines/ultima/ultima8/world/actors/avatar_mover_process.h
+++ b/engines/ultima/ultima8/world/actors/avatar_mover_process.h
@@ -94,6 +94,22 @@ protected:
void turnToDirection(Direction direction);
bool checkTurn(Direction direction, bool moving);
+ // Walk and then stop in the given direction
+ void slowFromRun(Direction direction);
+
+ // Stow weapon and stand
+ void putAwayWeapon(Direction direction);
+
+ // If the last animation was falling or die but we're not dead, stand up!
+ // return true if we are waiting to get up
+ bool standUpIfNeeded(Direction direction);
+
+ // Get directions based on what movement flags are set, eg y=+1 for up, x=-1 for left.
+ void getMovementFlagAxes(int &x, int &y);
+
+ // Adjust the direction based on the current turn flags
+ Direction getTurnDirForTurnFlags(Direction direction, DirectionMode dirmode);
+
uint32 _lastFrame;
// attack speed limiting
diff --git a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
index b96306468c..d76e1fd242 100644
--- a/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/cru_avatar_mover_process.cpp
@@ -56,20 +56,16 @@ void CruAvatarMoverProcess::handleHangingMode() {
void CruAvatarMoverProcess::handleCombatMode() {
MainActor *avatar = getMainActor();
- Animation::Sequence lastanim = avatar->getLastAnim();
+ const Animation::Sequence lastanim = avatar->getLastAnim();
Direction direction = avatar->getDir();
- bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
+ const bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
// never idle when in combat
_idleTime = 0;
// If Avatar has fallen down, stand up
- if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
- if (!stasis) {
- waitFor(avatar->doAnim(Animation::standUp, direction));
- }
+ if (standUpIfNeeded(direction))
return;
- }
// can't do any new actions if in stasis
if (stasis)
@@ -77,17 +73,9 @@ void CruAvatarMoverProcess::handleCombatMode() {
bool moving = (lastanim == Animation::advance || lastanim == Animation::retreat);
- DirectionMode dirmode = avatar->animDirMode(Animation::combatStand);
-
// 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_OneLeft(direction, dirmode);
- }
-
- if (hasMovementFlags(MOVE_TURN_RIGHT)) {
- direction = Direction_OneRight(direction, dirmode);
- }
+ direction = getTurnDirForTurnFlags(direction, avatar->animDirMode(Animation::combatStand));
}
if (hasMovementFlags(MOVE_FORWARD)) {
@@ -117,20 +105,8 @@ void CruAvatarMoverProcess::handleCombatMode() {
return;
}
- int y = 0;
- int x = 0;
- if (hasMovementFlags(MOVE_UP)) {
- y++;
- }
- if (hasMovementFlags(MOVE_DOWN)) {
- y--;
- }
- if (hasMovementFlags(MOVE_LEFT)) {
- x--;
- }
- if (hasMovementFlags(MOVE_RIGHT)) {
- x++;
- }
+ int x, y;
+ getMovementFlagAxes(x, y);
if (x != 0 || y != 0) {
Direction nextdir = Direction_Get(y, x, dirmode_8dirs);
@@ -138,7 +114,7 @@ void CruAvatarMoverProcess::handleCombatMode() {
if (checkTurn(nextdir, true))
return;
- Animation::Sequence nextanim;
+ Animation::Sequence nextanim = Animation::combatStand;
if (lastanim == Animation::run) {
// want to run while in combat mode?
// first sheath weapon
@@ -164,18 +140,16 @@ void CruAvatarMoverProcess::handleCombatMode() {
// not doing anything in particular? stand
if (lastanim != Animation::combatStand) {
- Animation::Sequence nextanim = Animation::combatStand;
- nextanim = Animation::checkWeapon(nextanim, lastanim);
+ Animation::Sequence nextanim = Animation::checkWeapon(Animation::combatStand, lastanim);
waitFor(avatar->doAnim(nextanim, direction));
}
}
void CruAvatarMoverProcess::handleNormalMode() {
- Ultima8Engine *guiapp = Ultima8Engine::get_instance();
MainActor *avatar = getMainActor();
- Animation::Sequence lastanim = avatar->getLastAnim();
+ const Animation::Sequence lastanim = avatar->getLastAnim();
Direction direction = avatar->getDir();
- bool stasis = guiapp->isAvatarInStasis();
+ const bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
// Store current idle time. (Also see end of function.)
uint32 currentIdleTime = _idleTime;
@@ -187,36 +161,21 @@ void CruAvatarMoverProcess::handleNormalMode() {
avatar->toggleInCombat();
}
- // If Avatar has fallen down do nothing
- if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
- if (!stasis) {
- waitFor(avatar->doAnim(Animation::standUp, direction));
- }
+ // If Avatar has fallen down and not dead, get up!
+ if (standUpIfNeeded(direction))
return;
- }
// If still in combat stance, sheathe weapon
if (!stasis && Animation::isCombatAnim(lastanim)) {
- ProcId anim1 = avatar->doAnim(Animation::unreadyWeapon, direction);
- ProcId anim2 = avatar->doAnim(Animation::stand, direction);
- Process *anim2p = Kernel::get_instance()->getProcess(anim2);
- anim2p->waitFor(anim1);
- waitFor(anim2);
-
+ putAwayWeapon(direction);
return;
}
- if (!hasMovementFlags(MOVE_ANY_DIRECTION)) {
+ if (!hasMovementFlags(MOVE_ANY_DIRECTION) && lastanim == Animation::run) {
// if we were running, slow to a walk before stopping
// (even in stasis)
- if (lastanim == Animation::run) {
- ProcId walkpid = avatar->doAnim(Animation::walk, direction);
- ProcId standpid = avatar->doAnim(Animation::stand, direction);
- Process *standproc = Kernel::get_instance()->getProcess(standpid);
- standproc->waitFor(walkpid);
- waitFor(standpid);
- return;
- }
+ slowFromRun(direction);
+ return;
}
// can't do any new actions if in stasis
@@ -260,13 +219,7 @@ void CruAvatarMoverProcess::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_OneLeft(direction, dirmode);
- }
-
- if (hasMovementFlags(MOVE_TURN_RIGHT)) {
- direction = Direction_OneRight(direction, dirmode);
- }
+ direction = getTurnDirForTurnFlags(direction, dirmode);
}
Animation::Sequence nextanim = Animation::walk;
@@ -295,20 +248,8 @@ void CruAvatarMoverProcess::handleNormalMode() {
return;
}
- int y = 0;
- int x = 0;
- if (hasMovementFlags(MOVE_UP)) {
- y++;
- }
- if (hasMovementFlags(MOVE_DOWN)) {
- y--;
- }
- if (hasMovementFlags(MOVE_LEFT)) {
- x--;
- }
- if (hasMovementFlags(MOVE_RIGHT)) {
- x++;
- }
+ int x, y;
+ getMovementFlagAxes(x, y);
if (x != 0 || y != 0) {
direction = Direction_Get(y, x, dirmode_8dirs);
diff --git a/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp b/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
index 5e6ffdc7d3..6c330a8a1b 100644
--- a/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
+++ b/engines/ultima/ultima8/world/actors/u8_avatar_mover_process.cpp
@@ -94,21 +94,15 @@ void U8AvatarMoverProcess::handleCombatMode() {
Direction direction = avatar->getDir();
bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
- int32 mx, my;
- mouse->getMouseCoords(mx, my);
- unsigned int mouselength = mouse->getMouseLength(mx, my);
-
- Direction mousedir = mouse->getMouseDirectionWorld(mx, my);
+ unsigned int mouselength = mouse->getMouseLength();
+ Direction mousedir = mouse->getMouseDirectionWorld();
// never idle when in combat
_idleTime = 0;
// If Avatar has fallen down, stand up.
- if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
- if (!stasis)
- waitFor(avatar->doAnim(Animation::standUp, mousedir));
+ if (standUpIfNeeded(direction))
return;
- }
// if we were blocking, and no longer holding the mouse, stop
if (lastanim == Animation::startBlock &&
@@ -182,6 +176,8 @@ void U8AvatarMoverProcess::handleCombatMode() {
_mouseButton[1]._lastDown = 0;
Gump *desktopgump = Ultima8Engine::get_instance()->getDesktopGump();
+ int32 mx, my;
+ mouse->getMouseCoords(mx, my);
if (desktopgump->TraceObjId(mx, my) == 1) {
// double right click on avatar = toggle combat mode
avatar->toggleInCombat();
@@ -218,7 +214,6 @@ void U8AvatarMoverProcess::handleCombatMode() {
//!! TODO: check if you can actually take this step
Direction nextdir = mousedir;
Animation::Sequence nextanim;
-
if (lastanim == Animation::run) {
// want to run while in combat mode?
// first sheath weapon
@@ -250,17 +245,9 @@ void U8AvatarMoverProcess::handleCombatMode() {
bool moving = (lastanim == Animation::advance || lastanim == Animation::retreat);
- DirectionMode dirmode = avatar->animDirMode(Animation::combatStand);
-
// 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_OneLeft(direction, dirmode);
- }
-
- if (hasMovementFlags(MOVE_TURN_RIGHT)) {
- direction = Direction_OneRight(direction, dirmode);
- }
+ direction = getTurnDirForTurnFlags(direction, avatar->animDirMode(Animation::combatStand));
}
if (hasMovementFlags(MOVE_FORWARD)) {
@@ -290,20 +277,8 @@ void U8AvatarMoverProcess::handleCombatMode() {
return;
}
- int y = 0;
- int x = 0;
- if (hasMovementFlags(MOVE_UP)) {
- y++;
- }
- if (hasMovementFlags(MOVE_DOWN)) {
- y--;
- }
- if (hasMovementFlags(MOVE_LEFT)) {
- x--;
- }
- if (hasMovementFlags(MOVE_RIGHT)) {
- x++;
- }
+ int x, y;
+ getMovementFlagAxes(x, y);
if (x != 0 || y != 0) {
Direction nextdir = Direction_Get(y, x, dirmode_8dirs);
@@ -342,25 +317,21 @@ void U8AvatarMoverProcess::handleCombatMode() {
// not doing anything in particular? stand
// TODO: make sure falling works properly.
if (lastanim != Animation::combatStand) {
- Animation::Sequence nextanim = Animation::combatStand;
- nextanim = Animation::checkWeapon(nextanim, lastanim);
+ Animation::Sequence nextanim = Animation::checkWeapon(Animation::combatStand, lastanim);
waitFor(avatar->doAnim(nextanim, direction));
}
}
void U8AvatarMoverProcess::handleNormalMode() {
- Ultima8Engine *guiapp = Ultima8Engine::get_instance();
- Mouse *mouse = Mouse::get_instance();
+ const Mouse *mouse = Mouse::get_instance();
MainActor *avatar = getMainActor();
Animation::Sequence lastanim = avatar->getLastAnim();
Direction direction = avatar->getDir();
- bool stasis = guiapp->isAvatarInStasis();
+ bool stasis = Ultima8Engine::get_instance()->isAvatarInStasis();
bool combatRun = avatar->hasActorFlags(Actor::ACT_COMBATRUN);
- int32 mx, my;
- mouse->getMouseCoords(mx, my);
- unsigned int mouselength = mouse->getMouseLength(mx, my);
- Direction mousedir = mouse->getMouseDirectionWorld(mx, my);
+ unsigned int mouselength = mouse->getMouseLength();
+ Direction mousedir = mouse->getMouseDirectionWorld();
// Store current idle time. (Also see end of function.)
uint32 currentIdleTime = _idleTime;
@@ -373,21 +344,12 @@ void U8AvatarMoverProcess::handleNormalMode() {
}
// If Avatar has fallen down, stand up.
- if (lastanim == Animation::die || lastanim == Animation::fallBackwards) {
- if (!stasis) {
- waitFor(avatar->doAnim(Animation::standUp, direction));
- }
+ if (standUpIfNeeded(direction))
return;
- }
// If still in combat stance, sheathe weapon
if (!stasis && Animation::isCombatAnim(lastanim)) {
- ProcId anim1 = avatar->doAnim(Animation::unreadyWeapon, direction);
- ProcId anim2 = avatar->doAnim(Animation::stand, direction);
- Process *anim2p = Kernel::get_instance()->getProcess(anim2);
- anim2p->waitFor(anim1);
- waitFor(anim2);
-
+ putAwayWeapon(direction);
return;
}
@@ -443,11 +405,7 @@ void U8AvatarMoverProcess::handleNormalMode() {
// if we were running, slow to a walk before stopping
// (even in stasis)
if (lastanim == Animation::run) {
- ProcId walkpid = avatar->doAnim(Animation::walk, direction);
- ProcId standpid = avatar->doAnim(Animation::stand, direction);
- Process *standproc = Kernel::get_instance()->getProcess(standpid);
- standproc->waitFor(walkpid);
- waitFor(standpid);
+ slowFromRun(direction);
return;
}
@@ -487,6 +445,8 @@ void U8AvatarMoverProcess::handleNormalMode() {
if (_mouseButton[1].isUnhandledDoubleClick()) {
Gump *desktopgump = Ultima8Engine::get_instance()->getDesktopGump();
+ int32 mx, my;
+ mouse->getMouseCoords(mx, my);
if (desktopgump->TraceObjId(mx, my) == 1) {
// double right click on avatar = toggle combat mode
_mouseButton[1].setState(MBS_HANDLED);
@@ -583,17 +543,9 @@ void U8AvatarMoverProcess::handleNormalMode() {
bool moving = (lastanim == Animation::step || lastanim == Animation::run || lastanim == Animation::walk);
- DirectionMode dirmode = avatar->animDirMode(Animation::step);
-
// 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_OneLeft(direction, dirmode);
- }
-
- if (hasMovementFlags(MOVE_TURN_RIGHT)) {
- direction = Direction_OneRight(direction, dirmode);
- }
+ direction = getTurnDirForTurnFlags(direction, avatar->animDirMode(Animation::step));
}
Animation::Sequence nextanim = Animation::walk;
@@ -622,20 +574,8 @@ void U8AvatarMoverProcess::handleNormalMode() {
return;
}
- int y = 0;
- int x = 0;
- if (hasMovementFlags(MOVE_UP)) {
- y++;
- }
- if (hasMovementFlags(MOVE_DOWN)) {
- y--;
- }
- if (hasMovementFlags(MOVE_LEFT)) {
- x--;
- }
- if (hasMovementFlags(MOVE_RIGHT)) {
- x++;
- }
+ int x, y;
+ getMovementFlagAxes(x, y);
if (x != 0 || y != 0) {
direction = Direction_Get(y, x, dirmode_8dirs);
@@ -695,9 +635,7 @@ void U8AvatarMoverProcess::step(Animation::Sequence action, Direction direction,
MainActor *avatar = getMainActor();
Animation::Sequence lastanim = avatar->getLastAnim();
-
Animation::Result res = avatar->tryAnim(action, direction);
-
Direction stepdir = direction;
if (res == Animation::FAILURE ||
@@ -753,7 +691,7 @@ void U8AvatarMoverProcess::step(Animation::Sequence action, Direction direction,
if (checkTurn(stepdir, moving))
return;
- debug(6, "Step: step ok: action %d dir %d", action, stepdir);
+ //debug(6, "Step: step ok: action %d dir %d", action, stepdir);
action = Animation::checkWeapon(action, lastanim);
waitFor(avatar->doAnim(action, stepdir));
}
More information about the Scummvm-git-logs
mailing list