Bunch of bug fixes, guard behavior works again

This commit is contained in:
KimLS 2018-10-13 23:53:16 -07:00
parent 18ec09a79e
commit d0685556e8
14 changed files with 120 additions and 129 deletions

View File

@ -280,7 +280,7 @@ void Bot::ChangeBotArcherWeapons(bool isArcher) {
void Bot::Sit() {
if(IsMoving()) {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
}
SetAppearance(eaSitting);
@ -2999,7 +2999,7 @@ void Bot::PetAIProcess() {
botPet->SetHeading(botPet->GetTarget()->GetHeading());
if(moved) {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
botPet->SendPosition();
botPet->SetMoving(false);
}
@ -3027,7 +3027,7 @@ void Bot::PetAIProcess() {
botPet->SetHeading(botPet->GetTarget()->GetHeading());
if(moved) {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
botPet->SendPosition();
botPet->SetMoving(false);
}

View File

@ -10041,7 +10041,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
mypet->SetPetOrder(SPO_Guard);
mypet->CastToNPC()->SaveGuardSpot();
if (!mypet->GetTarget()) // want them to not twitch if they're chasing something down
mypet->SetCurrentSpeed(0);
mypet->StopNavigation();
if (mypet->IsPetStop()) {
mypet->SetPetStop(false);
SetPetCommandState(PET_BUTTON_STOP, 0);
@ -10343,7 +10343,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
mypet->SetPetStop(false);
} else {
mypet->SetPetStop(true);
mypet->SetCurrentSpeed(0);
mypet->StopNavigation();
mypet->SetTarget(nullptr);
if (mypet->IsPetRegroup()) {
mypet->SetPetRegroup(false);
@ -10359,7 +10359,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
mypet->SetPetStop(true);
mypet->SetCurrentSpeed(0);
mypet->StopNavigation();
mypet->SetTarget(nullptr);
mypet->SayTo_StringID(this, MT_PetResponse, PET_GETLOST_STRING);
if (mypet->IsPetRegroup()) {

View File

@ -1271,48 +1271,11 @@ void command_movement(Client *c, const Seperator *sep)
if (strcasecmp(sep->arg[1], "stats") == 0)
{
//mgr.DumpStats(c);
mgr.DumpStats(c);
}
else if (strcasecmp(sep->arg[1], "clearstats") == 0)
{
//mgr.ClearStats();
}
if (strcasecmp(sep->arg[1], "test") == 0)
{
auto target = c->GetTarget();
if (!target) {
c->Message(0, "Requires target");
}
mgr.NavigateTo(target, c->GetX(), c->GetY(), c->GetZ(), false, MovementRunning);
//auto heading = target->CalculateHeadingToTarget(c->GetX(), c->GetY());
//mgr.SendCommandToClients(target, 0.0f, 0.0f, 0.0f, atof(sep->arg[2]), 0, ClientRangeAny);
//mgr.RotateTo(target, heading);
//double a1 = atof(sep->arg[2]);
//double a2 = atof(sep->arg[3]);
//double a3 = atof(sep->arg[4]);
//double a4 = atof(sep->arg[5]);
//int a5 = atoi(sep->arg[6]);
//
////PlayerPositionUpdateServer_Struct
//EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
//PlayerPositionUpdateServer_Struct *spu = (PlayerPositionUpdateServer_Struct*)outapp.pBuffer;
//
//memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
//spu->spawn_id = target->GetID();
//spu->x_pos = FloatToEQ19(target->GetX());
//spu->y_pos = FloatToEQ19(target->GetY());
//spu->z_pos = FloatToEQ19(target->GetZ());
//spu->heading = FloatToEQ12(target->GetHeading());
//spu->delta_x = FloatToEQ13(a1);
//spu->delta_y = FloatToEQ13(a2);
//spu->delta_z = FloatToEQ13(a3);
//spu->delta_heading = FloatToEQ10(a4);
//spu->animation = a5;
//
//c->QueuePacket(&outapp);
mgr.ClearStats();
}
else {
c->Message(0, "Usage: #movement stats/clearstats");

View File

@ -1471,7 +1471,7 @@ void Merc::AI_Process() {
if(moved) {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
}
}
@ -1513,7 +1513,7 @@ void Merc::AI_Process() {
SetRunAnimSpeed(0);
if(moved) {
SetCurrentSpeed(0);
StopNavigation();
}
}
@ -1771,7 +1771,7 @@ void Merc::AI_Process() {
else {
if (moved) {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
}
}
}

View File

@ -1434,16 +1434,14 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
}
void Mob::StopMoving() {
FixZ();
SetCurrentSpeed(0);
StopNavigation();
if (moved)
moved = false;
}
void Mob::StopMoving(float new_heading) {
SetHeading(new_heading);
FixZ();
SetCurrentSpeed(0);
StopNavigation();
RotateTo(new_heading);
if (moved)
moved = false;
}
@ -2706,10 +2704,10 @@ void Mob::FaceTarget(Mob* mob_to_face /*= 0*/) {
float new_heading = CalculateHeadingToTarget(faced_mob->GetX(), faced_mob->GetY());
if(current_heading != new_heading) {
if (IsEngaged() || IsRunning()) {
mMovementManager->RotateTo(this, new_heading);
RotateToRunning(new_heading);
}
else {
mMovementManager->RotateTo(this, new_heading, MovementWalking);
RotateToWalking(new_heading);
}
}
@ -5765,18 +5763,6 @@ void Mob::SendRemovePlayerState(PlayerState old_state)
safe_delete(app);
}
void Mob::SetCurrentSpeed(int in){
if (current_speed != in)
{
current_speed = in;
if (in == 0) {
SetRunAnimSpeed(0);
SetMoving(false);
SendPosition();
}
}
}
int32 Mob::GetMeleeMitigation() {
int32 mitigation = 0;
mitigation += spellbonuses.MeleeMitigationEffect;

View File

@ -549,7 +549,6 @@ public:
virtual void Gate(uint8 bindnum = 0);
int GetWalkspeed() const { return(_GetWalkSpeed()); }
int GetRunspeed() const { return(_GetRunSpeed()); }
void SetCurrentSpeed(int in);
int GetBaseRunspeed() const { return base_runspeed; }
int GetBaseWalkspeed() const { return base_walkspeed; }
int GetBaseFearSpeed() const { return base_fearspeed; }
@ -972,6 +971,9 @@ public:
void WalkTo(float x, float y, float z);
void RunTo(float x, float y, float z);
void NavigateTo(float x, float y, float z);
void RotateTo(float new_heading);
void RotateToWalking(float new_heading);
void RotateToRunning(float new_heading);
void StopNavigation();
float CalculateDistance(float x, float y, float z);
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);

View File

@ -372,7 +372,7 @@ bool NPC::AIDoSpellCast(uint8 i, Mob* tar, int32 mana_cost, uint32* oDontDoAgain
//stop moving if were casting a spell and were not a bard...
if(!IsBardSong(AIspells[i].spellid)) {
SetCurrentSpeed(0);
StopNavigation();
}
return CastSpell(AIspells[i].spellid, tar->GetID(), EQEmu::CastingSlot::Gem2, AIspells[i].manacost == -2 ? 0 : -1, mana_cost, oDontDoAgainBefore, -1, -1, 0, &(AIspells[i].resist_adjust));
@ -715,7 +715,7 @@ void Client::AI_SpellCast()
{
if(!IsBardSong(spell_to_cast))
{
SetCurrentSpeed(0);
StopNavigation();
}
CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
return;
@ -729,7 +729,7 @@ void Client::AI_SpellCast()
{
if(!IsBardSong(spell_to_cast))
{
SetCurrentSpeed(0);
StopNavigation();
}
CastSpell(spell_to_cast, tar->GetID(), slot_to_use);
return;
@ -787,9 +787,8 @@ void Client::AI_Process()
if (IsRooted()) {
//make sure everybody knows were not moving, for appearance sake
if (IsMoving()) {
if (GetTarget())
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SetCurrentSpeed(0);
FaceTarget();
StopNavigation();
}
//continue on to attack code, ensuring that we execute the engaged code
engaged = true;
@ -797,7 +796,7 @@ void Client::AI_Process()
else {
if (AI_movement_timer->Check()) {
// Check if we have reached the last fear point
if(IsPositionEqual(glm::vec3(GetX(), GetY(), GetZ()), m_FearWalkTarget)) {
if(IsPositionEqualWithinCertainZ(glm::vec3(GetX(), GetY(), GetZ()), m_FearWalkTarget, 5.0f)) {
CalculateNewFearpoint();
}
@ -844,10 +843,8 @@ void Client::AI_Process()
if (AI_movement_timer->Check()) {
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) !=
m_Position.w) {
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SendPosition();
FaceTarget();
}
SetCurrentSpeed(0);
}
if (GetTarget() && !IsStunned() && !IsMezzed() && !GetFeigned()) {
if (attack_timer.Check()) {
@ -874,8 +871,7 @@ void Client::AI_Process()
}
else if(IsMoving())
{
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
SetCurrentSpeed(0);
FaceTarget();
}
}
AI_SpellCast();
@ -1070,9 +1066,8 @@ void Mob::AI_Process() {
!IsPetRegroup()) {
//make sure everybody knows were not moving, for appearance sake
if (IsMoving()) {
if (target)
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
SetCurrentSpeed(0);
FaceTarget();
StopNavigation();
moved = false;
}
//continue on to attack code, ensuring that we execute the engaged code
@ -1081,7 +1076,7 @@ void Mob::AI_Process() {
else {
if (AI_movement_timer->Check()) {
// Check if we have reached the last fear point
if (IsPositionEqual(glm::vec3(GetX(), GetY(), GetZ()), m_FearWalkTarget)) {
if (IsPositionEqualWithinCertainZ(glm::vec3(GetX(), GetY(), GetZ()), m_FearWalkTarget, 5.0f)) {
// Calculate a new point to run to
CalculateNewFearpoint();
}
@ -1403,8 +1398,7 @@ void Mob::AI_Process() {
}
else if (IsMoving()) {
SetHeading(CalculateHeadingToTarget(target->GetX(), target->GetY()));
SetCurrentSpeed(0);
FaceTarget();
}
}
}
@ -1490,9 +1484,7 @@ void Mob::AI_Process() {
* Distance: >= 450 (Snap to owner)
*/
if (distance_to_owner >= 202500 || z_distance > 100) {
m_Position = pet_owner_position;
SendPositionUpdate();
moved = true;
Teleport(pet_owner_position);
}
else {
@ -1562,7 +1554,7 @@ void Mob::AI_Process() {
}
else {
moved = false;
SetCurrentSpeed(0);
StopNavigation();
}
}
}
@ -1688,9 +1680,6 @@ void NPC::AI_DoMovement() {
if (m_Position.x == roambox_destination_x && m_Position.y == roambox_destination_y) {
time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay);
SetMoving(false);
this->FixZ();
SendPosition();
}
return;
@ -1721,14 +1710,10 @@ void NPC::AI_DoMovement() {
SetWaypointPause();
SetAppearance(eaStanding, false);
SetMoving(false);
if (m_CurrentWayPoint.w >= 0.0) {
SetHeading(m_CurrentWayPoint.w);
RotateTo(m_CurrentWayPoint.w);
}
this->FixZ();
SendPosition();
//kick off event_waypoint arrive
char temp[16];
sprintf(temp, "%d", cur_wp);
@ -1771,7 +1756,7 @@ void NPC::AI_DoMovement() {
}
else if (IsGuarding()) {
bool at_gp = IsPositionEqual(m_Position, m_GuardPoint);
bool at_gp = IsPositionEqualWithinCertainZ(m_Position, m_GuardPoint, 5.0f);
if (at_gp) {
@ -1786,12 +1771,11 @@ void NPC::AI_DoMovement() {
ClearFeignMemory();
moved = false;
if (GetTarget() == nullptr || DistanceSquared(m_Position, GetTarget()->GetPosition()) >= 5 * 5) {
SetHeading(m_GuardPoint.w);
RotateTo(m_GuardPoint.w);
}
else {
FaceTarget(GetTarget());
}
SetCurrentSpeed(0);
SetAppearance(GetGuardPointAnim());
}
}
@ -1925,8 +1909,7 @@ void Mob::AI_Event_NoLongerEngaged() {
// except if we're a pet, then we might run into some issues with pets backing off when they should immediately be moving
if(!IsPet())
{
SetRunAnimSpeed(0);
SendPosition();
StopNavigation();
}
ClearRampage();

View File

@ -48,6 +48,7 @@ public:
if (!m_started) {
m_started = true;
m->SetMoving(true);
if (rotate_to_speed > 0.0 && rotate_to_speed <= 25.0) { //send basic rotation
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, m_rotate_to_dir * rotate_to_speed, 0, ClientRangeClose);
@ -71,7 +72,8 @@ public:
if (td >= dist) {
m->SetHeading(to);
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
m->SetMoving(false);
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
return true;
}
@ -129,6 +131,7 @@ public:
if (!m_started) {
m_started = true;
//rotate to the point
m->SetMoving(true);
m->SetHeading(m->CalculateHeadingToTarget(m_move_to_x, m_move_to_y));
m->TryFixZ();
@ -165,6 +168,7 @@ public:
glm::vec2 pos(p.x, p.y);
double len = glm::distance(pos, tar);
if (len == 0) {
m->SetMoving(false);
return true;
}
@ -172,7 +176,7 @@ public:
glm::vec2 dir = tar - pos;
glm::vec2 ndir = glm::normalize(dir);
double distance_moved = frame_time * current_speed * 0.4f * 1.4f;
double distance_moved = frame_time * current_speed * 0.4f * 1.45f;
if (distance_moved > len) {
m->SetPosition(m_move_to_x, m_move_to_y, m_move_to_z);
@ -182,6 +186,7 @@ public:
}
m->TryFixZ();
m->SetMoving(false);
return true;
}
else {
@ -272,7 +277,7 @@ public:
return true;
}
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
return true;
}
@ -284,12 +289,14 @@ public:
struct MovementStats
{
MovementStats() {
LastResetTime = static_cast<double>(Timer::GetCurrentTime()) / 1000.0;
TotalSent = 0ULL;
TotalSentMovement = 0ULL;
TotalSentPosition = 0ULL;
TotalSentHeading = 0ULL;
}
double LastResetTime;
uint64_t TotalSent;
uint64_t TotalSentMovement;
uint64_t TotalSentPosition;
@ -302,12 +309,14 @@ struct NavigateTo
navigate_to_x = 0.0;
navigate_to_y = 0.0;
navigate_to_z = 0.0;
navigate_to_heading = 0.0;
last_set_time = 0.0;
}
double navigate_to_x;
double navigate_to_y;
double navigate_to_z;
double navigate_to_heading;
double last_set_time;
};
@ -417,24 +426,28 @@ void MobMovementManager::Teleport(Mob *who, float x, float y, float z, float hea
PushTeleportTo(ent.second, x, y, z, heading);
}
void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, bool force, MobMovementMode mode)
void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode)
{
auto iter = _impl->Entries.find(who);
auto &ent = (*iter);
auto &nav = ent.second.NavigateTo;
double current_time = static_cast<double>(Timer::GetCurrentTime()) / 1000.0;
if (force || (current_time - nav.last_set_time) > 0.5) {
if ((current_time - nav.last_set_time) > 0.5) {
//Can potentially recalc
auto within = IsPositionWithinSimpleCylinder(glm::vec3(x, y, z), glm::vec3(nav.navigate_to_x, nav.navigate_to_y, nav.navigate_to_z), 1.5f, 6.0f);
if (false == within) {
auto heading_match = IsHeadingEqual(0.0, nav.navigate_to_heading);
if (false == within || false == heading_match) {
ent.second.Commands.clear();
//Path is no longer valid, calculate a new path
UpdatePath(who, x, y, z, mode);
nav.navigate_to_x = x;
nav.navigate_to_y = y;
nav.navigate_to_z = z;
nav.navigate_to_heading = 0.0;
nav.last_set_time = current_time;
}
}
@ -455,7 +468,7 @@ void MobMovementManager::StopNavigation(Mob *who) {
}
who->TryFixZ();
SendCommandToClients(who, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
SendCommandToClients(who, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
ent.second.Commands.clear();
}
@ -492,19 +505,19 @@ void MobMovementManager::SendCommandToClients(Mob *m, float dx, float dy, float
bool match = false;
if (range & ClientRangeClose) {
if (dist < 200.0f) {
if (dist < 250.0f) {
match = true;
}
}
if (!match && range & ClientRangeMedium) {
if (dist >= 200.0f && dist < 1000.0f) {
if (dist >= 250.0f && dist < 1500.0f) {
match = true;
}
}
if (!match && range & ClientRangeLong) {
if (dist >= 1000.0f) {
if (dist >= 1500.0f) {
match = true;
}
}
@ -542,6 +555,27 @@ float MobMovementManager::FixHeading(float in)
return h;
}
void MobMovementManager::DumpStats(Client *to)
{
auto current_time = static_cast<double>(Timer::GetCurrentTime()) / 1000.0;
auto total_time = current_time - _impl->Stats.LastResetTime;
to->Message(MT_System, "Dumping Movement Stats:");
to->Message(MT_System, "Total Sent: %u (%.2f / sec)", _impl->Stats.TotalSent, static_cast<double>(_impl->Stats.TotalSent) / total_time);
to->Message(MT_System, "Total Heading: %u (%.2f / sec)", _impl->Stats.TotalSentHeading, static_cast<double>(_impl->Stats.TotalSentHeading) / total_time);
to->Message(MT_System, "Total Movement: %u (%.2f / sec)", _impl->Stats.TotalSentMovement, static_cast<double>(_impl->Stats.TotalSentMovement) / total_time);
to->Message(MT_System, "Total Position: %u (%.2f / sec)", _impl->Stats.TotalSentPosition, static_cast<double>(_impl->Stats.TotalSentPosition) / total_time);
}
void MobMovementManager::ClearStats()
{
_impl->Stats.LastResetTime = static_cast<double>(Timer::GetCurrentTime()) / 1000.0;
_impl->Stats.TotalSent = 0;
_impl->Stats.TotalSentHeading = 0;
_impl->Stats.TotalSentMovement = 0;
_impl->Stats.TotalSentPosition = 0;
}
void MobMovementManager::FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim)
{
memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));

View File

@ -39,13 +39,12 @@ public:
void RotateTo(Mob *who, float to, MobMovementMode mode = MovementRunning);
void Teleport(Mob *who, float x, float y, float z, float heading);
void NavigateTo(Mob *who, float x, float y, float z, bool force = false, MobMovementMode mode = MovementRunning);
void NavigateTo(Mob *who, float x, float y, float z, MobMovementMode mode = MovementRunning);
void StopNavigation(Mob *who);
void SendCommandToClients(Mob *m, float dx, float dy, float dz, float dh, int anim, ClientRange range);
float FixHeading(float in);
//void Dump(Mob *m, Client *to);
//void DumpStats(Client *to);
//void ClearStats();
void DumpStats(Client *to);
void ClearStats();
static MobMovementManager &Get() {
static MobMovementManager inst;

View File

@ -772,9 +772,8 @@ bool NPC::Process()
DoGravityEffect();
}
if(reface_timer->Check() && !IsEngaged() && (m_GuardPoint.x == GetX() && m_GuardPoint.y == GetY() && m_GuardPoint.z == GetZ())) {
SetHeading(m_GuardPoint.w);
SendPosition();
if(reface_timer->Check() && !IsEngaged() && IsPositionEqualWithinCertainZ(m_Position, m_GuardPoint, 5.0f)) {
RotateTo(m_GuardPoint.w);
reface_timer->Disable();
}

View File

@ -163,6 +163,11 @@ float GetReciprocalHeading(const float heading)
return result;
}
bool IsHeadingEqual(const float h1, const float h2)
{
return std::abs(h2 - h1) < 0.01f;
}
bool IsPositionEqual(const glm::vec2 &p1, const glm::vec2 &p2)
{
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps;

View File

@ -50,6 +50,8 @@ float DistanceSquaredNoZ(const glm::vec4& point1, const glm::vec4& point2);
float GetReciprocalHeading(const glm::vec4& point1);
float GetReciprocalHeading(const float heading);
bool IsHeadingEqual(const float h1, const float h2);
bool IsPositionEqual(const glm::vec2 &p1, const glm::vec2 &p2);
bool IsPositionEqual(const glm::vec3 &p1, const glm::vec3 &p2);
bool IsPositionEqual(const glm::vec4 &p1, const glm::vec4 &p2);

View File

@ -4898,12 +4898,11 @@ void Client::UnStun() {
void NPC::Stun(int duration) {
Mob::Stun(duration);
SetCurrentSpeed(0);
StopNavigation();
}
void NPC::UnStun() {
Mob::UnStun();
SetCurrentSpeed(GetRunspeed());
}
void Mob::Mesmerize()

View File

@ -428,12 +428,11 @@ void NPC::SaveGuardSpot(bool iClearGuardSpot) {
void NPC::NextGuardPosition() {
NavigateTo(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z);
if ((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && (m_Position.z == m_GuardPoint.z))
if (IsPositionEqualWithinCertainZ(m_Position, m_GuardPoint, 5.0f))
{
if (moved)
{
moved = false;
SetCurrentSpeed(0);
}
}
}
@ -444,24 +443,44 @@ float Mob::CalculateDistance(float x, float y, float z) {
void Mob::WalkTo(float x, float y, float z)
{
mMovementManager->NavigateTo(this, x, y, z, false, MovementWalking);
mMovementManager->NavigateTo(this, x, y, z, MovementWalking);
}
void Mob::RunTo(float x, float y, float z)
{
mMovementManager->NavigateTo(this, x, y, z, false, MovementRunning);
mMovementManager->NavigateTo(this, x, y, z, MovementRunning);
}
void Mob::NavigateTo(float x, float y, float z)
{
if (IsRunning()) {
mMovementManager->NavigateTo(this, x, y, z, false, MovementRunning);
RunTo(x, y, z);
}
else {
mMovementManager->NavigateTo(this, x, y, z, false, MovementWalking);
WalkTo(x, y, z);
}
}
void Mob::RotateTo(float new_heading)
{
if (IsRunning()) {
RotateToRunning(new_heading);
}
else {
RotateToWalking(new_heading);
}
}
void Mob::RotateToWalking(float new_heading)
{
mMovementManager->RotateTo(this, new_heading, MovementWalking);
}
void Mob::RotateToRunning(float new_heading)
{
mMovementManager->RotateTo(this, new_heading, MovementRunning);
}
void Mob::StopNavigation() {
mMovementManager->StopNavigation(this);
}