diff --git a/engines/grim/actor.cpp b/engines/grim/actor.cpp index 9f52ee92a2d..db3cc562da0 100644 --- a/engines/grim/actor.cpp +++ b/engines/grim/actor.cpp @@ -459,11 +459,48 @@ void Actor::setPos(const Math::Vector3d &position) { } } +Math::Vector3d Actor::actorForward() const { + if (g_grim->getGameType() == GType_GRIM) { + return Math::Vector3d(0.f, 1.f, 0.f); + } + return Math::Vector3d(0.f, 0.f, 1.f); +} + +Math::Vector3d Actor::actorUp() const { + if (g_grim->getGameType() == GType_GRIM) { + return Math::Vector3d(0.f, 0.f, 1.f); + } + return Math::Vector3d(0.f, 1.f, 0.f); +} + +void Actor::turnTo(const Math::Vector3d &pos) { + Math::Vector3d lookVector = pos - _pos; + lookVector.normalize(); + + Math::Vector3d up = actorUp(); + if (_puckOrient) { + Sector *s = NULL; + g_grim->getCurrSet()->findClosestSector(_pos, &s, NULL); + if (s) { + up = s->getNormal(); + } + } + + Math::Matrix4 m; + m.buildFromTargetDir(actorForward(), lookVector, actorUp(), up); + + if (_puckOrient) { + turnTo(m.getPitch(), m.getYaw(), m.getRoll()); + } else { + turnTo(_pitch, m.getYaw(), _roll); + } +} + void Actor::turnTo(const Math::Angle &pitchParam, const Math::Angle &yawParam, const Math::Angle &rollParam) { - _pitch = pitchParam; - _roll = rollParam; + _movePitch = pitchParam; + _moveRoll = rollParam; _moveYaw = yawParam; - if (_yaw != yawParam) { + if (_yaw != yawParam || _pitch != pitchParam || _roll != rollParam) { _turning = true; } else _turning = false; @@ -1216,15 +1253,33 @@ void Actor::updateWalk() { } } - destPos = handleCollisionTo(_pos, destPos); - Math::Angle y = getYawTo(destPos); - turnTo(_pitch, y, _roll); + turnTo(destPos); dir = destPos - _pos; dir.normalize(); _pos += dir * walkAmt; } +static int animTurn(float turnAmt, const Math::Angle &dest, Math::Angle *cur) { + Math::Angle d = dest - *cur; + d.normalize(-180); + // If the actor won't turn because the rate is set to zero then + // have the actor turn all the way to the destination yaw. + // Without this some actors will lock the interface on changing + // scenes, this affects the Bone Wagon in particular. + if (turnAmt == 0 || turnAmt >= fabsf(d.getDegrees())) { + *cur = dest; + } else if (d > 0) { + *cur += turnAmt; + } else { + *cur -= turnAmt; + } + if (d != 0) { + return (d > 0 ? 1 : -1); + } + return 0; +} + void Actor::update(uint frameTime) { // Snap actor to walkboxes if following them. This might be // necessary for example after activating/deactivating @@ -1234,23 +1289,12 @@ void Actor::update(uint frameTime) { } if (_turning) { - float turnAmt = g_grim->getPerSecond(_turnRate) * 5.f; - Math::Angle dyaw = _moveYaw - _yaw; - dyaw.normalize(-180); - // If the actor won't turn because the rate is set to zero then - // have the actor turn all the way to the destination yaw. - // Without this some actors will lock the interface on changing - // scenes, this affects the Bone Wagon in particular. - if (turnAmt == 0 || turnAmt >= fabsf(dyaw.getDegrees())) { - setYaw(_moveYaw); + float turnAmt = g_grim->getPerSecond(_turnRate)*5; + _currTurnDir = animTurn(turnAmt, _moveYaw, &_yaw); + int p = animTurn(turnAmt, _movePitch, &_pitch); + int r = animTurn(turnAmt, _moveRoll, &_roll); + if (_currTurnDir == 0 && p == 0 && r == 0) { _turning = false; - } else if (dyaw > 0) { - setYaw(_yaw + turnAmt); - } else { - setYaw(_yaw - turnAmt); - } - if (dyaw != 0) { - _currTurnDir = (dyaw > 0 ? 1 : -1); } } diff --git a/engines/grim/actor.h b/engines/grim/actor.h index 93e70667546..311f30e6cf8 100644 --- a/engines/grim/actor.h +++ b/engines/grim/actor.h @@ -183,6 +183,16 @@ public: * @see isTurning */ void turnTo(const Math::Angle &pitch, const Math::Angle &yaw, const Math::Angle &roll); + /** + * Turn the actor towards a point in space. + * The effect is not immediate, the actor will slowly rotate + * to the destination orientation. + * + * @param pos The position the actor should turn to. + * @see turnTo + * @see setRot + */ + void turnTo(const Math::Vector3d &pos); /** * Returns true if the actor is turning. * @@ -472,6 +482,15 @@ public: void detach(); Math::Quaternion getRotationQuat() const; + /** + * Returns the forward direction in the local space of the actor. + */ + Math::Vector3d actorForward() const; + /** + * Returns the up direction in the local space of the actor. + */ + Math::Vector3d actorUp() const; + void setInOverworld(bool inOverworld) { _inOverworld = inOverworld; } bool isInOverworld() { return _inOverworld; } @@ -537,6 +556,8 @@ private: // turning animation while still allowing the actor to move in a // new direction immediately after reflecting off a wall. Math::Angle _moveYaw; + Math::Angle _movePitch; + Math::Angle _moveRoll; // Variables for walking to a point bool _walking; diff --git a/engines/grim/lua_v1_actor.cpp b/engines/grim/lua_v1_actor.cpp index e29ed6b2fb6..25258ebd2fd 100644 --- a/engines/grim/lua_v1_actor.cpp +++ b/engines/grim/lua_v1_actor.cpp @@ -1173,20 +1173,12 @@ void Lua_V1::TurnActorTo() { z = lua_getnumber(zObj); } - // TODO turning stuff below is not complete - - // Find the vector pointing from the actor to the desired location Math::Vector3d turnToVector(x, y, z); - Math::Vector3d lookVector = turnToVector - actor->getPos(); - // find the angle the requested position is around the unit circle - Math::Angle yaw = lookVector.unitCircleAngle(); - // yaw is offset from forward by 90 degrees - yaw -= 90.0f; - actor->turnTo(0, yaw, 0); + actor->turnTo(turnToVector); - // Return true if the actor is still turning and its yaw is not the target one. + // Return true if the actor is still turning // This allows manny to have the right yaw when he exits the elevator in the garage - pushbool(actor->getYaw() != yaw); + pushbool(actor->isTurning()); } void Lua_V1::PointActorAt() {