mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-16 05:11:29 +00:00
Added facing check to auto attack LoS code
The Mob::InFrontMob check uses 56 degrees which is where the client will generate the "You cannon see your target." message. There were still a few weird angles that I was able to still attack, but in like 99% of the cases it should work ...
This commit is contained in:
parent
9fff694382
commit
5ac23a2f8f
@ -284,11 +284,13 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
aa_los_me.x = 0;
|
aa_los_me.x = 0;
|
||||||
aa_los_me.y = 0;
|
aa_los_me.y = 0;
|
||||||
aa_los_me.z = 0;
|
aa_los_me.z = 0;
|
||||||
|
aa_los_me_heading = 0;
|
||||||
aa_los_them.x = 0;
|
aa_los_them.x = 0;
|
||||||
aa_los_them.y = 0;
|
aa_los_them.y = 0;
|
||||||
aa_los_them.z = 0;
|
aa_los_them.z = 0;
|
||||||
aa_los_them_mob = nullptr;
|
aa_los_them_mob = nullptr;
|
||||||
los_status = false;
|
los_status = false;
|
||||||
|
los_status_facing = false;
|
||||||
qGlobals = nullptr;
|
qGlobals = nullptr;
|
||||||
HideCorpseMode = HideCorpseNone;
|
HideCorpseMode = HideCorpseNone;
|
||||||
PendingGuildInvitation = false;
|
PendingGuildInvitation = false;
|
||||||
|
|||||||
@ -1200,6 +1200,8 @@ protected:
|
|||||||
VERTEX aa_los_them;
|
VERTEX aa_los_them;
|
||||||
Mob *aa_los_them_mob;
|
Mob *aa_los_them_mob;
|
||||||
bool los_status;
|
bool los_status;
|
||||||
|
float aa_los_me_heading;
|
||||||
|
bool los_status_facing;
|
||||||
QGlobalCache *qGlobals;
|
QGlobalCache *qGlobals;
|
||||||
|
|
||||||
/** Adventure Variables **/
|
/** Adventure Variables **/
|
||||||
|
|||||||
@ -1303,6 +1303,7 @@ void Client::Handle_OP_AutoAttack(const EQApplicationPacket *app)
|
|||||||
aa_los_me.x = 0;
|
aa_los_me.x = 0;
|
||||||
aa_los_me.y = 0;
|
aa_los_me.y = 0;
|
||||||
aa_los_me.z = 0;
|
aa_los_me.z = 0;
|
||||||
|
aa_los_me_heading = 0;
|
||||||
aa_los_them.x = 0;
|
aa_los_them.x = 0;
|
||||||
aa_los_them.y = 0;
|
aa_los_them.y = 0;
|
||||||
aa_los_them.z = 0;
|
aa_los_them.z = 0;
|
||||||
@ -1322,24 +1323,25 @@ void Client::Handle_OP_AutoAttack(const EQApplicationPacket *app)
|
|||||||
aa_los_me.x = GetX();
|
aa_los_me.x = GetX();
|
||||||
aa_los_me.y = GetY();
|
aa_los_me.y = GetY();
|
||||||
aa_los_me.z = GetZ();
|
aa_los_me.z = GetZ();
|
||||||
|
aa_los_me_heading = GetHeading();
|
||||||
aa_los_them.x = aa_los_them_mob->GetX();
|
aa_los_them.x = aa_los_them_mob->GetX();
|
||||||
aa_los_them.y = aa_los_them_mob->GetY();
|
aa_los_them.y = aa_los_them_mob->GetY();
|
||||||
aa_los_them.z = aa_los_them_mob->GetZ();
|
aa_los_them.z = aa_los_them_mob->GetZ();
|
||||||
if(CheckLosFN(aa_los_them_mob))
|
los_status = CheckLosFN(aa_los_them_mob);
|
||||||
los_status = true;
|
los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y);
|
||||||
else
|
|
||||||
los_status = false;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
aa_los_me.x = GetX();
|
aa_los_me.x = GetX();
|
||||||
aa_los_me.y = GetY();
|
aa_los_me.y = GetY();
|
||||||
aa_los_me.z = GetZ();
|
aa_los_me.z = GetZ();
|
||||||
|
aa_los_me_heading = GetHeading();
|
||||||
aa_los_them.x = 0;
|
aa_los_them.x = 0;
|
||||||
aa_los_them.y = 0;
|
aa_los_them.y = 0;
|
||||||
aa_los_them.z = 0;
|
aa_los_them.z = 0;
|
||||||
aa_los_them_mob = nullptr;
|
aa_los_them_mob = nullptr;
|
||||||
los_status = false;
|
los_status = false;
|
||||||
|
los_status_facing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -299,7 +299,7 @@ bool Client::Process() {
|
|||||||
if(ranged->GetItem() && ranged->GetItem()->ItemType == ItemTypeBow){
|
if(ranged->GetItem() && ranged->GetItem()->ItemType == ItemTypeBow){
|
||||||
if(ranged_timer.Check(false)){
|
if(ranged_timer.Check(false)){
|
||||||
if(GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())){
|
if(GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())){
|
||||||
if(!GetTarget()->BehindMob(this, GetTarget()->GetX(), GetTarget()->GetY())){
|
if(GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())){
|
||||||
if(CheckLosFN(GetTarget())){
|
if(CheckLosFN(GetTarget())){
|
||||||
//client has built in los check, but auto fire does not.. done last.
|
//client has built in los check, but auto fire does not.. done last.
|
||||||
RangedAttack(GetTarget());
|
RangedAttack(GetTarget());
|
||||||
@ -319,7 +319,7 @@ bool Client::Process() {
|
|||||||
else if(ranged->GetItem() && (ranged->GetItem()->ItemType == ItemTypeLargeThrowing || ranged->GetItem()->ItemType == ItemTypeSmallThrowing)){
|
else if(ranged->GetItem() && (ranged->GetItem()->ItemType == ItemTypeLargeThrowing || ranged->GetItem()->ItemType == ItemTypeSmallThrowing)){
|
||||||
if(ranged_timer.Check(false)){
|
if(ranged_timer.Check(false)){
|
||||||
if(GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())){
|
if(GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient())){
|
||||||
if(!GetTarget()->BehindMob(this, GetTarget()->GetX(), GetTarget()->GetY())){
|
if(GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())){
|
||||||
if(CheckLosFN(GetTarget())){
|
if(CheckLosFN(GetTarget())){
|
||||||
//client has built in los check, but auto fire does not.. done last.
|
//client has built in los check, but auto fire does not.. done last.
|
||||||
ThrowingAttack(GetTarget());
|
ThrowingAttack(GetTarget());
|
||||||
@ -359,10 +359,15 @@ bool Client::Process() {
|
|||||||
aa_los_them.x = aa_los_them_mob->GetX();
|
aa_los_them.x = aa_los_them_mob->GetX();
|
||||||
aa_los_them.y = aa_los_them_mob->GetY();
|
aa_los_them.y = aa_los_them_mob->GetY();
|
||||||
aa_los_them.z = aa_los_them_mob->GetZ();
|
aa_los_them.z = aa_los_them_mob->GetZ();
|
||||||
if(CheckLosFN(auto_attack_target))
|
los_status = CheckLosFN(auto_attack_target);
|
||||||
los_status = true;
|
aa_los_me_heading = GetHeading();
|
||||||
else
|
los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y);
|
||||||
los_status = false;
|
}
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -371,25 +376,23 @@ bool Client::Process() {
|
|||||||
aa_los_me.x = GetX();
|
aa_los_me.x = GetX();
|
||||||
aa_los_me.y = GetY();
|
aa_los_me.y = GetY();
|
||||||
aa_los_me.z = GetZ();
|
aa_los_me.z = GetZ();
|
||||||
|
aa_los_me_heading = GetHeading();
|
||||||
aa_los_them.x = aa_los_them_mob->GetX();
|
aa_los_them.x = aa_los_them_mob->GetX();
|
||||||
aa_los_them.y = aa_los_them_mob->GetY();
|
aa_los_them.y = aa_los_them_mob->GetY();
|
||||||
aa_los_them.z = aa_los_them_mob->GetZ();
|
aa_los_them.z = aa_los_them_mob->GetZ();
|
||||||
if(CheckLosFN(auto_attack_target))
|
los_status = CheckLosFN(auto_attack_target);
|
||||||
los_status = true;
|
los_status_facing = aa_los_them_mob->InFrontMob(this, aa_los_them.x, aa_los_them.y);
|
||||||
else
|
|
||||||
los_status = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CombatRange(auto_attack_target))
|
if (!CombatRange(auto_attack_target))
|
||||||
{
|
{
|
||||||
//duplicate message not wanting to see it.
|
Message_StringID(MT_TooFarAway,TARGET_TOO_FAR);
|
||||||
//Message_StringID(MT_TooFarAway,TARGET_TOO_FAR);
|
|
||||||
}
|
}
|
||||||
else if (auto_attack_target == this)
|
else if (auto_attack_target == this)
|
||||||
{
|
{
|
||||||
Message_StringID(MT_TooFarAway,TRY_ATTACKING_SOMEONE);
|
Message_StringID(MT_TooFarAway,TRY_ATTACKING_SOMEONE);
|
||||||
}
|
}
|
||||||
else if (!los_status)
|
else if (!los_status || !los_status_facing)
|
||||||
{
|
{
|
||||||
//you can't see your target
|
//you can't see your target
|
||||||
}
|
}
|
||||||
@ -482,13 +485,13 @@ bool Client::Process() {
|
|||||||
// Range check
|
// Range check
|
||||||
if(!CombatRange(auto_attack_target)) {
|
if(!CombatRange(auto_attack_target)) {
|
||||||
// this is a duplicate message don't use it.
|
// this is a duplicate message don't use it.
|
||||||
Message_StringID(MT_TooFarAway,TARGET_TOO_FAR);
|
//Message_StringID(MT_TooFarAway,TARGET_TOO_FAR);
|
||||||
}
|
}
|
||||||
// Don't attack yourself
|
// Don't attack yourself
|
||||||
else if(auto_attack_target == this) {
|
else if(auto_attack_target == this) {
|
||||||
Message_StringID(MT_TooFarAway,TRY_ATTACKING_SOMEONE);
|
//Message_StringID(MT_TooFarAway,TRY_ATTACKING_SOMEONE);
|
||||||
}
|
}
|
||||||
else if (!los_status)
|
else if (!los_status || !los_status_facing)
|
||||||
{
|
{
|
||||||
//you can't see your target
|
//you can't see your target
|
||||||
}
|
}
|
||||||
|
|||||||
40
zone/mob.cpp
40
zone/mob.cpp
@ -1876,35 +1876,43 @@ void Mob::SetOwnerID(uint16 NewOwnerID) {
|
|||||||
this->Depop();
|
this->Depop();
|
||||||
}
|
}
|
||||||
|
|
||||||
//heko: for backstab
|
// used in checking for behind (backstab) and checking in front (melee LoS)
|
||||||
bool Mob::BehindMob(Mob* other, float playerx, float playery) const {
|
float Mob::MobAngle(Mob *other, float ourx, float oury) const {
|
||||||
if (!other)
|
if (!other || other == this)
|
||||||
return true; // sure your behind your invisible friend?? (fall thru for sneak)
|
return 0.0f;
|
||||||
//see if player is behind mob
|
|
||||||
float angle, lengthb, vectorx, vectory;
|
float angle, lengthb, vectorx, vectory, dotp;
|
||||||
float mobx = -(other->GetX()); // mob xlocation (inverse because eq is confused)
|
float mobx = -(other->GetX()); // mob xloc (inverse because eq)
|
||||||
float moby = other->GetY(); // mobylocation
|
float moby = other->GetY(); // mob yloc
|
||||||
float heading = other->GetHeading(); // mob heading
|
float heading = other->GetHeading(); // mob heading
|
||||||
heading = (heading * 360.0f) / 256.0f; // convert to degrees
|
heading = (heading * 360.0f) / 256.0f; // convert to degrees
|
||||||
if (heading < 270)
|
if (heading < 270)
|
||||||
heading += 90;
|
heading += 90;
|
||||||
else
|
else
|
||||||
heading -= 270;
|
heading -= 270;
|
||||||
|
|
||||||
heading = heading * 3.1415f / 180.0f; // convert to radians
|
heading = heading * 3.1415f / 180.0f; // convert to radians
|
||||||
vectorx = mobx + (10.0f * cosf(heading)); // create a vector based on heading
|
vectorx = mobx + (10.0f * cosf(heading)); // create a vector based on heading
|
||||||
vectory = moby + (10.0f * sinf(heading)); // of mob length 10
|
vectory = moby + (10.0f * sinf(heading)); // of mob length 10
|
||||||
|
|
||||||
//length of mob to player vector
|
// length of mob to player vector
|
||||||
//lengthb = (float)sqrtf(pow((-playerx-mobx),2) + pow((playery-moby),2));
|
lengthb = (float) sqrtf(((-ourx - mobx) * (-ourx - mobx)) + ((oury - moby) * (oury - moby)));
|
||||||
lengthb = (float) sqrtf( ( (-playerx-mobx) * (-playerx-mobx) ) + ( (playery-moby) * (playery-moby) ) );
|
|
||||||
|
|
||||||
// calculate dot product to get angle
|
// calculate dot product to get angle
|
||||||
angle = acosf(((vectorx-mobx)*(-playerx-mobx)+(vectory-moby)*(playery-moby)) / (10 * lengthb));
|
// Handle acos domain errors due to floating point rounding errors
|
||||||
|
dotp = ((vectorx - mobx) * (-ourx - mobx) +
|
||||||
|
(vectory - moby) * (oury - moby)) / (10 * lengthb);
|
||||||
|
// I haven't seen any errors that cause problems that weren't slightly
|
||||||
|
// larger/smaller than 1/-1, so only handle these cases for now
|
||||||
|
if (dotp > 1)
|
||||||
|
return 0.0f;
|
||||||
|
else if (dotp < -1)
|
||||||
|
return 180.0f;
|
||||||
|
|
||||||
|
angle = acosf(dotp);
|
||||||
angle = angle * 180.0f / 3.1415f;
|
angle = angle * 180.0f / 3.1415f;
|
||||||
if (angle > 90.0f) //not sure what value to use (90*2=180 degrees is front)
|
|
||||||
return true;
|
return angle;
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::SetZone(uint32 zone_id, uint32 instance_id)
|
void Mob::SetZone(uint32 zone_id, uint32 instance_id)
|
||||||
|
|||||||
@ -106,7 +106,13 @@ public:
|
|||||||
//Attack
|
//Attack
|
||||||
virtual void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10);
|
virtual void RogueBackstab(Mob* other, bool min_damage = false, int ReuseTime = 10);
|
||||||
virtual void RogueAssassinate(Mob* other); // solar
|
virtual void RogueAssassinate(Mob* other); // solar
|
||||||
bool BehindMob(Mob* other = 0, float playerx = 0.0f, float playery = 0.0f) const;
|
float MobAngle(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const;
|
||||||
|
// greater than 90 is behind
|
||||||
|
inline bool BehindMob(Mob *other = 0, float ourx = 0.0f, float oury = 0.0f) const
|
||||||
|
{ return (!other || other == this) ? true : MobAngle(other, ourx, oury) > 90.0f; }
|
||||||
|
// 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; }
|
||||||
virtual void RangedAttack(Mob* other) { }
|
virtual void RangedAttack(Mob* other) { }
|
||||||
virtual void ThrowingAttack(Mob* other) { }
|
virtual void ThrowingAttack(Mob* other) { }
|
||||||
uint16 GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg);
|
uint16 GetThrownDamage(int16 wDmg, int32& TotalDmg, int& minDmg);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user