diff --git a/zone/common.h b/zone/common.h index a7a5f07a0..e79293388 100644 --- a/zone/common.h +++ b/zone/common.h @@ -737,6 +737,7 @@ typedef struct int ammo_slot; uint8 skill; float speed_mod; + bool disable_procs; } tProjatk; //eventually turn this into a typedef and diff --git a/zone/mob.cpp b/zone/mob.cpp index 48893ae6b..d754e27e2 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -355,6 +355,7 @@ Mob::Mob( ProjectileAtk[i].ammo_slot = 0; ProjectileAtk[i].skill = 0; ProjectileAtk[i].speed_mod = 0.0f; + ProjectileAtk[i].disable_procs = false; } for (int i = 0; i < MAX_FOCUS_PROC_LIMIT_TIMERS; i++) { diff --git a/zone/mob.h b/zone/mob.h index dd5c29b70..edd3ac36a 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1000,10 +1000,10 @@ public: int32 ReduceAllDamage(int32 damage); void DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int base_damage, int min_damage = 0, int32 hate_override = -1, int ReuseTime = 10); - virtual void DoThrowingAttackDmg(Mob* other, const EQ::ItemInstance* RangeWeapon = nullptr, const EQ::ItemData* AmmoItem = nullptr, uint16 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, int AmmoSlot = 0, float speed = 4.0f); + virtual void DoThrowingAttackDmg(Mob* other, const EQ::ItemInstance* RangeWeapon = nullptr, const EQ::ItemData* AmmoItem = nullptr, uint16 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, int AmmoSlot = 0, float speed = 4.0f, bool DisableProcs = false); void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, EQ::skills::SkillType skillinuse, int16 chance_mod = 0, int16 focus = 0, bool CanRiposte = false, int ReuseTime = 0); - virtual void DoArcheryAttackDmg(Mob* other, const EQ::ItemInstance* RangeWeapon = nullptr, const EQ::ItemInstance* Ammo = nullptr, uint16 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, uint32 ammo_id = 0, const EQ::ItemData *AmmoItem = nullptr, int AmmoSlot = 0, float speed = 4.0f); - bool TryProjectileAttack(Mob* other, const EQ::ItemData *item, EQ::skills::SkillType skillInUse, uint16 weapon_dmg, const EQ::ItemInstance* RangeWeapon, const EQ::ItemInstance* Ammo, int AmmoSlot, float speed); + virtual void DoArcheryAttackDmg(Mob* other, const EQ::ItemInstance* RangeWeapon = nullptr, const EQ::ItemInstance* Ammo = nullptr, uint16 weapon_damage = 0, int16 chance_mod = 0, int16 focus = 0, int ReuseTime = 0, uint32 range_id = 0, uint32 ammo_id = 0, const EQ::ItemData *AmmoItem = nullptr, int AmmoSlot = 0, float speed = 4.0f, bool DisableProcs = false); + bool TryProjectileAttack(Mob* other, const EQ::ItemData *item, EQ::skills::SkillType skillInUse, uint16 weapon_dmg, const EQ::ItemInstance* RangeWeapon, const EQ::ItemInstance* Ammo, int AmmoSlot, float speed, bool DisableProcs = false); void ProjectileAttack(); inline bool HasProjectileAttack() const { return ActiveProjectileATK; } inline void SetProjectileAttack(bool value) { ActiveProjectileATK = value; } diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 5116eb481..0a51d10fb 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -783,7 +783,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, const EQ::ItemInstance *Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, uint32 range_id, - uint32 ammo_id, const EQ::ItemData *AmmoItem, int AmmoSlot, float speed) + uint32 ammo_id, const EQ::ItemData *AmmoItem, int AmmoSlot, float speed, bool DisableProcs) { if ((other == nullptr || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || @@ -848,7 +848,7 @@ void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, co if (LaunchProjectile) { // 1: Shoot the Projectile once we calculate weapon damage. TryProjectileAttack(other, AmmoItem, EQ::skills::SkillArchery, (WDmg + ADmg), RangeWeapon, - Ammo, AmmoSlot, speed); + Ammo, AmmoSlot, speed, DisableProcs); return; } @@ -896,46 +896,49 @@ void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, co other->Damage(this, TotalDmg, SPELL_UNKNOWN, EQ::skills::SkillArchery); + if (!DisableProcs) { + // Weapon Proc + if (RangeWeapon && other && !other->HasDied()) { + TryCombatProcs(RangeWeapon, other, EQ::invslot::slotRange); + } - // Weapon Proc - if (RangeWeapon && other && !other->HasDied()) { - TryCombatProcs(RangeWeapon, other, EQ::invslot::slotRange); - } - - // Ammo Proc, do not try spell procs if from ammo. - if (last_ammo_used) { - TryWeaponProc(nullptr, last_ammo_used, other, EQ::invslot::slotRange); - } - else if (Ammo && other && !other->HasDied()) { - TryWeaponProc(Ammo, Ammo->GetItem(), other, EQ::invslot::slotRange); + // Ammo Proc, do not try spell procs if from ammo. + if (last_ammo_used) { + TryWeaponProc(nullptr, last_ammo_used, other, EQ::invslot::slotRange); + } + else if (Ammo && other && !other->HasDied()) { + TryWeaponProc(Ammo, Ammo->GetItem(), other, EQ::invslot::slotRange); + } } TryCastOnSkillUse(other, EQ::skills::SkillArchery); - // Skill Proc Attempt - if (HasSkillProcs() && other && !other->HasDied()) { - if (ReuseTime) { - TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime); + if (!DisableProcs) { + // Skill Proc Attempt + if (HasSkillProcs() && other && !other->HasDied()) { + if (ReuseTime) { + TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime); + } + else { + TrySkillProc(other, EQ::skills::SkillArchery, 0, false, EQ::invslot::slotRange); + } } - else { - TrySkillProc(other, EQ::skills::SkillArchery, 0, false, EQ::invslot::slotRange); - } - } - // Skill Proc Success ... can proc off hits OR misses - if (HasSkillProcSuccess() && other && !other->HasDied()) { - if (ReuseTime) { - TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime, true); - } - else { - TrySkillProc(other, EQ::skills::SkillArchery, 0, true, EQ::invslot::slotRange); + // Skill Proc Success ... can proc off hits OR misses + if (HasSkillProcSuccess() && other && !other->HasDied()) { + if (ReuseTime) { + TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime, true); + } + else { + TrySkillProc(other, EQ::skills::SkillArchery, 0, true, EQ::invslot::slotRange); + } } } } bool Mob::TryProjectileAttack(Mob *other, const EQ::ItemData *item, EQ::skills::SkillType skillInUse, uint16 weapon_dmg, const EQ::ItemInstance *RangeWeapon, - const EQ::ItemInstance *Ammo, int AmmoSlot, float speed) + const EQ::ItemInstance *Ammo, int AmmoSlot, float speed, bool DisableProcs) { if (!other) return false; @@ -996,6 +999,7 @@ bool Mob::TryProjectileAttack(Mob *other, const EQ::ItemData *item, EQ::skills:: ProjectileAtk[slot].ammo_slot = AmmoSlot; ProjectileAtk[slot].skill = skillInUse; ProjectileAtk[slot].speed_mod = speed; + ProjectileAtk[slot].disable_procs = DisableProcs; SetProjectileAttack(true); @@ -1072,11 +1076,11 @@ void Mob::ProjectileAttack() DoArcheryAttackDmg(target, nullptr, nullptr, ProjectileAtk[i].wpn_dmg, 0, 0, 0, ProjectileAtk[i].ranged_id, ProjectileAtk[i].ammo_id, nullptr, - ProjectileAtk[i].ammo_slot); + ProjectileAtk[i].ammo_slot, 4.0f, ProjectileAtk[i].disable_procs); else if (ProjectileAtk[i].skill == EQ::skills::SkillThrowing) DoThrowingAttackDmg(target, nullptr, nullptr, ProjectileAtk[i].wpn_dmg, 0, 0, 0, ProjectileAtk[i].ranged_id, - ProjectileAtk[i].ammo_slot); + ProjectileAtk[i].ammo_slot, 4.0f, ProjectileAtk[i].disable_procs); else if (ProjectileAtk[i].skill == EQ::skills::SkillConjuration && IsValidSpell(ProjectileAtk[i].wpn_dmg)) SpellOnTarget(ProjectileAtk[i].wpn_dmg, target, false, true, @@ -1376,12 +1380,12 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 } void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, const EQ::ItemData *AmmoItem, - uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, uint32 range_id, - int AmmoSlot, float speed) + uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, uint32 range_id, + int AmmoSlot, float speed, bool DisableProcs) { if ((other == nullptr || - ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || - HasDied() || (!IsAttackAllowed(other)) || (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)))) { + ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || + HasDied() || (!IsAttackAllowed(other)) || (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)))) { return; } @@ -1398,11 +1402,12 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c if (RuleB(Combat, ProjectileDmgOnImpact)) { if (AmmoItem) { LaunchProjectile = true; - } else { + } + else { if (!RangeWeapon && range_id) { if (IsClient()) { m_RangeWeapon = CastToClient()->m_inv[AmmoSlot]; - + if (m_RangeWeapon && m_RangeWeapon->GetItem() && m_RangeWeapon->GetItem()->ID == range_id) { RangeWeapon = m_RangeWeapon; } @@ -1412,7 +1417,8 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c } } } - } else if (AmmoItem) { + } + else if (AmmoItem) { SendItemAnimation(other, AmmoItem, EQ::skills::SkillThrowing); } @@ -1430,10 +1436,11 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c if (LaunchProjectile) { TryProjectileAttack(other, AmmoItem, EQ::skills::SkillThrowing, WDmg, RangeWeapon, - nullptr, AmmoSlot, speed); + nullptr, AmmoSlot, speed); return; } - } else { + } + else { WDmg = weapon_damage; } @@ -1458,7 +1465,8 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c TotalDmg = my_hit.damage_done; LogCombat("Item DMG [{}]. Hit for damage [{}]", WDmg, TotalDmg); - } else { + } + else { TotalDmg = DMG_INVULNERABLE; } @@ -1467,25 +1475,29 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c other->Damage(this, TotalDmg, SPELL_UNKNOWN, EQ::skills::SkillThrowing); - if (other && !other->HasDied()) { + if (!DisableProcs && other && !other->HasDied()) { TryCombatProcs(RangeWeapon, other, EQ::invslot::slotRange, last_ammo_used); } - if (HasSkillProcs() && other && !other->HasDied()) { - if (ReuseTime) { - TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime); - } - else { - TrySkillProc(other, EQ::skills::SkillThrowing, 0, false, EQ::invslot::slotRange); - } - } + TryCastOnSkillUse(other, EQ::skills::SkillThrowing); - if (HasSkillProcSuccess() && other && !other->HasDied()) { - if (ReuseTime) { - TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime, true); + if (!DisableProcs) { + if (HasSkillProcs() && other && !other->HasDied()) { + if (ReuseTime) { + TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime); + } + else { + TrySkillProc(other, EQ::skills::SkillThrowing, 0, false, EQ::invslot::slotRange); + } } - else { - TrySkillProc(other, EQ::skills::SkillThrowing, 0, true, EQ::invslot::slotRange); + + if (HasSkillProcSuccess() && other && !other->HasDied()) { + if (ReuseTime) { + TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime, true); + } + else { + TrySkillProc(other, EQ::skills::SkillThrowing, 0, true, EQ::invslot::slotRange); + } } } @@ -2250,10 +2262,8 @@ void Mob::DoMeleeSkillAttackDmg(Mob *other, uint16 weapon_damage, EQ::skills::Sk damage = DMG_INVULNERABLE; } - bool CanSkillProc = true; if (skillinuse == EQ::skills::SkillOffense) { // Hack to allow damage to display. skillinuse = EQ::skills::SkillTigerClaw; //'strike' your opponent - Arbitrary choice for message. - CanSkillProc = false; // Disable skill procs } other->AddToHateList(this, hate, 0); @@ -2263,14 +2273,6 @@ void Mob::DoMeleeSkillAttackDmg(Mob *other, uint16 weapon_damage, EQ::skills::Sk return; TryCastOnSkillUse(other, skillinuse); - - if (CanSkillProc && HasSkillProcs()) { - TrySkillProc(other, skillinuse, ReuseTime); - } - - if (CanSkillProc && (damage > 0) && HasSkillProcSuccess()) { - TrySkillProc(other, skillinuse, ReuseTime, true); - } } bool Mob::CanDoSpecialAttack(Mob *other) { diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index c9d76de7a..cc4e90ccd 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2275,10 +2275,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove switch(spells[spell_id].skill) { case EQ::skills::SkillThrowing: - caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base_value[i],spells[spell_id].limit_value[i], 0, ReuseTime); + caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base_value[i],spells[spell_id].limit_value[i], 0, ReuseTime, 0, 0, 4.0f, true); break; case EQ::skills::SkillArchery: - caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base_value[i],spells[spell_id].limit_value[i], 0, ReuseTime); + caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base_value[i],spells[spell_id].limit_value[i], 0, ReuseTime, 0, 0, nullptr, 0, 4.0f, true); break; default: caster->DoMeleeSkillAttackDmg(this, spells[spell_id].base_value[i], spells[spell_id].skill, spells[spell_id].limit_value[i], 0, false, ReuseTime);