diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 1a9420dd7..cc5414ac4 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1328,7 +1328,7 @@ void Client::Handle_OP_AutoAttack(const EQApplicationPacket *app) aa_los_them.y = aa_los_them_mob->GetY(); aa_los_them.z = aa_los_them_mob->GetZ(); los_status = CheckLosFN(aa_los_them_mob); - los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y); + los_status_facing = IsFacingMob(aa_los_them_mob); } else { diff --git a/zone/client_process.cpp b/zone/client_process.cpp index c28affd28..f245c1d44 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -361,13 +361,13 @@ bool Client::Process() { aa_los_them.z = aa_los_them_mob->GetZ(); los_status = CheckLosFN(auto_attack_target); aa_los_me_heading = GetHeading(); - los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y); + los_status_facing = IsFacingMob(aa_los_them_mob); } // If only our heading changes, we can skip the CheckLosFN call // but above we still need to update los_status_facing if (aa_los_me_heading != GetHeading()) { aa_los_me_heading = GetHeading(); - los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y); + los_status_facing = IsFacingMob(aa_los_them_mob); } } else @@ -381,7 +381,7 @@ bool Client::Process() { aa_los_them.y = aa_los_them_mob->GetY(); aa_los_them.z = aa_los_them_mob->GetZ(); los_status = CheckLosFN(auto_attack_target); - los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y); + los_status_facing = IsFacingMob(aa_los_them_mob); } if (!CombatRange(auto_attack_target)) diff --git a/zone/mob.cpp b/zone/mob.cpp index 6d5907014..cef5bd605 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -5046,3 +5046,52 @@ void Mob::ProcessSpecialAbilities(const std::string str) { } } } + +// derived from client to keep these functions more consistent +// if anything seems weird, blame SoE +bool Mob::IsFacingMob(Mob *other) +{ + float angle = HeadingAngleToMob(other); + // what the client uses appears to be 2x our internal heading + float heading = GetHeading() * 2.0; + + if (angle > 472.0 && heading < 40.0) + angle = heading; + if (angle < 40.0 && heading > 472.0) + angle = heading; + + if (fabs(angle - heading) <= 80.0) + return true; + + return false; +} + +// All numbers derived from the client +float Mob::HeadingAngleToMob(Mob *other) +{ + float mob_x = other->GetX(); + float mob_y = other->GetY(); + float this_x = GetX(); + float this_y = GetY(); + + float y_diff = fabs(this_y - mob_y); + float x_diff = fabs(this_x - mob_x); + if (y_diff < 0.0000009999999974752427) + y_diff = 0.0000009999999974752427; + + float angle = atan2(x_diff, y_diff) * 180.0 * 0.3183099014828645; // 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 >= mob_y) { + if (mob_x >= this_x) + return (90.0 - angle + 90.0) * 511.5 * 0.0027777778; + if (mob_x <= this_x) + return (angle + 180.0) * 511.5 * 0.0027777778; + } + if (this_y > mob_y || mob_x > this_x) + return angle * 511.5 * 0.0027777778; + else + return (90.0 - angle + 270.0) * 511.5 * 0.0027777778; +} + diff --git a/zone/mob.h b/zone/mob.h index 92b999d9d..1df559d16 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -125,6 +125,8 @@ public: // less than 56 is in front, greater than 56 is usually where the client generates the messages inline bool InFrontMob(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const { return (!other || other == this) ? true : MobAngle(other, ourx, oury) < 56.0f; } + bool IsFacingMob(Mob *other); // kind of does the same as InFrontMob, but derived from client + float HeadingAngleToMob(Mob *other); // to keep consistent with client generated messages virtual void RangedAttack(Mob* other) { } virtual void ThrowingAttack(Mob* other) { } uint16 GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg);