diff --git a/zone/attack.cpp b/zone/attack.cpp index 6a65e7d33..5d6d2350b 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1275,7 +1275,7 @@ int64 Mob::GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, in 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 auto level = GetLevel(); @@ -1404,8 +1404,8 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, boo // check to see if we hit.. if (!FromRiposte && other->AvoidDamage(this, hit)) { - int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; - if (strike_through && zone->random.Roll(strike_through)) { + if (int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; + strike_through && zone->random.Roll(strike_through)) { MessageString(Chat::StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses! 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 // IsFromSpell added to allow spell effects to use Attack. (Mainly for the Rampage AA right now.) //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) { 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; } - if (!GetTarget()) + if (!GetTarget()) { 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 ( (IsCasting() && GetClass() != BARD && !IsFromSpell) || other == nullptr || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || (GetHP() < 0) || (!IsAttackAllowed(other)) + || (IsBot() && GetAppearance() == eaDead) ) { LogCombat("Attack cancelled, invalid circumstances"); 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"); - MessageString(Chat::DefaultText, DIVINE_AURA_NO_ATK); //You can't attack while invulnerable + MessageString(Chat::DefaultText, DIVINE_AURA_NO_ATK); return false; } - if (GetFeigned()) + if (GetFeigned()) { return false; // Rogean: How can you attack while feigned? Moved up from Aggro Code. + } - EQ::ItemInstance* weapon = nullptr; - if (Hand == EQ::invslot::slotSecondary) { // Kaiyodo - Pick weapon from the attacking hand - weapon = GetInv().GetItem(EQ::invslot::slotSecondary); + const EQ::ItemInstance* weapon = nullptr; + + + if (IsBot()) { + FaceTarget(GetTarget()); + } + + if (Hand == EQ::invslot::slotSecondary) { + weapon = (IsClient()) ? GetInv().GetItem(EQ::invslot::slotSecondary) : CastToBot()->GetBotItem(EQ::invslot::slotPrimary); OffHandAtk(true); } else { - weapon = GetInv().GetItem(EQ::invslot::slotPrimary); + weapon = (IsClient()) ? GetInv().GetItem(EQ::invslot::slotPrimary) : CastToBot()->GetBotItem(EQ::invslot::slotPrimary); OffHandAtk(false); } - if (weapon != nullptr) { if (!weapon->IsWeapon()) { LogCombat("Attack cancelled, Item [{}] ([{}]) is not a weapon", weapon->GetItem()->Name, weapon->GetID()); return(false); } - LogCombat("Attacking with weapon: [{}] ([{}])", weapon->GetItem()->Name, weapon->GetID()); + LogCombatDetail("Attacking with weapon: [{}] ([{}])", weapon->GetItem()->Name, weapon->GetID()); } else { - LogCombat("Attacking without a weapon"); + LogCombatDetail("Attacking without a weapon"); } DamageHitInfo my_hit; // calculate attack_skill and skillinuse depending on hand and weapon // also send Packet to near clients 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 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); @@ -1546,8 +1552,10 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b hate = hate * (100 + shield_inc) / 100; } - CheckIncreaseSkill(my_hit.skill, other, -15); - CheckIncreaseSkill(EQ::skills::SkillOffense, other, -15); + if (IsClient()) { + CastToClient()->CheckIncreaseSkill(my_hit.skill, other, -15); + CastToClient()->CheckIncreaseSkill(EQ::skills::SkillOffense, other, -15); + } // *************************************************************** // *** 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 //Live AA - Sinister Strikes *Adds weapon damage bonus to offhand weapon. - if (Hand == EQ::invslot::slotSecondary) { - if (aabonuses.SecondaryDmgInc || itembonuses.SecondaryDmgInc || spellbonuses.SecondaryDmgInc) { + if (Hand == EQ::invslot::slotSecondary && + ( + 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; - hate += ucDamageBonus; - } + my_hit.min_damage = ucDamageBonus; + hate += ucDamageBonus; } - // damage = mod_client_damage(damage, skillinuse, Hand, weapon, other); - - LogCombat("Damage calculated: base [{}] min damage [{}] skill [{}]", my_hit.base_damage, my_hit.min_damage, my_hit.skill); + LogCombatDetail("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); // 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); DoAttack(other, my_hit, opts, bRiposte); + + LogCombatDetail("Final damage after all reductions [{}]", my_hit.damage_done); } else { my_hit.damage_done = DMG_INVULNERABLE; @@ -1615,22 +1626,23 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b other->AddToHateList(this, hate); //Guard Assist Code - if (RuleB(Character, PVPEnableGuardFactionAssist)) { - if (IsClient() && other->IsClient() || (HasOwner() && GetOwner()->IsClient() && other->IsClient() )) { - auto& mob_list = entity_list.GetCloseMobList(other); - for (auto& e : mob_list) { - auto mob = e.second; - if (!mob) { - continue; - } + if (RuleB(Character, PVPEnableGuardFactionAssist) && + ( + (IsClient() && other->IsClient()) || + (HasOwner() && GetOwner()->IsClient() && other->IsClient()) + ) + ) { + for (auto const& [id, mob] : entity_list.GetCloseMobList(other)) { + if (!mob) { + continue; + } - if (mob->IsNPC() && mob->CastToNPC()->IsGuard()) { - float distance = Distance(other->CastToClient()->m_Position, mob->GetPosition()); - if ((mob->CheckLosFN(other) || mob->CheckLosFN(this)) && distance <= 70) { - auto petorowner = GetOwnerOrSelf(); - if (other->GetReverseFactionCon(mob) <= petorowner->GetReverseFactionCon(mob)) { - mob->AddToHateList(this); - } + if (mob->IsNPC() && mob->CastToNPC()->IsGuard()) { + float distance = Distance(other->CastToClient()->m_Position, mob->GetPosition()); + if ((mob->CheckLosFN(other) || mob->CheckLosFN(this)) && distance <= 70) { + auto petorowner = GetOwnerOrSelf(); + if (other->GetReverseFactionCon(mob) <= petorowner->GetReverseFactionCon(mob)) { + mob->AddToHateList(this); } } } @@ -1642,7 +1654,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b /////////////////////////////////////////////////////////// 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; } diff --git a/zone/beacon.h b/zone/beacon.h index 4c3a10081..2954edc90 100644 --- a/zone/beacon.h +++ b/zone/beacon.h @@ -36,12 +36,12 @@ public: //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 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 HasGroup() { return false; } virtual Raid* GetRaid() { 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 Process(); diff --git a/zone/bot.cpp b/zone/bot.cpp index fd778875d..0f7600919 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3375,7 +3375,7 @@ void Bot::AI_Process() TEST_COMBATANTS(); if (attack_timer.Check()) { // Process primary weapon attacks - Attack(tar, EQ::invslot::slotPrimary); + Mob::Attack(tar, EQ::invslot::slotPrimary); TEST_COMBATANTS(); TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false); @@ -3389,19 +3389,19 @@ void Bot::AI_Process() if (CanThisClassDoubleAttack()) { if (CheckBotDoubleAttack()) { - Attack(tar, EQ::invslot::slotPrimary, true); + Mob::Attack(tar, EQ::invslot::slotPrimary, true); } TEST_COMBATANTS(); if (GetSpecialAbility(SPECATK_TRIPLE) && CheckBotDoubleAttack(true)) { // tripleSuccess = true; - Attack(tar, EQ::invslot::slotPrimary, true); + Mob::Attack(tar, EQ::invslot::slotPrimary, true); } TEST_COMBATANTS(); // quad attack, does this belong here?? 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) { MessageString(Chat::NPCFlurry, YOU_FLURRY); - Attack(tar, EQ::invslot::slotPrimary, false); + Mob::Attack(tar, EQ::invslot::slotPrimary, false); 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 (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); 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(); TryCombatProcs(s_item, tar, EQ::invslot::slotSecondary); @@ -3476,7 +3476,7 @@ void Bot::AI_Process() if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) { 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 float Bot::GetProcChances(float ProcBonus, uint16 hand) { int mydex = GetDEX(); diff --git a/zone/bot.h b/zone/bot.h index 28b0c6a4b..2bfd356f2 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -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, 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 HasGroup() override { return (GetGroup() ? true : false); } Raid* GetRaid() override { return entity_list.GetRaidByMob(this); } diff --git a/zone/client.h b/zone/client.h index eaa04fe3f..2bb016fe6 100644 --- a/zone/client.h +++ b/zone/client.h @@ -254,8 +254,6 @@ public: //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 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 HasGroup() { return (GetGroup() ? true : false); } virtual Raid* GetRaid() { return entity_list.GetRaidByClient(this); } @@ -264,7 +262,6 @@ public: virtual void SetAttackTimer(); int GetQuiverHaste(int delay); void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false); - int64 DoDamageCaps(int64 base_damage); void AI_Init(); void AI_Start(uint32 iMoveDelay = 0); diff --git a/zone/corpse.h b/zone/corpse.h index 0bd3c1ee2..a5841cec2 100644 --- a/zone/corpse.h +++ b/zone/corpse.h @@ -53,7 +53,10 @@ class Corpse : public Mob { /* Corpse: General */ 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 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 HasGroup() { return false; } virtual Raid* GetRaid() { return 0; } diff --git a/zone/encounter.h b/zone/encounter.h index fd9f5e99d..8e79f356d 100644 --- a/zone/encounter.h +++ b/zone/encounter.h @@ -36,8 +36,8 @@ public: //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 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) { + bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, + bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) override { return false; } virtual bool HasRaid() { return false; } diff --git a/zone/mob.h b/zone/mob.h index 03e2582bb..556edbf63 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -199,7 +199,7 @@ public: virtual void ThrowingAttack(Mob* other) { } // 13 = Primary (default), 14 = secondary 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); int MonkSpecialAttack(Mob* other, uint8 skill_used); virtual void TryBackstab(Mob *other,int ReuseTime = 10); @@ -1413,6 +1413,7 @@ public: void ResetAssistCap() { npc_assist_cap = 0; } int64 GetWeaponDamage(Mob *against, const EQ::ItemData *weapon_item); int64 GetWeaponDamage(Mob *against, const EQ::ItemInstance *weapon_item, int64 *hate = nullptr); + int64 DoDamageCaps(int64 base_damage); int64 GetHPRegen() const; int64 GetManaRegen() const; diff --git a/zone/npc.h b/zone/npc.h index 6863d7576..aeaa2de1b 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -117,9 +117,9 @@ public: //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 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 false; } + bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, + bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) override; + virtual bool HasRaid() { return false; } virtual bool HasGroup() { return false; } virtual Raid* GetRaid() { return 0; } virtual Group* GetGroup() { return 0; } diff --git a/zone/tune.cpp b/zone/tune.cpp index ce5ca2d25..dcd51a0cc 100644 --- a/zone/tune.cpp +++ b/zone/tune.cpp @@ -904,7 +904,6 @@ int64 Mob::TuneClientAttack(Mob* other, bool no_avoid, bool no_hit_chance, int h // 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);