mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
[Cleanup] Merge Client::Attack and Bot::Attack into Mob::Attack (#2756)
* [Cleanup] Merge Client::Attack and Bot::Attack into Mob::Attack (#11) * Remove #ifdef Bots to go along with KK fix * Remove method in logging * remove method from logging * Fixes * Rename
This commit is contained in:
parent
5c095ab87a
commit
886f80117c
@ -1275,7 +1275,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in
|
|||||||
return std::max((int64)0, dmg);
|
return std::max((int64)0, dmg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64 Client::DoDamageCaps(int64 base_damage)
|
int64 Mob::DoDamageCaps(int64 base_damage)
|
||||||
{
|
{
|
||||||
// this is based on a client function that caps melee base_damage
|
// this is based on a client function that caps melee base_damage
|
||||||
auto level = GetLevel();
|
auto level = GetLevel();
|
||||||
@ -1404,8 +1404,8 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, boo
|
|||||||
|
|
||||||
// check to see if we hit..
|
// check to see if we hit..
|
||||||
if (!FromRiposte && other->AvoidDamage(this, hit)) {
|
if (!FromRiposte && other->AvoidDamage(this, hit)) {
|
||||||
int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
if (int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
||||||
if (strike_through && zone->random.Roll(strike_through)) {
|
strike_through && zone->random.Roll(strike_through)) {
|
||||||
MessageString(Chat::StrikeThrough,
|
MessageString(Chat::StrikeThrough,
|
||||||
STRIKETHROUGH_STRING); // You strike through your opponents defenses!
|
STRIKETHROUGH_STRING); // You strike through your opponents defenses!
|
||||||
hit.damage_done = 1; // set to one, we will check this to continue
|
hit.damage_done = 1; // set to one, we will check this to continue
|
||||||
@ -1460,71 +1460,77 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, boo
|
|||||||
//stop the attack calculations
|
//stop the attack calculations
|
||||||
// IsFromSpell added to allow spell effects to use Attack. (Mainly for the Rampage AA right now.)
|
// IsFromSpell added to allow spell effects to use Attack. (Mainly for the Rampage AA right now.)
|
||||||
//SYNC WITH: tune.cpp, mob.h TuneClientAttack
|
//SYNC WITH: tune.cpp, mob.h TuneClientAttack
|
||||||
bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts)
|
bool Mob::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts)
|
||||||
{
|
{
|
||||||
if (!other) {
|
if (!other) {
|
||||||
SetTarget(nullptr);
|
SetTarget(nullptr);
|
||||||
LogError("A null Mob object was passed to Client::Attack() for evaluation!");
|
LogError("A null Mob object was passed for evaluation!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GetTarget())
|
if (!GetTarget()) {
|
||||||
SetTarget(other);
|
SetTarget(other);
|
||||||
|
}
|
||||||
|
|
||||||
LogCombat("Attacking [{}] with hand [{}] [{}]", other ? other->GetName() : "(nullptr)", Hand, bRiposte ? "(this is a riposte)" : "");
|
LogCombatDetail("Attacking [{}] with hand [{}] [{}]", other ? other->GetName() : "nullptr", Hand, bRiposte ? "this is a riposte" : "");
|
||||||
|
|
||||||
//SetAttackTimer();
|
|
||||||
if (
|
if (
|
||||||
(IsCasting() && GetClass() != BARD && !IsFromSpell)
|
(IsCasting() && GetClass() != BARD && !IsFromSpell)
|
||||||
|| other == nullptr
|
|| other == nullptr
|
||||||
|| ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead))
|
|| ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead))
|
||||||
|| (GetHP() < 0)
|
|| (GetHP() < 0)
|
||||||
|| (!IsAttackAllowed(other))
|
|| (!IsAttackAllowed(other))
|
||||||
|
|| (IsBot() && GetAppearance() == eaDead)
|
||||||
) {
|
) {
|
||||||
LogCombat("Attack cancelled, invalid circumstances");
|
LogCombat("Attack cancelled, invalid circumstances");
|
||||||
return false; // Only bards can attack while casting
|
return false; // Only bards can attack while casting
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DivineAura() && !GetGM()) {//cant attack while invulnerable unless your a gm
|
if (DivineAura() && !CastToClient()->GetGM()) { //cant attack while invulnerable unless your a gm
|
||||||
LogCombat("Attack cancelled, Divine Aura is in effect");
|
LogCombat("Attack cancelled, Divine Aura is in effect");
|
||||||
MessageString(Chat::DefaultText, DIVINE_AURA_NO_ATK); //You can't attack while invulnerable
|
MessageString(Chat::DefaultText, DIVINE_AURA_NO_ATK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetFeigned())
|
if (GetFeigned()) {
|
||||||
return false; // Rogean: How can you attack while feigned? Moved up from Aggro Code.
|
return false; // Rogean: How can you attack while feigned? Moved up from Aggro Code.
|
||||||
|
}
|
||||||
|
|
||||||
EQ::ItemInstance* weapon = nullptr;
|
const EQ::ItemInstance* weapon = nullptr;
|
||||||
if (Hand == EQ::invslot::slotSecondary) { // Kaiyodo - Pick weapon from the attacking hand
|
|
||||||
weapon = GetInv().GetItem(EQ::invslot::slotSecondary);
|
|
||||||
|
if (IsBot()) {
|
||||||
|
FaceTarget(GetTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Hand == EQ::invslot::slotSecondary) {
|
||||||
|
weapon = (IsClient()) ? GetInv().GetItem(EQ::invslot::slotSecondary) : CastToBot()->GetBotItem(EQ::invslot::slotPrimary);
|
||||||
OffHandAtk(true);
|
OffHandAtk(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
weapon = GetInv().GetItem(EQ::invslot::slotPrimary);
|
weapon = (IsClient()) ? GetInv().GetItem(EQ::invslot::slotPrimary) : CastToBot()->GetBotItem(EQ::invslot::slotPrimary);
|
||||||
OffHandAtk(false);
|
OffHandAtk(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weapon != nullptr) {
|
if (weapon != nullptr) {
|
||||||
if (!weapon->IsWeapon()) {
|
if (!weapon->IsWeapon()) {
|
||||||
LogCombat("Attack cancelled, Item [{}] ([{}]) is not a weapon", weapon->GetItem()->Name, weapon->GetID());
|
LogCombat("Attack cancelled, Item [{}] ([{}]) is not a weapon", weapon->GetItem()->Name, weapon->GetID());
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
LogCombat("Attacking with weapon: [{}] ([{}])", weapon->GetItem()->Name, weapon->GetID());
|
LogCombatDetail("Attacking with weapon: [{}] ([{}])", weapon->GetItem()->Name, weapon->GetID());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LogCombat("Attacking without a weapon");
|
LogCombatDetail("Attacking without a weapon");
|
||||||
}
|
}
|
||||||
|
|
||||||
DamageHitInfo my_hit;
|
DamageHitInfo my_hit;
|
||||||
// calculate attack_skill and skillinuse depending on hand and weapon
|
// calculate attack_skill and skillinuse depending on hand and weapon
|
||||||
// also send Packet to near clients
|
// also send Packet to near clients
|
||||||
my_hit.skill = AttackAnimation(Hand, weapon);
|
my_hit.skill = AttackAnimation(Hand, weapon);
|
||||||
LogCombat("Attacking with [{}] in slot [{}] using skill [{}]", weapon ? weapon->GetItem()->Name : "Fist", Hand, my_hit.skill);
|
LogCombatDetail("Attacking with [{}] in slot [{}] using skill [{}]", weapon ? weapon->GetItem()->Name : "Fist", Hand, my_hit.skill);
|
||||||
|
|
||||||
// Now figure out damage
|
// Now figure out damage
|
||||||
my_hit.damage_done = 1;
|
my_hit.damage_done = 1;
|
||||||
my_hit.min_damage = 0;
|
my_hit.min_damage = 0;
|
||||||
uint8 mylevel = GetLevel() ? GetLevel() : 1;
|
|
||||||
int64 hate = 0;
|
int64 hate = 0;
|
||||||
if (weapon)
|
if (weapon)
|
||||||
hate = (weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt);
|
hate = (weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt);
|
||||||
@ -1546,8 +1552,10 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
hate = hate * (100 + shield_inc) / 100;
|
hate = hate * (100 + shield_inc) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckIncreaseSkill(my_hit.skill, other, -15);
|
if (IsClient()) {
|
||||||
CheckIncreaseSkill(EQ::skills::SkillOffense, other, -15);
|
CastToClient()->CheckIncreaseSkill(my_hit.skill, other, -15);
|
||||||
|
CastToClient()->CheckIncreaseSkill(EQ::skills::SkillOffense, other, -15);
|
||||||
|
}
|
||||||
|
|
||||||
// ***************************************************************
|
// ***************************************************************
|
||||||
// *** Calculate the damage bonus, if applicable, for this hit ***
|
// *** Calculate the damage bonus, if applicable, for this hit ***
|
||||||
@ -1575,19 +1583,20 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
//Live AA - Sinister Strikes *Adds weapon damage bonus to offhand weapon.
|
//Live AA - Sinister Strikes *Adds weapon damage bonus to offhand weapon.
|
||||||
if (Hand == EQ::invslot::slotSecondary) {
|
if (Hand == EQ::invslot::slotSecondary &&
|
||||||
if (aabonuses.SecondaryDmgInc || itembonuses.SecondaryDmgInc || spellbonuses.SecondaryDmgInc) {
|
(
|
||||||
|
aabonuses.SecondaryDmgInc ||
|
||||||
|
itembonuses.SecondaryDmgInc ||
|
||||||
|
spellbonuses.SecondaryDmgInc
|
||||||
|
)
|
||||||
|
) {
|
||||||
ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQ::ItemData*) nullptr, true);
|
ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQ::ItemData*) nullptr, true);
|
||||||
|
|
||||||
my_hit.min_damage = ucDamageBonus;
|
my_hit.min_damage = ucDamageBonus;
|
||||||
hate += ucDamageBonus;
|
hate += ucDamageBonus;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// damage = mod_client_damage(damage, skillinuse, Hand, weapon, other);
|
LogCombatDetail("Damage calculated base [{}] min damage [{}] skill [{}]", my_hit.base_damage, my_hit.min_damage, my_hit.skill);
|
||||||
|
|
||||||
LogCombat("Damage calculated: base [{}] min damage [{}] skill [{}]", my_hit.base_damage, my_hit.min_damage, my_hit.skill);
|
|
||||||
|
|
||||||
int hit_chance_bonus = 0;
|
int hit_chance_bonus = 0;
|
||||||
my_hit.offense = offense(my_hit.skill); // we need this a few times
|
my_hit.offense = offense(my_hit.skill); // we need this a few times
|
||||||
@ -1604,6 +1613,8 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus);
|
my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus);
|
||||||
|
|
||||||
DoAttack(other, my_hit, opts, bRiposte);
|
DoAttack(other, my_hit, opts, bRiposte);
|
||||||
|
|
||||||
|
LogCombatDetail("Final damage after all reductions [{}]", my_hit.damage_done);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
my_hit.damage_done = DMG_INVULNERABLE;
|
my_hit.damage_done = DMG_INVULNERABLE;
|
||||||
@ -1615,11 +1626,13 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
other->AddToHateList(this, hate);
|
other->AddToHateList(this, hate);
|
||||||
|
|
||||||
//Guard Assist Code
|
//Guard Assist Code
|
||||||
if (RuleB(Character, PVPEnableGuardFactionAssist)) {
|
if (RuleB(Character, PVPEnableGuardFactionAssist) &&
|
||||||
if (IsClient() && other->IsClient() || (HasOwner() && GetOwner()->IsClient() && other->IsClient() )) {
|
(
|
||||||
auto& mob_list = entity_list.GetCloseMobList(other);
|
(IsClient() && other->IsClient()) ||
|
||||||
for (auto& e : mob_list) {
|
(HasOwner() && GetOwner()->IsClient() && other->IsClient())
|
||||||
auto mob = e.second;
|
)
|
||||||
|
) {
|
||||||
|
for (auto const& [id, mob] : entity_list.GetCloseMobList(other)) {
|
||||||
if (!mob) {
|
if (!mob) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1635,14 +1648,13 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
////// Send Attack Damage
|
////// Send Attack Damage
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks);
|
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks);
|
||||||
|
|
||||||
if (IsDead()) {
|
if (CastToClient()->IsDead() || (IsBot() && GetAppearance() == eaDead)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,12 +36,12 @@ public:
|
|||||||
//abstract virtual function implementations requird by base abstract class
|
//abstract virtual function implementations requird by base abstract class
|
||||||
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill) { return true; }
|
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill) { return true; }
|
||||||
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||||
virtual bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
|
||||||
ExtraAttackOptions *opts = nullptr) { return false; }
|
|
||||||
virtual bool HasRaid() { return false; }
|
virtual bool HasRaid() { return false; }
|
||||||
virtual bool HasGroup() { return false; }
|
virtual bool HasGroup() { return false; }
|
||||||
virtual Raid* GetRaid() { return 0; }
|
virtual Raid* GetRaid() { return 0; }
|
||||||
virtual Group* GetGroup() { return 0; }
|
virtual Group* GetGroup() { return 0; }
|
||||||
|
bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
||||||
|
ExtraAttackOptions *opts = nullptr) override { return false; }
|
||||||
|
|
||||||
bool IsBeacon() const { return true; }
|
bool IsBeacon() const { return true; }
|
||||||
bool Process();
|
bool Process();
|
||||||
|
|||||||
183
zone/bot.cpp
183
zone/bot.cpp
@ -3375,7 +3375,7 @@ void Bot::AI_Process()
|
|||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
if (attack_timer.Check()) { // Process primary weapon attacks
|
if (attack_timer.Check()) { // Process primary weapon attacks
|
||||||
|
|
||||||
Attack(tar, EQ::invslot::slotPrimary);
|
Mob::Attack(tar, EQ::invslot::slotPrimary);
|
||||||
|
|
||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false);
|
TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false);
|
||||||
@ -3389,19 +3389,19 @@ void Bot::AI_Process()
|
|||||||
if (CanThisClassDoubleAttack()) {
|
if (CanThisClassDoubleAttack()) {
|
||||||
|
|
||||||
if (CheckBotDoubleAttack()) {
|
if (CheckBotDoubleAttack()) {
|
||||||
Attack(tar, EQ::invslot::slotPrimary, true);
|
Mob::Attack(tar, EQ::invslot::slotPrimary, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
if (GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) {
|
if (GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) {
|
||||||
// tripleSuccess = true;
|
// tripleSuccess = true;
|
||||||
Attack(tar, EQ::invslot::slotPrimary, true);
|
Mob::Attack(tar, EQ::invslot::slotPrimary, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
// quad attack, does this belong here??
|
// quad attack, does this belong here??
|
||||||
if (GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) {
|
if (GetSpecialAbility(SPECATK_QUAD) && CheckBotDoubleAttack(true)) {
|
||||||
Attack(tar, EQ::invslot::slotPrimary, true);
|
Mob::Attack(tar, EQ::invslot::slotPrimary, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3413,10 +3413,10 @@ void Bot::AI_Process()
|
|||||||
if (zone->random.Int(0, 100) < flurrychance) {
|
if (zone->random.Int(0, 100) < flurrychance) {
|
||||||
|
|
||||||
MessageString(Chat::NPCFlurry, YOU_FLURRY);
|
MessageString(Chat::NPCFlurry, YOU_FLURRY);
|
||||||
Attack(tar, EQ::invslot::slotPrimary, false);
|
Mob::Attack(tar, EQ::invslot::slotPrimary, false);
|
||||||
|
|
||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
Attack(tar, EQ::invslot::slotPrimary, false);
|
Mob::Attack(tar, EQ::invslot::slotPrimary, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3429,7 +3429,7 @@ void Bot::AI_Process()
|
|||||||
if (p_item && p_item->GetItem()->IsType2HWeapon()) {
|
if (p_item && p_item->GetItem()->IsType2HWeapon()) {
|
||||||
|
|
||||||
if (zone->random.Int(0, 100) < ExtraAttackChanceBonus) {
|
if (zone->random.Int(0, 100) < ExtraAttackChanceBonus) {
|
||||||
Attack(tar, EQ::invslot::slotPrimary, false);
|
Mob::Attack(tar, EQ::invslot::slotPrimary, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3467,7 +3467,7 @@ void Bot::AI_Process()
|
|||||||
float random = zone->random.Real(0, 1);
|
float random = zone->random.Real(0, 1);
|
||||||
if (random < DualWieldProbability) { // Max 78% of DW
|
if (random < DualWieldProbability) { // Max 78% of DW
|
||||||
|
|
||||||
Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand
|
Mob::Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand
|
||||||
|
|
||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
TryCombatProcs(s_item, tar, EQ::invslot::slotSecondary);
|
TryCombatProcs(s_item, tar, EQ::invslot::slotSecondary);
|
||||||
@ -3476,7 +3476,7 @@ void Bot::AI_Process()
|
|||||||
if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) {
|
if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) {
|
||||||
|
|
||||||
if (tar->GetHP() > -10) {
|
if (tar->GetHP() > -10) {
|
||||||
Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand
|
Mob::Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5316,171 +5316,6 @@ void Bot::Damage(Mob *from, int64 damage, uint16 spell_id, EQ::skills::SkillType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) {
|
|
||||||
if (!other) {
|
|
||||||
SetTarget(nullptr);
|
|
||||||
LogErrorDetail("A null Mob object was passed to Bot::Attack for evaluation!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((GetHP() <= 0) || (GetAppearance() == eaDead)) {
|
|
||||||
SetTarget(nullptr);
|
|
||||||
LogCombatDetail("Attempted to attack [{}] while unconscious or, otherwise, appearing dead", other->GetCleanName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if(!GetTarget() || GetTarget() != other) // NPC::Attack() doesn't do this
|
|
||||||
// SetTarget(other);
|
|
||||||
|
|
||||||
// apparently, we always want our target to be 'other'..why not just set it?
|
|
||||||
SetTarget(other);
|
|
||||||
// takes more to compare a call result, load for a call, load a compare to address and compare, and finally
|
|
||||||
// push a value to an address than to just load for a call and push a value to an address.
|
|
||||||
|
|
||||||
LogCombat("Attacking [{}] with hand [{}] [{}]", other->GetCleanName(), Hand, (FromRiposte ? "(this is a riposte)" : ""));
|
|
||||||
if ((IsCasting() && (GetClass() != BARD) && !IsFromSpell) || (!IsAttackAllowed(other))) {
|
|
||||||
if(GetOwnerID())
|
|
||||||
entity_list.MessageClose(this, 1, 200, 10, "%s says, '%s is not a legal target master.'", GetCleanName(), GetTarget()->GetCleanName());
|
|
||||||
|
|
||||||
if(other) {
|
|
||||||
RemoveFromHateList(other);
|
|
||||||
LogCombat("I am not allowed to attack [{}]", other->GetCleanName());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(DivineAura()) {//cant attack while invulnerable
|
|
||||||
LogCombat("Attack canceled, Divine Aura is in effect");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FaceTarget(GetTarget());
|
|
||||||
EQ::ItemInstance* weapon = nullptr;
|
|
||||||
if (Hand == EQ::invslot::slotPrimary) {
|
|
||||||
weapon = GetBotItem(EQ::invslot::slotPrimary);
|
|
||||||
OffHandAtk(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Hand == EQ::invslot::slotSecondary) {
|
|
||||||
weapon = GetBotItem(EQ::invslot::slotSecondary);
|
|
||||||
OffHandAtk(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(weapon != nullptr) {
|
|
||||||
if (!weapon->IsWeapon()) {
|
|
||||||
LogCombat("Attack canceled, Item [{}] ([{}]) is not a weapon", weapon->GetItem()->Name, weapon->GetID());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LogCombat("Attacking with weapon: [{}] ([{}])", weapon->GetItem()->Name, weapon->GetID());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LogCombat("Attacking without a weapon");
|
|
||||||
|
|
||||||
// calculate attack_skill and skillinuse depending on hand and weapon
|
|
||||||
// also send Packet to near clients
|
|
||||||
DamageHitInfo my_hit;
|
|
||||||
my_hit.skill = AttackAnimation(Hand, weapon);
|
|
||||||
LogCombat("Attacking with [{}] in slot [{}] using skill [{}]", weapon?weapon->GetItem()->Name:"Fist", Hand, my_hit.skill);
|
|
||||||
|
|
||||||
// Now figure out damage
|
|
||||||
my_hit.damage_done = 1;
|
|
||||||
my_hit.min_damage = 0;
|
|
||||||
uint8 mylevel = GetLevel() ? GetLevel() : 1;
|
|
||||||
int64 hate = 0;
|
|
||||||
if (weapon)
|
|
||||||
hate = (weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt);
|
|
||||||
|
|
||||||
my_hit.base_damage = GetWeaponDamage(other, weapon, &hate);
|
|
||||||
if (hate == 0 && my_hit.base_damage > 1)
|
|
||||||
hate = my_hit.base_damage;
|
|
||||||
|
|
||||||
//if weapon damage > 0 then we know we can hit the target with this weapon
|
|
||||||
//otherwise we cannot and we set the damage to -5 later on
|
|
||||||
if (my_hit.base_damage > 0) {
|
|
||||||
my_hit.min_damage = 0;
|
|
||||||
|
|
||||||
// ***************************************************************
|
|
||||||
// *** Calculate the damage bonus, if applicable, for this hit ***
|
|
||||||
// ***************************************************************
|
|
||||||
|
|
||||||
#ifndef EQEMU_NO_WEAPON_DAMAGE_BONUS
|
|
||||||
|
|
||||||
// If you include the preprocessor directive "#define EQEMU_NO_WEAPON_DAMAGE_BONUS", that indicates that you do not
|
|
||||||
// want damage bonuses added to weapon damage at all. This feature was requested by ChaosSlayer on the EQEmu Forums.
|
|
||||||
//
|
|
||||||
// This is not recommended for normal usage, as the damage bonus represents a non-trivial component of the DPS output
|
|
||||||
// of weapons wielded by higher-level melee characters (especially for two-handed weapons).
|
|
||||||
int ucDamageBonus = 0;
|
|
||||||
if (Hand == EQ::invslot::slotPrimary && GetLevel() >= 28 && IsWarriorClass()) {
|
|
||||||
// Damage bonuses apply only to hits from the main hand (Hand == MainPrimary) by characters level 28 and above
|
|
||||||
// who belong to a melee class. If we're here, then all of these conditions apply.
|
|
||||||
ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQ::ItemData*) nullptr);
|
|
||||||
my_hit.min_damage = ucDamageBonus;
|
|
||||||
hate += ucDamageBonus;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
//Live AA - Sinister Strikes *Adds weapon damage bonus to offhand weapon.
|
|
||||||
if (Hand == EQ::invslot::slotSecondary) {
|
|
||||||
if (aabonuses.SecondaryDmgInc || itembonuses.SecondaryDmgInc || spellbonuses.SecondaryDmgInc) {
|
|
||||||
ucDamageBonus = GetWeaponDamageBonus(weapon ? weapon->GetItem() : (const EQ::ItemData*) nullptr);
|
|
||||||
my_hit.min_damage = ucDamageBonus;
|
|
||||||
hate += ucDamageBonus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LogCombat("Damage calculated: base [{}] min damage [{}] skill [{}]", my_hit.base_damage, my_hit.min_damage, my_hit.skill);
|
|
||||||
|
|
||||||
int hit_chance_bonus = 0;
|
|
||||||
my_hit.offense = offense(my_hit.skill);
|
|
||||||
my_hit.hand = Hand;
|
|
||||||
|
|
||||||
if (opts) {
|
|
||||||
my_hit.base_damage *= opts->damage_percent;
|
|
||||||
my_hit.base_damage += opts->damage_flat;
|
|
||||||
hate *= opts->hate_percent;
|
|
||||||
hate += opts->hate_flat;
|
|
||||||
hit_chance_bonus += opts->hit_chance;
|
|
||||||
}
|
|
||||||
|
|
||||||
my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus);
|
|
||||||
|
|
||||||
DoAttack(other, my_hit, opts, FromRiposte);
|
|
||||||
|
|
||||||
LogCombat("Final damage after all reductions: [{}]", my_hit.damage_done);
|
|
||||||
} else {
|
|
||||||
my_hit.damage_done = DMG_INVULNERABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same.
|
|
||||||
// If we are this far, this means we are atleast making a swing.
|
|
||||||
other->AddToHateList(this, hate);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
////// Send Attack Damage
|
|
||||||
///////////////////////////////////////////////////////////
|
|
||||||
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill);
|
|
||||||
|
|
||||||
if (GetHP() < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
MeleeLifeTap(my_hit.damage_done);
|
|
||||||
|
|
||||||
if (my_hit.damage_done > 0)
|
|
||||||
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
|
|
||||||
|
|
||||||
CommonBreakInvisibleFromCombat();
|
|
||||||
if (spellbonuses.NegateIfCombat)
|
|
||||||
BuffFadeByEffect(SE_NegateIfCombat);
|
|
||||||
|
|
||||||
if(GetTarget())
|
|
||||||
TriggerDefensiveProcs(other, Hand, true, my_hit.damage_done);
|
|
||||||
|
|
||||||
if (my_hit.damage_done > 0)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//proc chance includes proc bonus
|
//proc chance includes proc bonus
|
||||||
float Bot::GetProcChances(float ProcBonus, uint16 hand) {
|
float Bot::GetProcChances(float ProcBonus, uint16 hand) {
|
||||||
int mydex = GetDEX();
|
int mydex = GetDEX();
|
||||||
|
|||||||
@ -147,8 +147,6 @@ public:
|
|||||||
void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1,
|
void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1,
|
||||||
bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) override;
|
bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) override;
|
||||||
|
|
||||||
bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
|
||||||
ExtraAttackOptions *opts = nullptr) override;
|
|
||||||
bool HasRaid() override { return (GetRaid() ? true : false); }
|
bool HasRaid() override { return (GetRaid() ? true : false); }
|
||||||
bool HasGroup() override { return (GetGroup() ? true : false); }
|
bool HasGroup() override { return (GetGroup() ? true : false); }
|
||||||
Raid* GetRaid() override { return entity_list.GetRaidByMob(this); }
|
Raid* GetRaid() override { return entity_list.GetRaidByMob(this); }
|
||||||
|
|||||||
@ -254,8 +254,6 @@ public:
|
|||||||
//abstract virtual function implementations required by base abstract class
|
//abstract virtual function implementations required by base abstract class
|
||||||
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill);
|
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill);
|
||||||
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||||
virtual bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
|
||||||
ExtraAttackOptions *opts = nullptr);
|
|
||||||
virtual bool HasRaid() { return (GetRaid() ? true : false); }
|
virtual bool HasRaid() { return (GetRaid() ? true : false); }
|
||||||
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
virtual bool HasGroup() { return (GetGroup() ? true : false); }
|
||||||
virtual Raid* GetRaid() { return entity_list.GetRaidByClient(this); }
|
virtual Raid* GetRaid() { return entity_list.GetRaidByClient(this); }
|
||||||
@ -264,7 +262,6 @@ public:
|
|||||||
virtual void SetAttackTimer();
|
virtual void SetAttackTimer();
|
||||||
int GetQuiverHaste(int delay);
|
int GetQuiverHaste(int delay);
|
||||||
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
|
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
|
||||||
int64 DoDamageCaps(int64 base_damage);
|
|
||||||
|
|
||||||
void AI_Init();
|
void AI_Init();
|
||||||
void AI_Start(uint32 iMoveDelay = 0);
|
void AI_Start(uint32 iMoveDelay = 0);
|
||||||
|
|||||||
@ -53,7 +53,10 @@ class Corpse : public Mob {
|
|||||||
/* Corpse: General */
|
/* Corpse: General */
|
||||||
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill) { return true; }
|
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill) { return true; }
|
||||||
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||||
virtual bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = true, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) { return false; }
|
bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = true,
|
||||||
|
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
virtual bool HasRaid() { return false; }
|
virtual bool HasRaid() { return false; }
|
||||||
virtual bool HasGroup() { return false; }
|
virtual bool HasGroup() { return false; }
|
||||||
virtual Raid* GetRaid() { return 0; }
|
virtual Raid* GetRaid() { return 0; }
|
||||||
|
|||||||
@ -36,8 +36,8 @@ public:
|
|||||||
//abstract virtual function implementations required by base abstract class
|
//abstract virtual function implementations required by base abstract class
|
||||||
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill) { return true; }
|
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill) { return true; }
|
||||||
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) { return; }
|
||||||
virtual bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false,
|
bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||||
ExtraAttackOptions *opts = nullptr) {
|
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) override {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
virtual bool HasRaid() { return false; }
|
virtual bool HasRaid() { return false; }
|
||||||
|
|||||||
@ -199,7 +199,7 @@ public:
|
|||||||
virtual void ThrowingAttack(Mob* other) { }
|
virtual void ThrowingAttack(Mob* other) { }
|
||||||
// 13 = Primary (default), 14 = secondary
|
// 13 = Primary (default), 14 = secondary
|
||||||
virtual bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
virtual bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) = 0;
|
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr);
|
||||||
void DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr, bool FromRiposte = false);
|
void DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr, bool FromRiposte = false);
|
||||||
int MonkSpecialAttack(Mob* other, uint8 skill_used);
|
int MonkSpecialAttack(Mob* other, uint8 skill_used);
|
||||||
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
|
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
|
||||||
@ -1413,6 +1413,7 @@ public:
|
|||||||
void ResetAssistCap() { npc_assist_cap = 0; }
|
void ResetAssistCap() { npc_assist_cap = 0; }
|
||||||
int64 GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item);
|
int64 GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item);
|
||||||
int64 GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, int64 *hate = nullptr);
|
int64 GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, int64 *hate = nullptr);
|
||||||
|
int64 DoDamageCaps(int64 base_damage);
|
||||||
|
|
||||||
int64 GetHPRegen() const;
|
int64 GetHPRegen() const;
|
||||||
int64 GetManaRegen() const;
|
int64 GetManaRegen() const;
|
||||||
|
|||||||
@ -117,8 +117,8 @@ public:
|
|||||||
//abstract virtual function implementations requird by base abstract class
|
//abstract virtual function implementations requird by base abstract class
|
||||||
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill);
|
virtual bool Death(Mob* killerMob, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill);
|
||||||
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
virtual void Damage(Mob* from, int64 damage, uint16 spell_id, EQ::skills::SkillType attack_skill, bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None);
|
||||||
virtual bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false,
|
||||||
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr);
|
bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) override;
|
||||||
virtual bool HasRaid() { return false; }
|
virtual bool HasRaid() { return false; }
|
||||||
virtual bool HasGroup() { return false; }
|
virtual bool HasGroup() { return false; }
|
||||||
virtual Raid* GetRaid() { return 0; }
|
virtual Raid* GetRaid() { return 0; }
|
||||||
|
|||||||
@ -904,7 +904,6 @@ int64 Mob::TuneClientAttack(Mob* other, bool no_avoid, bool no_hit_chance, int h
|
|||||||
// Now figure out damage
|
// Now figure out damage
|
||||||
my_hit.damage_done = 1;
|
my_hit.damage_done = 1;
|
||||||
my_hit.min_damage = 0;
|
my_hit.min_damage = 0;
|
||||||
uint8 mylevel = GetLevel() ? GetLevel() : 1;
|
|
||||||
int64 hate = 0;
|
int64 hate = 0;
|
||||||
if (weapon)
|
if (weapon)
|
||||||
hate = (weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt);
|
hate = (weapon->GetItem()->Damage + weapon->GetItem()->ElemDmgAmt);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user