mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
[Bug Fix] Potential fix for some undesired ranged explotative behavior. (#4413)
Original Commit: 33fecd68d4eab36885eb7f8067102ba6bce95bac Conditional ranged double attack
This commit is contained in:
parent
a23ac4628f
commit
3bfdc0cf71
@ -1133,7 +1133,7 @@ public:
|
|||||||
void RemoveNoRent(bool client_update = true);
|
void RemoveNoRent(bool client_update = true);
|
||||||
void RemoveDuplicateLore(bool client_update = true);
|
void RemoveDuplicateLore(bool client_update = true);
|
||||||
void MoveSlotNotAllowed(bool client_update = true);
|
void MoveSlotNotAllowed(bool client_update = true);
|
||||||
virtual void RangedAttack(Mob* other, bool CanDoubleAttack = false);
|
virtual bool RangedAttack(Mob* other, bool CanDoubleAttack = false);
|
||||||
virtual void ThrowingAttack(Mob* other, bool CanDoubleAttack = false);
|
virtual void ThrowingAttack(Mob* other, bool CanDoubleAttack = false);
|
||||||
void DoClassAttacks(Mob *ca_target, uint16 skill = -1, bool IsRiposte=false);
|
void DoClassAttacks(Mob *ca_target, uint16 skill = -1, bool IsRiposte=false);
|
||||||
|
|
||||||
|
|||||||
@ -321,48 +321,46 @@ bool Client::Process() {
|
|||||||
auto_fire = false;
|
auto_fire = false;
|
||||||
}
|
}
|
||||||
EQ::ItemInstance *ranged = GetInv().GetItem(EQ::invslot::slotRange);
|
EQ::ItemInstance *ranged = GetInv().GetItem(EQ::invslot::slotRange);
|
||||||
if (ranged)
|
if (ranged) {
|
||||||
{
|
|
||||||
if (ranged->GetItem() && ranged->GetItem()->ItemType == EQ::item::ItemTypeBow) {
|
if (ranged->GetItem() && ranged->GetItem()->ItemType == EQ::item::ItemTypeBow) {
|
||||||
if (ranged_timer.Check(false)) {
|
if (ranged_timer.Check(false)) {
|
||||||
if (GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient()) && IsAttackAllowed(GetTarget())) {
|
if (GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient()) && IsAttackAllowed(GetTarget())) {
|
||||||
if (GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())) {
|
if (GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())) {
|
||||||
if (CheckLosFN(GetTarget()) && CheckWaterAutoFireLoS(GetTarget())) {
|
if (CheckLosFN(GetTarget()) && CheckWaterAutoFireLoS(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());
|
if (RangedAttack(GetTarget()) && CheckDoubleRangedAttack()) {
|
||||||
if (CheckDoubleRangedAttack())
|
|
||||||
RangedAttack(GetTarget(), true);
|
RangedAttack(GetTarget(), true);
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
ranged_timer.Start();
|
ranged_timer.Start();
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
ranged_timer.Start();
|
ranged_timer.Start();
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
ranged_timer.Start();
|
ranged_timer.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ranged->GetItem() && (ranged->GetItem()->ItemType == EQ::item::ItemTypeLargeThrowing || ranged->GetItem()->ItemType == EQ::item::ItemTypeSmallThrowing)) {
|
} else if (ranged->GetItem() && (ranged->GetItem()->ItemType == EQ::item::ItemTypeLargeThrowing || ranged->GetItem()->ItemType == EQ::item::ItemTypeSmallThrowing)) {
|
||||||
if (ranged_timer.Check(false)) {
|
if (ranged_timer.Check(false)) {
|
||||||
if (GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient()) && IsAttackAllowed(GetTarget())) {
|
if (GetTarget() && (GetTarget()->IsNPC() || GetTarget()->IsClient()) && IsAttackAllowed(GetTarget())) {
|
||||||
if (GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())) {
|
if (GetTarget()->InFrontMob(this, GetTarget()->GetX(), GetTarget()->GetY())) {
|
||||||
if (CheckLosFN(GetTarget()) && CheckWaterAutoFireLoS(GetTarget())) {
|
if (CheckLosFN(GetTarget()) && CheckWaterAutoFireLoS(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());
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
ranged_timer.Start();
|
ranged_timer.Start();
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
ranged_timer.Start();
|
ranged_timer.Start();
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
ranged_timer.Start();
|
ranged_timer.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Mob *auto_attack_target = GetTarget();
|
Mob *auto_attack_target = GetTarget();
|
||||||
if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check()) {
|
if (auto_attack && auto_attack_target != nullptr && may_use_attacks && attack_timer.Check()) {
|
||||||
|
|||||||
@ -391,9 +391,7 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
|
|||||||
// ranged attack (archery)
|
// ranged attack (archery)
|
||||||
if (ca_atk->m_skill == EQ::skills::SkillArchery) {
|
if (ca_atk->m_skill == EQ::skills::SkillArchery) {
|
||||||
SetAttackTimer();
|
SetAttackTimer();
|
||||||
RangedAttack(GetTarget());
|
if (RangedAttack(GetTarget()) && CheckDoubleRangedAttack()) {
|
||||||
|
|
||||||
if (CheckDoubleRangedAttack()) {
|
|
||||||
RangedAttack(GetTarget(), true);
|
RangedAttack(GetTarget(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,19 +817,21 @@ void Mob::RogueAssassinate(Mob* other)
|
|||||||
DoAnim(anim1HPiercing, 0, false); //piercing animation
|
DoAnim(anim1HPiercing, 0, false); //piercing animation
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
bool Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
||||||
//conditions to use an attack checked before we are called
|
//conditions to use an attack checked before we are called
|
||||||
if (!other)
|
if (!other) {
|
||||||
return;
|
return false;
|
||||||
else if (other == this)
|
} else if (other == this) {
|
||||||
return;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//make sure the attack and ranged timers are up
|
//make sure the attack and ranged timers are up
|
||||||
//if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow
|
//if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow
|
||||||
if (!CanDoubleAttack && ((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check()))) {
|
if (!CanDoubleAttack && ((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check()))) {
|
||||||
LogCombat("Throwing attack canceled. Timer not up. Attack [{}], ranged [{}]", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
|
LogCombat("Throwing attack canceled. Timer not up. Attack [{}], ranged [{}]", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
|
||||||
// The server and client timers are not exact matches currently, so this would spam too often if enabled
|
// The server and client timers are not exact matches currently, so this would spam too often if enabled
|
||||||
//Message(0, "Error: Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
|
//Message(Chat::White, "Error: Timer not up. Attack %d, ranged %d", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
const EQ::ItemInstance* RangeWeapon = m_inv[EQ::invslot::slotRange];
|
const EQ::ItemInstance* RangeWeapon = m_inv[EQ::invslot::slotRange];
|
||||||
|
|
||||||
@ -841,13 +841,14 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
|
|
||||||
if (!RangeWeapon || !RangeWeapon->IsClassCommon()) {
|
if (!RangeWeapon || !RangeWeapon->IsClassCommon()) {
|
||||||
LogCombat("Ranged attack canceled. Missing or invalid ranged weapon ([{}]) in slot [{}]", GetItemIDAt(EQ::invslot::slotRange), EQ::invslot::slotRange);
|
LogCombat("Ranged attack canceled. Missing or invalid ranged weapon ([{}]) in slot [{}]", GetItemIDAt(EQ::invslot::slotRange), EQ::invslot::slotRange);
|
||||||
Message(0, "Error: Rangeweapon: GetItem(%i)==0, you have no bow!", GetItemIDAt(EQ::invslot::slotRange));
|
Message(Chat::White, "Error: Rangeweapon: GetItem(%i)==0, you have no bow!", GetItemIDAt(EQ::invslot::slotRange));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Ammo || !Ammo->IsClassCommon()) {
|
if (!Ammo || !Ammo->IsClassCommon()) {
|
||||||
LogCombat("Ranged attack canceled. Missing or invalid ammo item ([{}]) in slot [{}]", GetItemIDAt(EQ::invslot::slotAmmo), EQ::invslot::slotAmmo);
|
LogCombat("Ranged attack canceled. Missing or invalid ammo item ([{}]) in slot [{}]", GetItemIDAt(EQ::invslot::slotAmmo), EQ::invslot::slotAmmo);
|
||||||
Message(0, "Error: Ammo: GetItem(%i)==0, you have no ammo!", GetItemIDAt(EQ::invslot::slotAmmo));
|
Message(Chat::White, "Error: Ammo: GetItem(%i)==0, you have no ammo!", GetItemIDAt(EQ::invslot::slotAmmo));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EQ::ItemData* RangeItem = RangeWeapon->GetItem();
|
const EQ::ItemData* RangeItem = RangeWeapon->GetItem();
|
||||||
@ -855,13 +856,14 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
|
|
||||||
if (RangeItem->ItemType != EQ::item::ItemTypeBow) {
|
if (RangeItem->ItemType != EQ::item::ItemTypeBow) {
|
||||||
LogCombat("Ranged attack canceled. Ranged item is not a bow. type [{}]", RangeItem->ItemType);
|
LogCombat("Ranged attack canceled. Ranged item is not a bow. type [{}]", RangeItem->ItemType);
|
||||||
Message(0, "Error: Rangeweapon: Item %d is not a bow.", RangeWeapon->GetID());
|
Message(Chat::White, "Error: Rangeweapon: Item %d is not a bow.", RangeWeapon->GetID());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AmmoItem->ItemType != EQ::item::ItemTypeArrow) {
|
if (AmmoItem->ItemType != EQ::item::ItemTypeArrow) {
|
||||||
LogCombat("Ranged attack canceled. Ammo item is not an arrow. type [{}]", AmmoItem->ItemType);
|
LogCombat("Ranged attack canceled. Ammo item is not an arrow. type [{}]", AmmoItem->ItemType);
|
||||||
Message(0, "Error: Ammo: type %d != %d, you have the wrong type of ammo!", AmmoItem->ItemType, EQ::item::ItemTypeArrow);
|
Message(Chat::White, "Error: Ammo: type %d != %d, you have the wrong type of ammo!", AmmoItem->ItemType, EQ::item::ItemTypeArrow);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogCombat("Shooting [{}] with bow [{}] ([{}]) and arrow [{}] ([{}])", other->GetName(), RangeItem->Name, RangeItem->ID, AmmoItem->Name, AmmoItem->ID);
|
LogCombat("Shooting [{}] with bow [{}] ([{}]) and arrow [{}] ([{}])", other->GetName(), RangeItem->Name, RangeItem->ID, AmmoItem->Name, AmmoItem->ID);
|
||||||
@ -872,11 +874,13 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
for (int r = EQ::invslot::GENERAL_BEGIN; r <= EQ::invslot::GENERAL_END; r++) {
|
for (int r = EQ::invslot::GENERAL_BEGIN; r <= EQ::invslot::GENERAL_END; r++) {
|
||||||
const EQ::ItemInstance *pi = m_inv[r];
|
const EQ::ItemInstance *pi = m_inv[r];
|
||||||
if (pi == nullptr || !pi->IsClassBag())
|
if (pi == nullptr || !pi->IsClassBag()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
const EQ::ItemData* bagitem = pi->GetItem();
|
const EQ::ItemData* bagitem = pi->GetItem();
|
||||||
if (!bagitem || bagitem->BagType != EQ::item::BagTypeQuiver)
|
if (!bagitem || bagitem->BagType != EQ::item::BagTypeQuiver) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//we found a quiver, look for the ammo in it
|
//we found a quiver, look for the ammo in it
|
||||||
for (int i = 0; i < bagitem->BagSlots; i++) {
|
for (int i = 0; i < bagitem->BagSlots; i++) {
|
||||||
@ -895,9 +899,11 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(found)
|
|
||||||
|
if (found) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
//if we dont find a quiver, look through our inventory again
|
//if we dont find a quiver, look through our inventory again
|
||||||
@ -914,14 +920,14 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
float range = RangeItem->Range + AmmoItem->Range + GetRangeDistTargetSizeMod(GetTarget());
|
float range = RangeItem->Range + AmmoItem->Range + GetRangeDistTargetSizeMod(GetTarget());
|
||||||
LogCombat("Calculated bow range to be [{}]", range);
|
LogCombat("Calculated bow range to be [{}]", range);
|
||||||
range *= range;
|
range *= range;
|
||||||
|
|
||||||
if (float dist = DistanceSquared(m_Position, other->GetPosition()); dist > range) {
|
if (float dist = DistanceSquared(m_Position, other->GetPosition()); dist > range) {
|
||||||
LogCombat("Ranged attack out of range client should catch this. ([{}] > [{}]).\n", dist, range);
|
LogCombat("Ranged attack out of range client should catch this. ([{}] > [{}]).\n", dist, range);
|
||||||
MessageString(Chat::Red,TARGET_OUT_OF_RANGE);//Client enforces range and sends the message, this is a backup just incase.
|
MessageString(Chat::Red,TARGET_OUT_OF_RANGE);//Client enforces range and sends the message, this is a backup just incase.
|
||||||
return;
|
return false;
|
||||||
}
|
} else if (dist < (RuleI(Combat, MinRangedAttackDist)*RuleI(Combat, MinRangedAttackDist))){
|
||||||
else if (dist < (RuleI(Combat, MinRangedAttackDist)*RuleI(Combat, MinRangedAttackDist))){
|
|
||||||
MessageString(Chat::Yellow,RANGED_TOO_CLOSE);//Client enforces range and sends the message, this is a backup just incase.
|
MessageString(Chat::Yellow,RANGED_TOO_CLOSE);//Client enforces range and sends the message, this is a backup just incase.
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsAttackAllowed(other) ||
|
if (!IsAttackAllowed(other) ||
|
||||||
@ -932,7 +938,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
IsFeared() ||
|
IsFeared() ||
|
||||||
IsMezzed() ||
|
IsMezzed() ||
|
||||||
(GetAppearance() == eaDead)) {
|
(GetAppearance() == eaDead)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Shoots projectile and/or applies the archery damage
|
//Shoots projectile and/or applies the archery damage
|
||||||
@ -961,6 +967,8 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
|
|||||||
|
|
||||||
CheckIncreaseSkill(EQ::skills::SkillArchery, GetTarget(), -15);
|
CheckIncreaseSkill(EQ::skills::SkillArchery, GetTarget(), -15);
|
||||||
CommonBreakInvisibleFromCombat();
|
CommonBreakInvisibleFromCombat();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, const EQ::ItemInstance *Ammo,
|
void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, const EQ::ItemInstance *Ammo,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user