mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 18:51:29 +00:00
Bunch of refactoring and walking, AI needs a ton of tweaking to use the new logic
This commit is contained in:
parent
29ea65a71e
commit
1785120796
@ -567,7 +567,7 @@ RULE_BOOL(TaskSystem, EnableTaskProximity, true)
|
|||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Range)
|
RULE_CATEGORY(Range)
|
||||||
RULE_INT(Range, Say, 135)
|
RULE_INT(Range, Say, 15)
|
||||||
RULE_INT(Range, Emote, 135)
|
RULE_INT(Range, Emote, 135)
|
||||||
RULE_INT(Range, BeginCast, 200)
|
RULE_INT(Range, BeginCast, 200)
|
||||||
RULE_INT(Range, Anims, 135)
|
RULE_INT(Range, Anims, 135)
|
||||||
|
|||||||
@ -1108,7 +1108,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
|
|||||||
CheckLDoNHail(GetTarget());
|
CheckLDoNHail(GetTarget());
|
||||||
CheckEmoteHail(GetTarget(), message);
|
CheckEmoteHail(GetTarget(), message);
|
||||||
|
|
||||||
if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= RuleI(Range, Say)) {
|
if(DistanceNoZ(m_Position, GetTarget()->GetPosition()) <= RuleI(Range, Say)) {
|
||||||
NPC *tar = GetTarget()->CastToNPC();
|
NPC *tar = GetTarget()->CastToNPC();
|
||||||
parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language);
|
parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language);
|
||||||
|
|
||||||
|
|||||||
@ -1284,9 +1284,11 @@ void command_movement(Client *c, const Seperator *sep)
|
|||||||
c->Message(0, "Requires 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());
|
//auto heading = target->CalculateHeadingToTarget(c->GetX(), c->GetY());
|
||||||
mgr.RotateTo(target, heading, 16.0f);
|
//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 a1 = atof(sep->arg[2]);
|
||||||
//double a2 = atof(sep->arg[3]);
|
//double a2 = atof(sep->arg[3]);
|
||||||
|
|||||||
@ -1124,9 +1124,19 @@ double Lua_Mob::CalculateHeadingToTarget(double in_x, double in_y) {
|
|||||||
return self->CalculateHeadingToTarget(static_cast<float>(in_x), static_cast<float>(in_y));
|
return self->CalculateHeadingToTarget(static_cast<float>(in_x), static_cast<float>(in_y));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lua_Mob::NavigateTo(double x, double y, double z, double speed) {
|
void Lua_Mob::RunTo(double x, double y, double z) {
|
||||||
Lua_Safe_Call_Void();
|
Lua_Safe_Call_Void();
|
||||||
self->NavigateTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(speed));
|
self->RunTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Mob::WalkTo(double x, double y, double z) {
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->WalkTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lua_Mob::NavigateTo(double x, double y, double z) {
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
self->NavigateTo(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lua_Mob::StopNavigation() {
|
void Lua_Mob::StopNavigation() {
|
||||||
@ -2360,7 +2370,9 @@ luabind::scope lua_register_mob() {
|
|||||||
.def("FaceTarget", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::FaceTarget)
|
.def("FaceTarget", (void(Lua_Mob::*)(Lua_Mob))&Lua_Mob::FaceTarget)
|
||||||
.def("SetHeading", (void(Lua_Mob::*)(double))&Lua_Mob::SetHeading)
|
.def("SetHeading", (void(Lua_Mob::*)(double))&Lua_Mob::SetHeading)
|
||||||
.def("CalculateHeadingToTarget", (double(Lua_Mob::*)(double,double))&Lua_Mob::CalculateHeadingToTarget)
|
.def("CalculateHeadingToTarget", (double(Lua_Mob::*)(double,double))&Lua_Mob::CalculateHeadingToTarget)
|
||||||
.def("NavigateTo", (void(Lua_Mob::*)(double,double,double,double))&Lua_Mob::NavigateTo)
|
.def("RunTo", (void(Lua_Mob::*)(double, double, double))&Lua_Mob::RunTo)
|
||||||
|
.def("WalkTo", (void(Lua_Mob::*)(double, double, double))&Lua_Mob::WalkTo)
|
||||||
|
.def("NavigateTo", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::NavigateTo)
|
||||||
.def("StopNavigation", (void(Lua_Mob::*)(void))&Lua_Mob::StopNavigation)
|
.def("StopNavigation", (void(Lua_Mob::*)(void))&Lua_Mob::StopNavigation)
|
||||||
.def("CalculateDistance", (float(Lua_Mob::*)(double,double,double))&Lua_Mob::CalculateDistance)
|
.def("CalculateDistance", (float(Lua_Mob::*)(double,double,double))&Lua_Mob::CalculateDistance)
|
||||||
.def("SendTo", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::SendTo)
|
.def("SendTo", (void(Lua_Mob::*)(double,double,double))&Lua_Mob::SendTo)
|
||||||
|
|||||||
@ -240,7 +240,9 @@ public:
|
|||||||
void FaceTarget(Lua_Mob target);
|
void FaceTarget(Lua_Mob target);
|
||||||
void SetHeading(double in);
|
void SetHeading(double in);
|
||||||
double CalculateHeadingToTarget(double in_x, double in_y);
|
double CalculateHeadingToTarget(double in_x, double in_y);
|
||||||
void NavigateTo(double x, double y, double z, double speed);
|
void RunTo(double x, double y, double z);
|
||||||
|
void WalkTo(double x, double y, double z);
|
||||||
|
void NavigateTo(double x, double y, double z);
|
||||||
void StopNavigation();
|
void StopNavigation();
|
||||||
float CalculateDistance(double x, double y, double z);
|
float CalculateDistance(double x, double y, double z);
|
||||||
void SendTo(double x, double y, double z);
|
void SendTo(double x, double y, double z);
|
||||||
|
|||||||
@ -1479,7 +1479,7 @@ void Merc::AI_Process() {
|
|||||||
}
|
}
|
||||||
else if (!CheckLosFN(GetTarget())) {
|
else if (!CheckLosFN(GetTarget())) {
|
||||||
auto Goal = GetTarget()->GetPosition();
|
auto Goal = GetTarget()->GetPosition();
|
||||||
NavigateTo(Goal.x, Goal.y, Goal.z, GetRunspeed());
|
RunTo(Goal.x, Goal.y, Goal.z);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1545,7 +1545,7 @@ void Merc::AI_Process() {
|
|||||||
float newZ = 0;
|
float newZ = 0;
|
||||||
FaceTarget(GetTarget());
|
FaceTarget(GetTarget());
|
||||||
if (PlotPositionAroundTarget(this, newX, newY, newZ)) {
|
if (PlotPositionAroundTarget(this, newX, newY, newZ)) {
|
||||||
NavigateTo(newX, newY, newZ, GetRunspeed());
|
RunTo(newX, newY, newZ);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1557,7 +1557,7 @@ void Merc::AI_Process() {
|
|||||||
float newY = 0;
|
float newY = 0;
|
||||||
float newZ = 0;
|
float newZ = 0;
|
||||||
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ)) {
|
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ)) {
|
||||||
NavigateTo(newX, newY, newZ, GetRunspeed());
|
RunTo(newX, newY, newZ);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1568,7 +1568,7 @@ void Merc::AI_Process() {
|
|||||||
float newY = 0;
|
float newY = 0;
|
||||||
float newZ = 0;
|
float newZ = 0;
|
||||||
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) {
|
if (PlotPositionAroundTarget(GetTarget(), newX, newY, newZ, false) && GetArchetype() != ARCHETYPE_CASTER) {
|
||||||
NavigateTo(newX, newY, newZ, GetRunspeed());
|
RunTo(newX, newY, newZ);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1695,7 +1695,7 @@ void Merc::AI_Process() {
|
|||||||
{
|
{
|
||||||
if(!IsRooted()) {
|
if(!IsRooted()) {
|
||||||
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName());
|
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", GetTarget()->GetCleanName());
|
||||||
NavigateTo(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetRunspeed());
|
RunTo(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1750,15 +1750,20 @@ void Merc::AI_Process() {
|
|||||||
|
|
||||||
if (follow) {
|
if (follow) {
|
||||||
float dist = DistanceSquared(m_Position, follow->GetPosition());
|
float dist = DistanceSquared(m_Position, follow->GetPosition());
|
||||||
int speed = GetRunspeed();
|
bool running = true;
|
||||||
|
|
||||||
if (dist < GetFollowDistance() + 1000)
|
if (dist < GetFollowDistance() + 1000)
|
||||||
speed = GetWalkspeed();
|
running = false;
|
||||||
|
|
||||||
SetRunAnimSpeed(0);
|
SetRunAnimSpeed(0);
|
||||||
|
|
||||||
if (dist > GetFollowDistance()) {
|
if (dist > GetFollowDistance()) {
|
||||||
NavigateTo(follow->GetX(), follow->GetY(), follow->GetZ(), speed);
|
if (running) {
|
||||||
|
RunTo(follow->GetX(), follow->GetY(), follow->GetZ());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WalkTo(follow->GetX(), follow->GetY(), follow->GetZ());
|
||||||
|
}
|
||||||
|
|
||||||
if (rest_timer.Enabled())
|
if (rest_timer.Enabled())
|
||||||
rest_timer.Disable();
|
rest_timer.Disable();
|
||||||
|
|||||||
34
zone/mob.cpp
34
zone/mob.cpp
@ -442,9 +442,6 @@ Mob::Mob(const char* in_name,
|
|||||||
PrimaryAggro = false;
|
PrimaryAggro = false;
|
||||||
AssistAggro = false;
|
AssistAggro = false;
|
||||||
npc_assist_cap = 0;
|
npc_assist_cap = 0;
|
||||||
|
|
||||||
PathRecalcTimer.reset(new Timer(500));
|
|
||||||
PathingLoopCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mob::~Mob()
|
Mob::~Mob()
|
||||||
@ -1622,8 +1619,6 @@ void Mob::ShowBuffList(Client* client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Mob::GMMove(float x, float y, float z, float heading, bool SendUpdate) {
|
void Mob::GMMove(float x, float y, float z, float heading, bool SendUpdate) {
|
||||||
Route.clear();
|
|
||||||
|
|
||||||
if(IsNPC()) {
|
if(IsNPC()) {
|
||||||
entity_list.ProcessMove(CastToNPC(), x, y, z);
|
entity_list.ProcessMove(CastToNPC(), x, y, z);
|
||||||
}
|
}
|
||||||
@ -2710,7 +2705,12 @@ void Mob::FaceTarget(Mob* mob_to_face /*= 0*/) {
|
|||||||
float current_heading = GetHeading();
|
float current_heading = GetHeading();
|
||||||
float new_heading = CalculateHeadingToTarget(faced_mob->GetX(), faced_mob->GetY());
|
float new_heading = CalculateHeadingToTarget(faced_mob->GetX(), faced_mob->GetY());
|
||||||
if(current_heading != new_heading) {
|
if(current_heading != new_heading) {
|
||||||
mMovementManager->RotateTo(this, new_heading, 16.0f);
|
if (IsEngaged() || IsRunning()) {
|
||||||
|
mMovementManager->RotateTo(this, new_heading);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mMovementManager->RotateTo(this, new_heading, MovementWalking);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsNPC() && !IsEngaged()) {
|
if(IsNPC() && !IsEngaged()) {
|
||||||
@ -3553,10 +3553,12 @@ void Mob::SetFlyMode(GravityBehavior flymode)
|
|||||||
|
|
||||||
void Mob::Teleport(const glm::vec3 &pos)
|
void Mob::Teleport(const glm::vec3 &pos)
|
||||||
{
|
{
|
||||||
|
mMovementManager->Teleport(this, pos.x, pos.y, pos.z, m_Position.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::Teleport(const glm::vec4 &pos)
|
void Mob::Teleport(const glm::vec4 &pos)
|
||||||
{
|
{
|
||||||
|
mMovementManager->Teleport(this, pos.x, pos.y, pos.z, pos.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::IsNimbusEffectActive(uint32 nimbus_effect)
|
bool Mob::IsNimbusEffectActive(uint32 nimbus_effect)
|
||||||
@ -5580,25 +5582,7 @@ float Mob::HeadingAngleToMob(float other_x, float other_y)
|
|||||||
float this_x = GetX();
|
float this_x = GetX();
|
||||||
float this_y = GetY();
|
float this_y = GetY();
|
||||||
|
|
||||||
float y_diff = std::abs(this_y - other_y);
|
return CalculateHeadingAngleBetweenPositions(this_x, this_y, other_x, other_y);
|
||||||
float x_diff = std::abs(this_x - other_x);
|
|
||||||
if (y_diff < 0.0000009999999974752427)
|
|
||||||
y_diff = 0.0000009999999974752427;
|
|
||||||
|
|
||||||
float angle = atan2(x_diff, y_diff) * 180.0f * 0.3183099014828645f; // angle, nice "pi"
|
|
||||||
|
|
||||||
// return the right thing based on relative quadrant
|
|
||||||
// I'm sure this could be improved for readability, but whatever
|
|
||||||
if (this_y >= other_y) {
|
|
||||||
if (other_x >= this_x)
|
|
||||||
return (90.0f - angle + 90.0f) * 511.5f * 0.0027777778f;
|
|
||||||
if (other_x <= this_x)
|
|
||||||
return (angle + 180.0f) * 511.5f * 0.0027777778f;
|
|
||||||
}
|
|
||||||
if (this_y > other_y || other_x > this_x)
|
|
||||||
return angle * 511.5f * 0.0027777778f;
|
|
||||||
else
|
|
||||||
return (90.0f - angle + 270.0f) * 511.5f * 0.0027777778f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::GetSeeInvisible(uint8 see_invis)
|
bool Mob::GetSeeInvisible(uint8 see_invis)
|
||||||
|
|||||||
17
zone/mob.h
17
zone/mob.h
@ -523,6 +523,7 @@ public:
|
|||||||
uint32 GetNPCTypeID() const { return npctype_id; }
|
uint32 GetNPCTypeID() const { return npctype_id; }
|
||||||
void SetNPCTypeID(uint32 npctypeid) { npctype_id = npctypeid; }
|
void SetNPCTypeID(uint32 npctypeid) { npctype_id = npctypeid; }
|
||||||
inline const glm::vec4& GetPosition() const { return m_Position; }
|
inline const glm::vec4& GetPosition() const { return m_Position; }
|
||||||
|
inline void SetPosition(const float x, const float y, const float z) { m_Position.x = x; m_Position.y = y; m_Position.z = z; }
|
||||||
inline const float GetX() const { return m_Position.x; }
|
inline const float GetX() const { return m_Position.x; }
|
||||||
inline const float GetY() const { return m_Position.y; }
|
inline const float GetY() const { return m_Position.y; }
|
||||||
inline const float GetZ() const { return m_Position.z; }
|
inline const float GetZ() const { return m_Position.z; }
|
||||||
@ -968,7 +969,9 @@ public:
|
|||||||
|
|
||||||
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
|
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
|
||||||
float CalculateHeadingToTarget(float in_x, float in_y) { return HeadingAngleToMob(in_x, in_y); }
|
float CalculateHeadingToTarget(float in_x, float in_y) { return HeadingAngleToMob(in_x, in_y); }
|
||||||
void NavigateTo(float x, float y, float z, float speed);
|
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 StopNavigation();
|
void StopNavigation();
|
||||||
float CalculateDistance(float x, float y, float z);
|
float CalculateDistance(float x, float y, float z);
|
||||||
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
|
float GetGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||||
@ -1133,9 +1136,6 @@ public:
|
|||||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item);
|
int GetWeaponDamage(Mob *against, const EQEmu::ItemData *weapon_item);
|
||||||
int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr);
|
int GetWeaponDamage(Mob *against, const EQEmu::ItemInstance *weapon_item, uint32 *hate = nullptr);
|
||||||
|
|
||||||
//Pathing
|
|
||||||
glm::vec3 UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached);
|
|
||||||
|
|
||||||
// Bots HealRotation methods
|
// Bots HealRotation methods
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
|
bool IsHealRotationTarget() { return (m_target_of_heal_rotation.use_count() && m_target_of_heal_rotation.get()); }
|
||||||
@ -1292,7 +1292,6 @@ protected:
|
|||||||
void CalculateNewFearpoint();
|
void CalculateNewFearpoint();
|
||||||
float FindGroundZ(float new_x, float new_y, float z_offset=0.0);
|
float FindGroundZ(float new_x, float new_y, float z_offset=0.0);
|
||||||
float FindDestGroundZ(glm::vec3 dest, float z_offset=0.0);
|
float FindDestGroundZ(glm::vec3 dest, float z_offset=0.0);
|
||||||
glm::vec3 HandleStuckPath(const glm::vec3 &To, const glm::vec3 &From);
|
|
||||||
|
|
||||||
virtual float GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate = 0);
|
virtual float GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate = 0);
|
||||||
int16 GetSympatheticSpellProcRate(uint16 spell_id);
|
int16 GetSympatheticSpellProcRate(uint16 spell_id);
|
||||||
@ -1481,15 +1480,7 @@ protected:
|
|||||||
glm::vec3 m_FearWalkTarget;
|
glm::vec3 m_FearWalkTarget;
|
||||||
bool currently_fleeing;
|
bool currently_fleeing;
|
||||||
|
|
||||||
// Pathing
|
|
||||||
//
|
|
||||||
glm::vec3 PathingDestination;
|
|
||||||
IPathfinder::IPath Route;
|
|
||||||
std::unique_ptr<Timer> PathRecalcTimer;
|
|
||||||
bool DistractedFromGrid;
|
bool DistractedFromGrid;
|
||||||
glm::vec3 PathingLastPosition;
|
|
||||||
int PathingLoopCount;
|
|
||||||
|
|
||||||
uint32 pDontHealMeBefore;
|
uint32 pDontHealMeBefore;
|
||||||
uint32 pDontBuffMeBefore;
|
uint32 pDontBuffMeBefore;
|
||||||
uint32 pDontDotMeBefore;
|
uint32 pDontDotMeBefore;
|
||||||
|
|||||||
@ -796,16 +796,12 @@ void Client::AI_Process()
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (AI_movement_timer->Check()) {
|
if (AI_movement_timer->Check()) {
|
||||||
int speed = GetFearSpeed();
|
|
||||||
animation = speed;
|
|
||||||
speed *= 2;
|
|
||||||
SetCurrentSpeed(speed);
|
|
||||||
// Check if we have reached the last fear point
|
// Check if we have reached the last fear point
|
||||||
if(IsPositionEqual(GetX(), GetY(), GetZ(), m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z)) {
|
if(IsPositionEqual(glm::vec3(GetX(), GetY(), GetZ()), m_FearWalkTarget)) {
|
||||||
CalculateNewFearpoint();
|
CalculateNewFearpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigateTo(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z, speed);
|
RunTo(m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -873,11 +869,7 @@ void Client::AI_Process()
|
|||||||
{
|
{
|
||||||
if(AI_movement_timer->Check())
|
if(AI_movement_timer->Check())
|
||||||
{
|
{
|
||||||
int newspeed = GetRunspeed();
|
RunTo(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ());
|
||||||
animation = newspeed;
|
|
||||||
newspeed *= 2;
|
|
||||||
SetCurrentSpeed(newspeed);
|
|
||||||
NavigateTo(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), newspeed);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(IsMoving())
|
else if(IsMoving())
|
||||||
@ -920,12 +912,12 @@ void Client::AI_Process()
|
|||||||
SendPositionUpdate(); // this shouldn't happen a lot (and hard to make it) so lets not rate limit
|
SendPositionUpdate(); // this shouldn't happen a lot (and hard to make it) so lets not rate limit
|
||||||
} else if (dist >= 400) { // >=20
|
} else if (dist >= 400) { // >=20
|
||||||
if (AI_movement_timer->Check()) {
|
if (AI_movement_timer->Check()) {
|
||||||
int nspeed = (dist >= 1225 ? GetRunspeed() : GetWalkspeed()); // >= 35
|
if (dist >= 1225) {
|
||||||
animation = nspeed;
|
RunTo(owner->GetX(), owner->GetY(), owner->GetZ());
|
||||||
nspeed *= 2;
|
}
|
||||||
SetCurrentSpeed(nspeed);
|
else {
|
||||||
|
WalkTo(owner->GetX(), owner->GetY(), owner->GetZ());
|
||||||
NavigateTo(owner->GetX(), owner->GetY(), owner->GetZ(), nspeed);
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
StopNavigation();
|
StopNavigation();
|
||||||
@ -1089,15 +1081,14 @@ void Mob::AI_Process() {
|
|||||||
else {
|
else {
|
||||||
if (AI_movement_timer->Check()) {
|
if (AI_movement_timer->Check()) {
|
||||||
// Check if we have reached the last fear point
|
// Check if we have reached the last fear point
|
||||||
if (IsPositionEqual(GetX(), GetY(), GetZ(), m_FearWalkTarget.x, m_FearWalkTarget.y, m_FearWalkTarget.z)) {
|
if (IsPositionEqual(glm::vec3(GetX(), GetY(), GetZ()), m_FearWalkTarget)) {
|
||||||
// Calculate a new point to run to
|
// Calculate a new point to run to
|
||||||
CalculateNewFearpoint();
|
CalculateNewFearpoint();
|
||||||
}
|
}
|
||||||
NavigateTo(
|
NavigateTo(
|
||||||
m_FearWalkTarget.x,
|
m_FearWalkTarget.x,
|
||||||
m_FearWalkTarget.y,
|
m_FearWalkTarget.y,
|
||||||
m_FearWalkTarget.z,
|
m_FearWalkTarget.z
|
||||||
GetFearSpeed()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -1216,18 +1207,7 @@ void Mob::AI_Process() {
|
|||||||
StopNavigation();
|
StopNavigation();
|
||||||
|
|
||||||
if (AI_movement_timer->Check()) {
|
if (AI_movement_timer->Check()) {
|
||||||
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) {
|
FaceTarget();
|
||||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
|
||||||
SendPosition();
|
|
||||||
}
|
|
||||||
SetCurrentSpeed(0);
|
|
||||||
}
|
|
||||||
if (IsMoving()) {
|
|
||||||
if (CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()) != m_Position.w) {
|
|
||||||
SetHeading(CalculateHeadingToTarget(GetTarget()->GetX(), GetTarget()->GetY()));
|
|
||||||
SendPosition();
|
|
||||||
}
|
|
||||||
SetCurrentSpeed(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//casting checked above...
|
//casting checked above...
|
||||||
@ -1419,7 +1399,7 @@ void Mob::AI_Process() {
|
|||||||
else if (AI_movement_timer->Check() && target) {
|
else if (AI_movement_timer->Check() && target) {
|
||||||
if (!IsRooted()) {
|
if (!IsRooted()) {
|
||||||
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName());
|
Log(Logs::Detail, Logs::AI, "Pursuing %s while engaged.", target->GetName());
|
||||||
NavigateTo(target->GetX(), target->GetY(), target->GetZ(), GetRunspeed());
|
RunTo(target->GetX(), target->GetY(), target->GetZ());
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (IsMoving()) {
|
else if (IsMoving()) {
|
||||||
@ -1497,13 +1477,13 @@ void Mob::AI_Process() {
|
|||||||
|
|
||||||
if (distance_to_owner >= 400 || z_distance > 100) {
|
if (distance_to_owner >= 400 || z_distance > 100) {
|
||||||
|
|
||||||
int pet_speed = GetWalkspeed();
|
bool running = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Distance: >= 35 (Run if far away)
|
* Distance: >= 35 (Run if far away)
|
||||||
*/
|
*/
|
||||||
if (distance_to_owner >= 1225) {
|
if (distance_to_owner >= 1225) {
|
||||||
pet_speed = GetRunspeed();
|
running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1518,7 +1498,12 @@ void Mob::AI_Process() {
|
|||||||
|
|
||||||
auto &Goal = owner->GetPosition();
|
auto &Goal = owner->GetPosition();
|
||||||
|
|
||||||
NavigateTo(Goal.x, Goal.y, Goal.z, pet_speed);
|
if (running) {
|
||||||
|
RunTo(Goal.x, Goal.y, Goal.z);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WalkTo(Goal.x, Goal.y, Goal.z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1558,17 +1543,22 @@ void Mob::AI_Process() {
|
|||||||
* Default follow distance is 100
|
* Default follow distance is 100
|
||||||
*/
|
*/
|
||||||
if (distance >= follow_distance) {
|
if (distance >= follow_distance) {
|
||||||
int speed = GetWalkspeed();
|
bool running = false;
|
||||||
|
|
||||||
if (distance >= follow_distance + 150) {
|
if (distance >= follow_distance + 150) {
|
||||||
speed = GetRunspeed();
|
running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool waypoint_changed, node_reached;
|
bool waypoint_changed, node_reached;
|
||||||
|
|
||||||
auto &Goal = follow->GetPosition();
|
auto &Goal = follow->GetPosition();
|
||||||
|
|
||||||
NavigateTo(Goal.x, Goal.y, Goal.z, speed);
|
if (running) {
|
||||||
|
RunTo(Goal.x, Goal.y, Goal.z);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
WalkTo(Goal.x, Goal.y, Goal.z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
moved = false;
|
moved = false;
|
||||||
@ -1694,7 +1684,7 @@ void NPC::AI_DoMovement() {
|
|||||||
roambox_destination_y);
|
roambox_destination_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigateTo(roambox_destination_x, roambox_destination_y, roambox_destination_z, move_speed);
|
NavigateTo(roambox_destination_x, roambox_destination_y, roambox_destination_z);
|
||||||
|
|
||||||
if (m_Position.x == roambox_destination_x && m_Position.y == roambox_destination_y) {
|
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);
|
time_until_can_move = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay);
|
||||||
@ -1761,8 +1751,7 @@ void NPC::AI_DoMovement() {
|
|||||||
NavigateTo(
|
NavigateTo(
|
||||||
m_CurrentWayPoint.x,
|
m_CurrentWayPoint.x,
|
||||||
m_CurrentWayPoint.y,
|
m_CurrentWayPoint.y,
|
||||||
m_CurrentWayPoint.z,
|
m_CurrentWayPoint.z
|
||||||
move_speed
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1782,10 +1771,9 @@ void NPC::AI_DoMovement() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
else if (IsGuarding()) {
|
else if (IsGuarding()) {
|
||||||
bool at_gp = IsPositionEqual(GetX(), GetY(), GetZ(), m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z);
|
bool at_gp = IsPositionEqual(m_Position, m_GuardPoint);
|
||||||
|
|
||||||
if (at_gp) {
|
if (at_gp) {
|
||||||
StopNavigation();
|
|
||||||
|
|
||||||
if (moved) {
|
if (moved) {
|
||||||
Log(Logs::Detail,
|
Log(Logs::Detail,
|
||||||
@ -1808,7 +1796,7 @@ void NPC::AI_DoMovement() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
NavigateTo(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, move_speed);
|
NavigateTo(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,53 +1,265 @@
|
|||||||
#include "mob_movement_manager.h"
|
#include "mob_movement_manager.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "mob.h"
|
#include "mob.h"
|
||||||
|
#include "zone.h"
|
||||||
|
#include "position.h"
|
||||||
#include "../common/eq_packet_structs.h"
|
#include "../common/eq_packet_structs.h"
|
||||||
#include "../common/misc_functions.h"
|
#include "../common/misc_functions.h"
|
||||||
|
#include "../common/data_verification.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
extern double frame_time;
|
extern double frame_time;
|
||||||
|
extern Zone *zone;
|
||||||
|
|
||||||
struct RotateCommand
|
class IMovementCommand
|
||||||
{
|
{
|
||||||
RotateCommand() {
|
public:
|
||||||
rotate_to = 0.0;
|
IMovementCommand() = default;
|
||||||
rotate_to_speed = 0.0;
|
virtual ~IMovementCommand() = default;
|
||||||
rotate_dir = 1.0;
|
virtual bool Process(MobMovementManager *mgr, Mob *m) = 0;
|
||||||
active = false;
|
virtual bool Started() const = 0;
|
||||||
started = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double rotate_to;
|
|
||||||
double rotate_to_speed;
|
|
||||||
double rotate_dir;
|
|
||||||
bool active;
|
|
||||||
bool started;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MovementCommand
|
class RotateToCommand : public IMovementCommand
|
||||||
{
|
{
|
||||||
MovementCommand() {
|
public:
|
||||||
move_to_x = 0.0;
|
RotateToCommand(double rotate_to, double dir, MobMovementMode mode) {
|
||||||
move_to_y = 0.0;
|
m_rotate_to = rotate_to;
|
||||||
move_to_z = 0.0;
|
m_rotate_to_dir = dir;
|
||||||
move_to_speed = 0.0;
|
m_rotate_to_mode = mode;
|
||||||
last_sent_short_distance = 0.0;
|
m_started = false;
|
||||||
last_sent_medium_distance = 0.0;
|
|
||||||
last_sent_long_distance = 0.0;
|
|
||||||
active = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double move_to_x;
|
virtual ~RotateToCommand() {
|
||||||
double move_to_y;
|
|
||||||
double move_to_z;
|
}
|
||||||
double move_to_speed;
|
|
||||||
double last_sent_short_distance;
|
virtual bool Process(MobMovementManager *mgr, Mob *m) {
|
||||||
double last_sent_medium_distance;
|
if (!m->IsAIControlled()) {
|
||||||
double last_sent_long_distance;
|
return true;
|
||||||
bool active;
|
}
|
||||||
|
|
||||||
|
auto rotate_to_speed = m_rotate_to_mode == MovementRunning ? 50.0 : 16.0; //todo: get this from mob
|
||||||
|
|
||||||
|
if (!m_started) {
|
||||||
|
m_started = 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto from = FixHeading(m->GetHeading());
|
||||||
|
auto to = FixHeading(m_rotate_to);
|
||||||
|
auto diff = to - from;
|
||||||
|
|
||||||
|
while (diff < -256.0) {
|
||||||
|
diff += 512.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (diff > 256) {
|
||||||
|
diff -= 512.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dist = std::abs(diff);
|
||||||
|
auto td = rotate_to_speed * 19.0 * frame_time;
|
||||||
|
|
||||||
|
if (td >= dist) {
|
||||||
|
m->SetHeading(to);
|
||||||
|
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
from += td * m_rotate_to_dir;
|
||||||
|
m->SetHeading(FixHeading(from));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Started() const {
|
||||||
|
return m_started;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
double m_rotate_to;
|
||||||
|
double m_rotate_to_dir;
|
||||||
|
MobMovementMode m_rotate_to_mode;
|
||||||
|
bool m_started;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MoveToCommand : public IMovementCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MoveToCommand(float x, float y, float z, MobMovementMode mode) {
|
||||||
|
m_move_to_x = x;
|
||||||
|
m_move_to_y = y;
|
||||||
|
m_move_to_z = z;
|
||||||
|
m_move_to_mode = mode;
|
||||||
|
m_last_sent_time = 0.0;
|
||||||
|
m_last_sent_speed = 0;
|
||||||
|
m_started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~MoveToCommand() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Process(MobMovementManager *mgr, Mob *m) {
|
||||||
|
if (!m->IsAIControlled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send a movement packet when you start moving
|
||||||
|
double current_time = static_cast<double>(Timer::GetCurrentTime()) / 1000.0;
|
||||||
|
int current_speed = 0;
|
||||||
|
|
||||||
|
if (m_move_to_mode == MovementRunning) {
|
||||||
|
current_speed = m->GetRunspeed();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
current_speed = m->GetWalkspeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_started) {
|
||||||
|
m_started = true;
|
||||||
|
//rotate to the point
|
||||||
|
m->SetHeading(m->CalculateHeadingToTarget(m_move_to_x, m_move_to_y));
|
||||||
|
|
||||||
|
m_last_sent_speed = current_speed;
|
||||||
|
m_last_sent_time = current_time;
|
||||||
|
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//When speed changes
|
||||||
|
if (current_speed != m_last_sent_speed) {
|
||||||
|
m_last_sent_speed = current_speed;
|
||||||
|
m_last_sent_time = current_time;
|
||||||
|
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If x seconds have passed without sending an update.
|
||||||
|
if (current_time - m_last_sent_time >= 5.0) {
|
||||||
|
m_last_sent_speed = current_speed;
|
||||||
|
m_last_sent_time = current_time;
|
||||||
|
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &p = m->GetPosition();
|
||||||
|
glm::vec3 tar(m_move_to_x, m_move_to_y, m_move_to_z);
|
||||||
|
glm::vec3 pos(p.x, p.y, p.z);
|
||||||
|
|
||||||
|
double len = glm::distance(pos, tar);
|
||||||
|
if (len == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 dir = tar - pos;
|
||||||
|
glm::vec3 ndir = glm::normalize(dir);
|
||||||
|
double distance_moved = frame_time * current_speed * 0.4f * 1.4f;
|
||||||
|
|
||||||
|
if (distance_moved > len) {
|
||||||
|
m->SetPosition(tar.x, tar.y, tar.z);
|
||||||
|
|
||||||
|
if (m->IsNPC()) {
|
||||||
|
entity_list.ProcessMove(m->CastToNPC(), tar.x, tar.y, tar.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
m->TryFixZ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glm::vec3 npos = pos + (ndir * static_cast<float>(distance_moved));
|
||||||
|
m->SetPosition(npos.x, npos.y, npos.z);
|
||||||
|
|
||||||
|
if (m->IsNPC()) {
|
||||||
|
entity_list.ProcessMove(m->CastToNPC(), npos.x, npos.y, npos.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Started() const {
|
||||||
|
return m_started;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
double m_move_to_x;
|
||||||
|
double m_move_to_y;
|
||||||
|
double m_move_to_z;
|
||||||
|
MobMovementMode m_move_to_mode;
|
||||||
|
bool m_started;
|
||||||
|
|
||||||
|
double m_last_sent_time;
|
||||||
|
int m_last_sent_speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TeleportToCommand : public IMovementCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TeleportToCommand(float x, float y, float z, float heading) {
|
||||||
|
m_teleport_to_x = x;
|
||||||
|
m_teleport_to_y = y;
|
||||||
|
m_teleport_to_z = z;
|
||||||
|
m_teleport_to_heading = heading;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TeleportToCommand() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Process(MobMovementManager *mgr, Mob *m) {
|
||||||
|
if (!m->IsAIControlled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m->SetPosition(m_teleport_to_x, m_teleport_to_y, m_teleport_to_z);
|
||||||
|
m->SetHeading(mgr->FixHeading(m_teleport_to_heading));
|
||||||
|
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Started() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
double m_teleport_to_x;
|
||||||
|
double m_teleport_to_y;
|
||||||
|
double m_teleport_to_z;
|
||||||
|
double m_teleport_to_heading;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StopMovingCommand : public IMovementCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StopMovingCommand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~StopMovingCommand() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Process(MobMovementManager *mgr, Mob *m) {
|
||||||
|
if (!m->IsAIControlled()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr->SendCommandToClients(m, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Started() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MovementStats
|
struct MovementStats
|
||||||
@ -65,10 +277,25 @@ struct MovementStats
|
|||||||
uint64_t TotalSentHeading;
|
uint64_t TotalSentHeading;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NavigateTo
|
||||||
|
{
|
||||||
|
NavigateTo() {
|
||||||
|
navigate_to_x = 0.0;
|
||||||
|
navigate_to_y = 0.0;
|
||||||
|
navigate_to_z = 0.0;
|
||||||
|
last_set_time = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double navigate_to_x;
|
||||||
|
double navigate_to_y;
|
||||||
|
double navigate_to_z;
|
||||||
|
double last_set_time;
|
||||||
|
};
|
||||||
|
|
||||||
struct MobMovementEntry
|
struct MobMovementEntry
|
||||||
{
|
{
|
||||||
RotateCommand RotateCommand;
|
std::deque<std::unique_ptr<IMovementCommand>> Commands;
|
||||||
MovementCommand MoveCommand;
|
NavigateTo NavigateTo;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MobMovementManager::Implementation
|
struct MobMovementManager::Implementation
|
||||||
@ -83,106 +310,6 @@ MobMovementManager::MobMovementManager()
|
|||||||
_impl.reset(new Implementation());
|
_impl.reset(new Implementation());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobMovementManager::ProcessRotateCommand(Mob *m, RotateCommand &cmd)
|
|
||||||
{
|
|
||||||
if (m->IsEngaged()) {
|
|
||||||
auto to = FixHeading(cmd.rotate_to);
|
|
||||||
m->SetHeading(to);
|
|
||||||
SendCommandToAllClients(m, 0.0, 0.0, 0.0, 0.0, 0);
|
|
||||||
cmd.active = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cmd.started) {
|
|
||||||
cmd.started = true;
|
|
||||||
|
|
||||||
SendCommandToAllClients(m, 0.0, 0.0, 0.0, cmd.rotate_dir * cmd.rotate_to_speed, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto from = FixHeading(m->GetHeading());
|
|
||||||
auto to = FixHeading(cmd.rotate_to);
|
|
||||||
float dist = 0.0;
|
|
||||||
if (cmd.rotate_dir > 0.0) {
|
|
||||||
if (to > from) {
|
|
||||||
dist = to - from;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dist = 512.0 - from + to;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (from > to) {
|
|
||||||
dist = from - to;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dist = (512.0 - to) + from;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto td = cmd.rotate_to_speed * 19.0 * frame_time;
|
|
||||||
|
|
||||||
if (td >= dist) {
|
|
||||||
m->SetHeading(to);
|
|
||||||
SendCommandToAllClients(m, 0.0, 0.0, 0.0, 0.0, 0);
|
|
||||||
cmd.active = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
from += td * cmd.rotate_dir;
|
|
||||||
m->SetHeading(FixHeading(from));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MobMovementManager::SendCommandToAllClients(Mob *m, float dx, float dy, float dz, float dh, int anim)
|
|
||||||
{
|
|
||||||
EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
|
||||||
PlayerPositionUpdateServer_Struct *spu = (PlayerPositionUpdateServer_Struct*)outapp.pBuffer;
|
|
||||||
FillCommandStruct(spu, m, dx, dy, dz, dh, anim);
|
|
||||||
|
|
||||||
for (auto &c : _impl->Clients) {
|
|
||||||
_impl->Stats.TotalSent++;
|
|
||||||
|
|
||||||
if (anim != 0) {
|
|
||||||
_impl->Stats.TotalSentMovement++;
|
|
||||||
}
|
|
||||||
else if (dh != 0) {
|
|
||||||
_impl->Stats.TotalSentHeading++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_impl->Stats.TotalSentPosition++;
|
|
||||||
}
|
|
||||||
|
|
||||||
c->QueuePacket(&outapp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MobMovementManager::FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim)
|
|
||||||
{
|
|
||||||
memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
|
|
||||||
spu->spawn_id = m->GetID();
|
|
||||||
spu->x_pos = FloatToEQ19(m->GetX());
|
|
||||||
spu->y_pos = FloatToEQ19(m->GetY());
|
|
||||||
spu->z_pos = FloatToEQ19(m->GetZ());
|
|
||||||
spu->heading = FloatToEQ12(m->GetHeading());
|
|
||||||
spu->delta_x = FloatToEQ13(dx);
|
|
||||||
spu->delta_y = FloatToEQ13(dy);
|
|
||||||
spu->delta_z = FloatToEQ13(dz);
|
|
||||||
spu->delta_heading = FloatToEQ10(dh);
|
|
||||||
spu->animation = anim;
|
|
||||||
}
|
|
||||||
|
|
||||||
float MobMovementManager::FixHeading(float in)
|
|
||||||
{
|
|
||||||
auto h = in;
|
|
||||||
while (h > 512.0) {
|
|
||||||
h -= 512.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (h < 0.0) {
|
|
||||||
h += 512.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
MobMovementManager::~MobMovementManager()
|
MobMovementManager::~MobMovementManager()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -191,12 +318,17 @@ void MobMovementManager::Process()
|
|||||||
{
|
{
|
||||||
for (auto &iter : _impl->Entries) {
|
for (auto &iter : _impl->Entries) {
|
||||||
auto &ent = iter.second;
|
auto &ent = iter.second;
|
||||||
|
auto &commands = ent.Commands;
|
||||||
|
|
||||||
if (ent.RotateCommand.active) {
|
while (true != commands.empty()) {
|
||||||
ProcessRotateCommand(iter.first, ent.RotateCommand);
|
auto &cmd = commands.front();
|
||||||
|
auto r = cmd->Process(this, iter.first);
|
||||||
|
|
||||||
|
if (true != r) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (ent.MoveCommand.active) {
|
|
||||||
|
|
||||||
|
commands.pop_front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,52 +361,250 @@ void MobMovementManager::RemoveClient(Client *c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobMovementManager::RotateTo(Mob *who, float to, float speed)
|
void MobMovementManager::RotateTo(Mob *who, float to, MobMovementMode mode)
|
||||||
{
|
{
|
||||||
auto iter = _impl->Entries.find(who);
|
auto iter = _impl->Entries.find(who);
|
||||||
auto &ent = (*iter);
|
auto &ent = (*iter);
|
||||||
|
|
||||||
auto from = FixHeading(who->GetHeading());
|
if (true != ent.second.Commands.empty()) {
|
||||||
to = FixHeading(to);
|
return;
|
||||||
|
|
||||||
ent.second.RotateCommand.active = true;
|
|
||||||
ent.second.RotateCommand.started = false;
|
|
||||||
ent.second.RotateCommand.rotate_to = to;
|
|
||||||
ent.second.RotateCommand.rotate_to_speed = speed;
|
|
||||||
|
|
||||||
double pdist = 0.0;
|
|
||||||
double ndist = 0.0;
|
|
||||||
if (to > from) {
|
|
||||||
pdist = to - from;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pdist = 512.0 - from + to;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from > to) {
|
PushRotateTo(ent.second, who, to, mode);
|
||||||
ndist = from - to;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ndist = (512.0 - to) + from;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdist <= ndist) {
|
|
||||||
ent.second.RotateCommand.rotate_dir = 1.0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ent.second.RotateCommand.rotate_dir = -1.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobMovementManager::Teleport(Mob *who, float x, float y, float z, float heading)
|
void MobMovementManager::Teleport(Mob *who, float x, float y, float z, float heading)
|
||||||
{
|
{
|
||||||
|
auto iter = _impl->Entries.find(who);
|
||||||
|
auto &ent = (*iter);
|
||||||
|
|
||||||
|
ent.second.Commands.clear();
|
||||||
|
|
||||||
|
PushTeleportTo(ent.second, x, y, z, heading);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, float speed)
|
void MobMovementManager::NavigateTo(Mob *who, float x, float y, float z, bool force, 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) {
|
||||||
|
//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) {
|
||||||
|
//Path is no longer valid, calculate a new path
|
||||||
|
UpdatePath(who, x, y, z, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MobMovementManager::StopNavigation(Mob *who) {
|
void MobMovementManager::StopNavigation(Mob *who) {
|
||||||
|
auto iter = _impl->Entries.find(who);
|
||||||
|
auto &ent = (*iter);
|
||||||
|
|
||||||
|
if (true == ent.second.Commands.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &running_cmd = ent.second.Commands.front();
|
||||||
|
if (false == running_cmd->Started()) {
|
||||||
|
ent.second.Commands.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendCommandToClients(who, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
|
||||||
|
ent.second.Commands.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MobMovementManager::SendCommandToClients(Mob *m, float dx, float dy, float dz, float dh, int anim, ClientRange range)
|
||||||
|
{
|
||||||
|
if (range == ClientRangeNone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EQApplicationPacket outapp(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
|
||||||
|
PlayerPositionUpdateServer_Struct *spu = (PlayerPositionUpdateServer_Struct*)outapp.pBuffer;
|
||||||
|
FillCommandStruct(spu, m, dx, dy, dz, dh, anim);
|
||||||
|
|
||||||
|
if (range == ClientRangeAny) {
|
||||||
|
for (auto &c : _impl->Clients) {
|
||||||
|
_impl->Stats.TotalSent++;
|
||||||
|
|
||||||
|
if (anim != 0) {
|
||||||
|
_impl->Stats.TotalSentMovement++;
|
||||||
|
}
|
||||||
|
else if (dh != 0) {
|
||||||
|
_impl->Stats.TotalSentHeading++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_impl->Stats.TotalSentPosition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->QueuePacket(&outapp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (auto &c : _impl->Clients) {
|
||||||
|
float dist = c->CalculateDistance(m->GetX(), m->GetY(), m->GetZ());
|
||||||
|
|
||||||
|
bool match = false;
|
||||||
|
if (range & ClientRangeClose) {
|
||||||
|
if (dist < 200.0f) {
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match && range & ClientRangeMedium) {
|
||||||
|
if (dist >= 200.0f && dist < 1000.0f) {
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match && range & ClientRangeLong) {
|
||||||
|
if (dist >= 1000.0f) {
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
_impl->Stats.TotalSent++;
|
||||||
|
|
||||||
|
if (anim != 0) {
|
||||||
|
_impl->Stats.TotalSentMovement++;
|
||||||
|
}
|
||||||
|
else if (dh != 0) {
|
||||||
|
_impl->Stats.TotalSentHeading++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_impl->Stats.TotalSentPosition++;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->QueuePacket(&outapp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float MobMovementManager::FixHeading(float in)
|
||||||
|
{
|
||||||
|
auto h = in;
|
||||||
|
while (h > 512.0) {
|
||||||
|
h -= 512.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (h < 0.0) {
|
||||||
|
h += 512.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MobMovementManager::FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim)
|
||||||
|
{
|
||||||
|
memset(spu, 0x00, sizeof(PlayerPositionUpdateServer_Struct));
|
||||||
|
spu->spawn_id = m->GetID();
|
||||||
|
spu->x_pos = FloatToEQ19(m->GetX());
|
||||||
|
spu->y_pos = FloatToEQ19(m->GetY());
|
||||||
|
spu->z_pos = FloatToEQ19(m->GetZ());
|
||||||
|
spu->heading = FloatToEQ12(m->GetHeading());
|
||||||
|
spu->delta_x = FloatToEQ13(dx);
|
||||||
|
spu->delta_y = FloatToEQ13(dy);
|
||||||
|
spu->delta_z = FloatToEQ13(dz);
|
||||||
|
spu->delta_heading = FloatToEQ10(dh);
|
||||||
|
spu->animation = anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode)
|
||||||
|
{
|
||||||
|
bool partial = false;
|
||||||
|
bool stuck = false;
|
||||||
|
auto route = zone->pathing->FindRoute(glm::vec3(who->GetX(), who->GetY(), who->GetZ()), glm::vec3(x, y, z), partial, stuck);
|
||||||
|
|
||||||
|
if (route.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &first = route.front();
|
||||||
|
|
||||||
|
//if who is already at the first node, then cull it
|
||||||
|
if (IsPositionEqualWithinCertainZ(glm::vec3(who->GetX(), who->GetY(), who->GetZ()), first.pos, 5.0f)) {
|
||||||
|
route.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (route.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto iter = _impl->Entries.find(who);
|
||||||
|
auto &ent = (*iter);
|
||||||
|
|
||||||
|
first = route.front();
|
||||||
|
//If mode = walking then rotateto first node (if possible, live does this)
|
||||||
|
if (mode == MovementWalking) {
|
||||||
|
auto h = who->CalculateHeadingToTarget(first.pos.x, first.pos.y);
|
||||||
|
PushRotateTo(ent.second, who, h, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//for each node create a moveto/teleport command
|
||||||
|
glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ());
|
||||||
|
for (auto &node : route) {
|
||||||
|
if (node.teleport) {
|
||||||
|
PushTeleportTo(ent.second, node.pos.x, node.pos.y, node.pos.z,
|
||||||
|
CalculateHeadingAngleBetweenPositions(previous_pos.x, previous_pos.y, node.pos.x, node.pos.y));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PushMoveTo(ent.second, node.pos.x, node.pos.y, node.pos.z, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_pos = node.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stuck) {
|
||||||
|
PushTeleportTo(ent.second, x, y, z,
|
||||||
|
CalculateHeadingAngleBetweenPositions(previous_pos.x, previous_pos.y, x, y));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PushStopMoving(ent.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MobMovementManager::PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading)
|
||||||
|
{
|
||||||
|
ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new TeleportToCommand(x, y, z, heading)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MobMovementManager::PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode)
|
||||||
|
{
|
||||||
|
ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new MoveToCommand(x, y, z, mode)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode)
|
||||||
|
{
|
||||||
|
auto from = FixHeading(who->GetHeading());
|
||||||
|
to = FixHeading(to);
|
||||||
|
|
||||||
|
float diff = to - from;
|
||||||
|
|
||||||
|
if (std::abs(diff) < 0.001f) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (diff < -256.0) {
|
||||||
|
diff += 512.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (diff > 256) {
|
||||||
|
diff -= 512.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new RotateToCommand(to, diff > 0 ? 1.0 : -1.0, mode)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MobMovementManager::PushStopMoving(MobMovementEntry &ent)
|
||||||
|
{
|
||||||
|
ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new StopMovingCommand()));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,28 @@ class Mob;
|
|||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
struct RotateCommand;
|
struct RotateCommand;
|
||||||
|
struct MovementCommand;
|
||||||
|
struct MobMovementEntry;
|
||||||
struct PlayerPositionUpdateServer_Struct;
|
struct PlayerPositionUpdateServer_Struct;
|
||||||
|
|
||||||
|
enum ClientRange : int
|
||||||
|
{
|
||||||
|
ClientRangeNone = 0,
|
||||||
|
ClientRangeClose = 1,
|
||||||
|
ClientRangeMedium = 2,
|
||||||
|
ClientRangeCloseMedium = 3,
|
||||||
|
ClientRangeLong = 4,
|
||||||
|
ClientRangeCloseLong = 5,
|
||||||
|
ClientRangeMediumLong = 6,
|
||||||
|
ClientRangeAny = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MobMovementMode : int
|
||||||
|
{
|
||||||
|
MovementWalking = 0,
|
||||||
|
MovementRunning = 1
|
||||||
|
};
|
||||||
|
|
||||||
class MobMovementManager
|
class MobMovementManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -17,10 +37,12 @@ public:
|
|||||||
void AddClient(Client *c);
|
void AddClient(Client *c);
|
||||||
void RemoveClient(Client *c);
|
void RemoveClient(Client *c);
|
||||||
|
|
||||||
void RotateTo(Mob *who, float to, float speed);
|
void RotateTo(Mob *who, float to, MobMovementMode mode = MovementRunning);
|
||||||
void Teleport(Mob *who, float x, float y, float z, float heading);
|
void Teleport(Mob *who, float x, float y, float z, float heading);
|
||||||
void NavigateTo(Mob *who, float x, float y, float z, float speed);
|
void NavigateTo(Mob *who, float x, float y, float z, bool force = false, MobMovementMode mode = MovementRunning);
|
||||||
void StopNavigation(Mob *who);
|
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 Dump(Mob *m, Client *to);
|
||||||
//void DumpStats(Client *to);
|
//void DumpStats(Client *to);
|
||||||
//void ClearStats();
|
//void ClearStats();
|
||||||
@ -35,10 +57,12 @@ private:
|
|||||||
MobMovementManager(const MobMovementManager&);
|
MobMovementManager(const MobMovementManager&);
|
||||||
MobMovementManager& operator=(const MobMovementManager&);
|
MobMovementManager& operator=(const MobMovementManager&);
|
||||||
|
|
||||||
void ProcessRotateCommand(Mob *m, RotateCommand &cmd);
|
|
||||||
void SendCommandToAllClients(Mob *m, float dx, float dy, float dz, float dh, int anim);
|
|
||||||
void FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim);
|
void FillCommandStruct(PlayerPositionUpdateServer_Struct *spu, Mob *m, float dx, float dy, float dz, float dh, int anim);
|
||||||
float FixHeading(float in);
|
void UpdatePath(Mob *who, float x, float y, float z, MobMovementMode mode);
|
||||||
|
void PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading);
|
||||||
|
void PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mode);
|
||||||
|
void PushRotateTo(MobMovementEntry &ent, Mob *who, float to, MobMovementMode mode);
|
||||||
|
void PushStopMoving(MobMovementEntry &ent);
|
||||||
|
|
||||||
struct Implementation;
|
struct Implementation;
|
||||||
std::unique_ptr<Implementation> _impl;
|
std::unique_ptr<Implementation> _impl;
|
||||||
|
|||||||
@ -134,7 +134,7 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl
|
|||||||
glm::vec3 PathfinderNavmesh::GetRandomLocation()
|
glm::vec3 PathfinderNavmesh::GetRandomLocation()
|
||||||
{
|
{
|
||||||
if (!m_impl->nav_mesh) {
|
if (!m_impl->nav_mesh) {
|
||||||
return glm::vec3();
|
return glm::vec3(0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_impl->query) {
|
if (!m_impl->query) {
|
||||||
@ -155,7 +155,7 @@ glm::vec3 PathfinderNavmesh::GetRandomLocation()
|
|||||||
return glm::vec3(point[0], point[2], point[1]);
|
return glm::vec3(point[0], point[2], point[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return glm::vec3();
|
return glm::vec3(0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathfinderNavmesh::DebugCommand(Client *c, const Seperator *sep)
|
void PathfinderNavmesh::DebugCommand(Client *c, const Seperator *sep)
|
||||||
|
|||||||
187
zone/pathing.cpp
187
zone/pathing.cpp
@ -22,193 +22,6 @@ void AdjustRoute(std::list<IPathfinder::IPathNode> &nodes, int flymode, float of
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 Mob::UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChanged, bool &NodeReached)
|
|
||||||
{
|
|
||||||
glm::vec3 To(ToX, ToY, ToZ);
|
|
||||||
if (Speed <= 0) {
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 From(GetX(), GetY(), GetZ());
|
|
||||||
|
|
||||||
if (DistanceSquared(To, From) < 1.0f) {
|
|
||||||
WaypointChanged = false;
|
|
||||||
NodeReached = true;
|
|
||||||
Route.clear();
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Route.empty()) {
|
|
||||||
bool partial = false;
|
|
||||||
bool stuck = false;
|
|
||||||
Route = zone->pathing->FindRoute(From, To, partial, stuck);
|
|
||||||
AdjustRoute(Route, flymode, GetZOffset());
|
|
||||||
|
|
||||||
PathingDestination = To;
|
|
||||||
WaypointChanged = true;
|
|
||||||
NodeReached = false;
|
|
||||||
if (stuck) {
|
|
||||||
return HandleStuckPath(To, From);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Route.empty()) {
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (*Route.begin()).pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (PathRecalcTimer->Check()) {
|
|
||||||
bool SameDestination = DistanceSquared(To, PathingDestination) < 100.0f;
|
|
||||||
if (!SameDestination) {
|
|
||||||
//We had a route but our target position moved too much
|
|
||||||
bool partial = false;
|
|
||||||
bool stuck = false;
|
|
||||||
Route = zone->pathing->FindRoute(From, To, partial, stuck);
|
|
||||||
AdjustRoute(Route, flymode, GetZOffset());
|
|
||||||
|
|
||||||
PathingDestination = To;
|
|
||||||
WaypointChanged = true;
|
|
||||||
NodeReached = false;
|
|
||||||
|
|
||||||
if (stuck) {
|
|
||||||
return HandleStuckPath(To, From);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Route.empty()) {
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (*Route.begin()).pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsRooted()) {
|
|
||||||
bool AtPrevNode = DistanceSquared(From, PathingLastPosition) < 1.0f;
|
|
||||||
if (AtPrevNode) {
|
|
||||||
PathingLoopCount++;
|
|
||||||
auto front = (*Route.begin()).pos;
|
|
||||||
|
|
||||||
if (PathingLoopCount > 5) {
|
|
||||||
Teleport(front); //todo new teleport
|
|
||||||
SendPosition();
|
|
||||||
Route.pop_front();
|
|
||||||
|
|
||||||
WaypointChanged = true;
|
|
||||||
NodeReached = true;
|
|
||||||
PathingLoopCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return front;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PathingLastPosition = From;
|
|
||||||
PathingLoopCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PathingLastPosition = From;
|
|
||||||
PathingLoopCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AtNextNode = false;
|
|
||||||
if (flymode == GravityBehavior::Flying) {
|
|
||||||
AtNextNode = DistanceSquared(From, (*Route.begin()).pos) < 4.0f;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
float z_dist = From.z - (*Route.begin()).pos.z;
|
|
||||||
z_dist *= z_dist;
|
|
||||||
AtNextNode = DistanceSquaredNoZ(From, (*Route.begin()).pos) < 4.0f && z_dist < 25.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AtNextNode) {
|
|
||||||
WaypointChanged = false;
|
|
||||||
NodeReached = true;
|
|
||||||
|
|
||||||
Route.pop_front();
|
|
||||||
|
|
||||||
if (Route.empty()) {
|
|
||||||
bool partial = false;
|
|
||||||
bool stuck = false;
|
|
||||||
Route = zone->pathing->FindRoute(From, To, partial, stuck);
|
|
||||||
AdjustRoute(Route, flymode, GetZOffset());
|
|
||||||
|
|
||||||
PathingDestination = To;
|
|
||||||
WaypointChanged = true;
|
|
||||||
|
|
||||||
if (stuck) {
|
|
||||||
return HandleStuckPath(To, From);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Route.empty()) {
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return (*Route.begin()).pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto node = *Route.begin();
|
|
||||||
if (node.teleport) {
|
|
||||||
Route.pop_front();
|
|
||||||
|
|
||||||
if (Route.empty()) {
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto nextNode = *Route.begin();
|
|
||||||
|
|
||||||
Teleport(nextNode.pos);
|
|
||||||
|
|
||||||
Route.pop_front();
|
|
||||||
|
|
||||||
if (Route.empty()) {
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (*Route.begin()).pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
return node.pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
WaypointChanged = false;
|
|
||||||
NodeReached = false;
|
|
||||||
return (*Route.begin()).pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 Mob::HandleStuckPath(const glm::vec3 &To, const glm::vec3 &From)
|
|
||||||
{
|
|
||||||
bool partial = false;
|
|
||||||
bool stuck = false;
|
|
||||||
auto r = zone->pathing->FindRoute(To, From, partial, stuck);
|
|
||||||
Route.clear();
|
|
||||||
|
|
||||||
if (r.size() < 1) {
|
|
||||||
Teleport(To);
|
|
||||||
return To;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto iter = r.rbegin();
|
|
||||||
auto final_node = (*iter);
|
|
||||||
Teleport(final_node.pos);
|
|
||||||
|
|
||||||
if (r.size() < 2) {
|
|
||||||
return final_node.pos;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
iter++;
|
|
||||||
return (*iter).pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CullPoints(std::vector<FindPerson_Point> &points) {
|
void CullPoints(std::vector<FindPerson_Point> &points) {
|
||||||
if (!zone->HasMap()) {
|
if (!zone->HasMap()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -5477,18 +5477,71 @@ XS(XS_Mob_CalculateHeadingToTarget) {
|
|||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
XS(XS_Mob_NavigateTo); /* prototype to pass -Wmissing-prototypes */
|
XS(XS_Mob_RunTo); /* prototype to pass -Wmissing-prototypes */
|
||||||
XS(XS_Mob_NavigateTo) {
|
XS(XS_Mob_RunTo) {
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
if (items < 5 || items > 6)
|
if (items < 4 || items > 5)
|
||||||
Perl_croak(aTHX_
|
Perl_croak(aTHX_
|
||||||
"Usage: Mob::NavigateTo(THIS, float x, float y, float z, float speed)");
|
"Usage: Mob::RunTo(THIS, float x, float y, float z)");
|
||||||
|
{
|
||||||
|
Mob *THIS;
|
||||||
|
float x = (float)SvNV(ST(1));
|
||||||
|
float y = (float)SvNV(ST(2));
|
||||||
|
float z = (float)SvNV(ST(3));
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "Mob")) {
|
||||||
|
IV tmp = SvIV((SV *)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(Mob *, tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||||
|
if (THIS == nullptr)
|
||||||
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
|
|
||||||
|
THIS->RunTo(x, y, z);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(XS_Mob_WalkTo); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_Mob_WalkTo) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items < 4 || items > 5)
|
||||||
|
Perl_croak(aTHX_
|
||||||
|
"Usage: Mob::WalkTo(THIS, float x, float y, float z)");
|
||||||
|
{
|
||||||
|
Mob *THIS;
|
||||||
|
float x = (float)SvNV(ST(1));
|
||||||
|
float y = (float)SvNV(ST(2));
|
||||||
|
float z = (float)SvNV(ST(3));
|
||||||
|
|
||||||
|
if (sv_derived_from(ST(0), "Mob")) {
|
||||||
|
IV tmp = SvIV((SV *)SvRV(ST(0)));
|
||||||
|
THIS = INT2PTR(Mob *, tmp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||||
|
if (THIS == nullptr)
|
||||||
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
|
|
||||||
|
THIS->WalkTo(x, y, z);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(XS_Mob_NavigateTo); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_Mob_NavigateTo) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items < 4 || items > 5)
|
||||||
|
Perl_croak(aTHX_
|
||||||
|
"Usage: Mob::NavigateTo(THIS, float x, float y, float z)");
|
||||||
{
|
{
|
||||||
Mob *THIS;
|
Mob *THIS;
|
||||||
float x = (float) SvNV(ST(1));
|
float x = (float) SvNV(ST(1));
|
||||||
float y = (float) SvNV(ST(2));
|
float y = (float) SvNV(ST(2));
|
||||||
float z = (float) SvNV(ST(3));
|
float z = (float) SvNV(ST(3));
|
||||||
float speed = (float) SvNV(ST(4));
|
|
||||||
|
|
||||||
if (sv_derived_from(ST(0), "Mob")) {
|
if (sv_derived_from(ST(0), "Mob")) {
|
||||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||||
@ -5499,7 +5552,7 @@ XS(XS_Mob_NavigateTo) {
|
|||||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
|
|
||||||
THIS->NavigateTo(x, y, z, speed);
|
THIS->NavigateTo(x, y, z);
|
||||||
}
|
}
|
||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
@ -8660,7 +8713,9 @@ XS(boot_Mob) {
|
|||||||
newXSproto(strcpy(buf, "WipeHateList"), XS_Mob_WipeHateList, file, "$");
|
newXSproto(strcpy(buf, "WipeHateList"), XS_Mob_WipeHateList, file, "$");
|
||||||
newXSproto(strcpy(buf, "CheckAggro"), XS_Mob_CheckAggro, file, "$$");
|
newXSproto(strcpy(buf, "CheckAggro"), XS_Mob_CheckAggro, file, "$$");
|
||||||
newXSproto(strcpy(buf, "CalculateHeadingToTarget"), XS_Mob_CalculateHeadingToTarget, file, "$$$");
|
newXSproto(strcpy(buf, "CalculateHeadingToTarget"), XS_Mob_CalculateHeadingToTarget, file, "$$$");
|
||||||
newXSproto(strcpy(buf, "NavigateTo"), XS_Mob_NavigateTo, file, "$$$$$");
|
newXSproto(strcpy(buf, "RunTo"), XS_Mob_RunTo, file, "$$$$");
|
||||||
|
newXSproto(strcpy(buf, "WalkTo"), XS_Mob_WalkTo, file, "$$$$");
|
||||||
|
newXSproto(strcpy(buf, "NavigateTo"), XS_Mob_NavigateTo, file, "$$$$");
|
||||||
newXSproto(strcpy(buf, "StopNavigation"), XS_Mob_StopNavigation, file, "$");
|
newXSproto(strcpy(buf, "StopNavigation"), XS_Mob_StopNavigation, file, "$");
|
||||||
newXSproto(strcpy(buf, "CalculateDistance"), XS_Mob_CalculateDistance, file, "$$$$");
|
newXSproto(strcpy(buf, "CalculateDistance"), XS_Mob_CalculateDistance, file, "$$$$");
|
||||||
newXSproto(strcpy(buf, "SendTo"), XS_Mob_SendTo, file, "$$$$");
|
newXSproto(strcpy(buf, "SendTo"), XS_Mob_SendTo, file, "$$$$");
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "../common/string_util.h"
|
#include "../common/string_util.h"
|
||||||
|
|
||||||
|
static const float position_eps = 0.0001f;
|
||||||
|
|
||||||
std::string to_string(const glm::vec4 &position) {
|
std::string to_string(const glm::vec4 &position) {
|
||||||
return StringFormat("(%.3f, %.3f, %.3f, %.3f)", position.x,position.y,position.z,position.w);
|
return StringFormat("(%.3f, %.3f, %.3f, %.3f)", position.x,position.y,position.z,position.w);
|
||||||
}
|
}
|
||||||
@ -161,8 +163,88 @@ float GetReciprocalHeading(const float heading)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPositionEqual(float x1, float y1, float z1, float x2, float y2, float z2)
|
bool IsPositionEqual(const glm::vec2 &p1, const glm::vec2 &p2)
|
||||||
{
|
{
|
||||||
static const float eps = 0.0001f;
|
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps;
|
||||||
return std::abs(x1 - x2) < eps && std::abs(y1 - y2) < eps && std::abs(z1 - z2) < eps;
|
}
|
||||||
|
|
||||||
|
bool IsPositionEqual(const glm::vec3 &p1, const glm::vec3 &p2)
|
||||||
|
{
|
||||||
|
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps && std::abs(p1.z - p2.z) < position_eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPositionEqual(const glm::vec4 &p1, const glm::vec4 &p2)
|
||||||
|
{
|
||||||
|
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps && std::abs(p1.z - p2.z) < position_eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPositionEqualWithinCertainZ(const glm::vec3 &p1, const glm::vec3 &p2, float z_eps) {
|
||||||
|
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps && std::abs(p1.z - p2.z) < z_eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPositionEqualWithinCertainZ(const glm::vec4 &p1, const glm::vec4 &p2, float z_eps) {
|
||||||
|
return std::abs(p1.x - p2.x) < position_eps && std::abs(p1.y - p2.y) < position_eps && std::abs(p1.z - p2.z) < z_eps;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPositionWithinSimpleCylinder(const glm::vec3 &p1, const glm::vec3 &cylinder_center, float cylinder_radius, float cylinder_height)
|
||||||
|
{
|
||||||
|
//If we're outside the height of cylinder then we're not in it (duh)
|
||||||
|
auto d = std::abs(p1.z - cylinder_center.z);
|
||||||
|
if (d > cylinder_height / 2.0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 p1d(p1.x, p1.y);
|
||||||
|
glm::vec2 ccd(cylinder_center.x, cylinder_center.y);
|
||||||
|
|
||||||
|
//If we're outside the radius of the cylinder then we're not in it (also duh)
|
||||||
|
d = Distance(p1d, ccd);
|
||||||
|
if (d > cylinder_radius) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPositionWithinSimpleCylinder(const glm::vec4 &p1, const glm::vec4 &cylinder_center, float cylinder_radius, float cylinder_height)
|
||||||
|
{
|
||||||
|
//If we're outside the height of cylinder then we're not in it (duh)
|
||||||
|
auto d = std::abs(p1.z - cylinder_center.z);
|
||||||
|
if (d > cylinder_height / 2.0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec2 p1d(p1.x, p1.y);
|
||||||
|
glm::vec2 ccd(cylinder_center.x, cylinder_center.y);
|
||||||
|
|
||||||
|
//If we're outside the radius of the cylinder then we're not in it (also duh)
|
||||||
|
d = Distance(p1d, ccd);
|
||||||
|
if (d > cylinder_radius) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float CalculateHeadingAngleBetweenPositions(float x1, float y1, float x2, float y2)
|
||||||
|
{
|
||||||
|
float y_diff = std::abs(y1 - y2);
|
||||||
|
float x_diff = std::abs(x1 - x2);
|
||||||
|
if (y_diff < 0.0000009999999974752427)
|
||||||
|
y_diff = 0.0000009999999974752427;
|
||||||
|
|
||||||
|
float angle = atan2(x_diff, y_diff) * 180.0f * 0.3183099014828645f; // angle, nice "pi"
|
||||||
|
|
||||||
|
// return the right thing based on relative quadrant
|
||||||
|
// I'm sure this could be improved for readability, but whatever
|
||||||
|
if (y1 >= y2) {
|
||||||
|
if (x2 >= x1)
|
||||||
|
return (90.0f - angle + 90.0f) * 511.5f * 0.0027777778f;
|
||||||
|
if (x2 <= x1)
|
||||||
|
return (angle + 180.0f) * 511.5f * 0.0027777778f;
|
||||||
|
}
|
||||||
|
if (y1 > y2 || x2 > x1)
|
||||||
|
return angle * 511.5f * 0.0027777778f;
|
||||||
|
else
|
||||||
|
return (90.0f - angle + 270.0f) * 511.5f * 0.0027777778f;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,15 @@ float DistanceSquaredNoZ(const glm::vec4& point1, const glm::vec4& point2);
|
|||||||
float GetReciprocalHeading(const glm::vec4& point1);
|
float GetReciprocalHeading(const glm::vec4& point1);
|
||||||
float GetReciprocalHeading(const float heading);
|
float GetReciprocalHeading(const float heading);
|
||||||
|
|
||||||
bool IsPositionEqual(float x1, float y1, float z1, float x2, float y2, float z2);
|
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);
|
||||||
|
bool IsPositionEqualWithinCertainZ(const glm::vec3 &p1, const glm::vec3 &p2, float z_eps);
|
||||||
|
bool IsPositionEqualWithinCertainZ(const glm::vec4 &p1, const glm::vec4 &p2, float z_eps);
|
||||||
|
|
||||||
|
bool IsPositionWithinSimpleCylinder(const glm::vec3 &p1, const glm::vec3 &cylinder_center, float cylinder_radius, float cylinder_height);
|
||||||
|
bool IsPositionWithinSimpleCylinder(const glm::vec4 &p1, const glm::vec4 &cylinder_center, float cylinder_radius, float cylinder_height);
|
||||||
|
|
||||||
|
float CalculateHeadingAngleBetweenPositions(float x1, float y1, float x2, float y2);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -427,7 +427,7 @@ void NPC::SaveGuardSpot(bool iClearGuardSpot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NPC::NextGuardPosition() {
|
void NPC::NextGuardPosition() {
|
||||||
NavigateTo(m_GuardPoint.x, m_GuardPoint.y, m_GuardPoint.z, GetMovespeed());
|
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 ((m_Position.x == m_GuardPoint.x) && (m_Position.y == m_GuardPoint.y) && (m_Position.z == m_GuardPoint.z))
|
||||||
{
|
{
|
||||||
if (moved)
|
if (moved)
|
||||||
@ -442,8 +442,24 @@ float Mob::CalculateDistance(float x, float y, float z) {
|
|||||||
return (float)sqrtf(((m_Position.x - x)*(m_Position.x - x)) + ((m_Position.y - y)*(m_Position.y - y)) + ((m_Position.z - z)*(m_Position.z - z)));
|
return (float)sqrtf(((m_Position.x - x)*(m_Position.x - x)) + ((m_Position.y - y)*(m_Position.y - y)) + ((m_Position.z - z)*(m_Position.z - z)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::NavigateTo(float x, float y, float z, float speed) {
|
void Mob::WalkTo(float x, float y, float z)
|
||||||
mMovementManager->NavigateTo(this, x, y, z, speed);
|
{
|
||||||
|
mMovementManager->NavigateTo(this, x, y, z, false, MovementWalking);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::RunTo(float x, float y, float z)
|
||||||
|
{
|
||||||
|
mMovementManager->NavigateTo(this, x, y, z, false, MovementRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mob::NavigateTo(float x, float y, float z)
|
||||||
|
{
|
||||||
|
if (IsRunning()) {
|
||||||
|
mMovementManager->NavigateTo(this, x, y, z, false, MovementRunning);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mMovementManager->NavigateTo(this, x, y, z, false, MovementWalking);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::StopNavigation() {
|
void Mob::StopNavigation() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user