From 06337fe762dc4cd65f67072781f5324e6dff775d Mon Sep 17 00:00:00 2001 From: Alex King <89047260+Kinglykrab@users.noreply.github.com> Date: Sun, 17 Sep 2023 14:15:51 -0400 Subject: [PATCH] [Feature] Add Defensive Proc Rules for Level Gap Penalty (#3580) # Notes - Allows operators to modify the level gap penalty and level gap required for the penalty for defensive procs' level gap penalty. - Setting `Spells:DefensiveProcPenaltyLevelGap` to `-1` will disable the penalty. --- common/ruletypes.h | 2 ++ zone/attack.cpp | 37 ++++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index b09681ba5..2dab1b0cb 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -454,6 +454,8 @@ RULE_INT(Spells, ResurrectionEffectBlock, 2, "0 = allow overwrites/rule disabled RULE_BOOL(Spells, WaterMatchRequiredForLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for spells LoS to pass.") RULE_INT(Spells, WizardCritMinimumRandomRatio, 20, "The minimum value for the random range which Wizards and Caster DPS Mercs innately have for spell crit ratio. Set to 20 for vanilla values.") RULE_INT(Spells, WizardCritMaximumRandomRatio, 70, "The maximum value for the random range which Wizards and Caster DPS Mercs innately have for spell crit ratio. Set to 70 for vanilla values.") +RULE_INT(Spells, DefensiveProcPenaltyLevelGap, 6, "Defensive Proc Penalty Level Gap where procs start losing their proc rate at RuleR(Spells, DefensiveProcPenaltyModifier)% per level difference") +RULE_REAL(Spells, DefensiveProcPenaltyLevelGapModifier, 10.0f, "Defensive Proc Penalty Level Gap Modifier where procs start losing their proc rate at defined % after RuleI(Spells, DefensiveProcLevelGap) level difference") RULE_CATEGORY_END() RULE_CATEGORY(Combat) diff --git a/zone/attack.cpp b/zone/attack.cpp index 6f424b7d3..7e40c8220 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4539,8 +4539,8 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 h } // argument 'weapon' not used -void Mob::TryDefensiveProc(Mob *on, uint16 hand) { - +void Mob::TryDefensiveProc(Mob *on, uint16 hand) +{ if (!on) { SetTarget(nullptr); LogError("A null Mob object was passed to Mob::TryDefensiveProc for evaluation!"); @@ -4552,23 +4552,26 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) { } if (!on->HasDied() && on->GetHP() > 0) { - - float ProcChance, ProcBonus; - on->GetDefensiveProcChances(ProcBonus, ProcChance, hand, this); + float proc_chance, proc_bonus; + on->GetDefensiveProcChances(proc_bonus, proc_chance, hand, this); if (hand == EQ::invslot::slotSecondary) { - ProcChance /= 2; + proc_chance /= 2; } - int level_penalty = 0; - int level_diff = GetLevel() - on->GetLevel(); - if (level_diff > 6) {//10% penalty per level if > 6 levels over target. - level_penalty = (level_diff - 6) * 10; + int level_penalty = 0; + int level_diff = GetLevel() - on->GetLevel(); + int penalty_level_gap = RuleI(Spells, DefensiveProcPenaltyLevelGap); + if ( + penalty_level_gap >= 0 && + level_diff > penalty_level_gap + ) {//10% penalty per level if > penalty_level_gap levels over target. + level_penalty = (level_diff - penalty_level_gap) * RuleR(Spells, DefensiveProcPenaltyLevelGapModifier); } - ProcChance -= ProcChance*level_penalty / 100; + proc_chance -= proc_chance * level_penalty / 100; - if (ProcChance < 0) { + if (proc_chance < 0) { return; } @@ -4576,7 +4579,7 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) { for (int i = 0; i < MAX_PROCS; i++) { if (IsValidSpell(DefensiveProcs[i].spellID)) { if (!IsProcLimitTimerActive(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, ProcType::DEFENSIVE_PROC)) { - float chance = ProcChance * (static_cast(DefensiveProcs[i].chance) / 100.0f); + float chance = proc_chance * (static_cast(DefensiveProcs[i].chance) / 100.0f); if (zone->random.Roll(chance)) { ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, DefensiveProcs[i].base_spellID); @@ -4589,14 +4592,14 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) { //AA Procs if (IsOfClientBot()) { for (int i = 0; i < MAX_AA_PROCS; i += 4) { - int32 aa_rank_id = aabonuses.DefensiveProc[i + +SBIndex::COMBAT_PROC_ORIGIN_ID]; - int32 aa_spell_id = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID]; - int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD]; + int32 aa_rank_id = aabonuses.DefensiveProc[i + +SBIndex::COMBAT_PROC_ORIGIN_ID]; + int32 aa_spell_id = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID]; + int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD]; uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]; if (aa_rank_id) { if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, ProcType::DEFENSIVE_PROC)) { - float chance = ProcChance * (static_cast(aa_proc_chance) / 100.0f); + float chance = proc_chance * (static_cast(aa_proc_chance) / 100.0f); if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) { ExecWeaponProc(nullptr, aa_spell_id, on); SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, ProcType::DEFENSIVE_PROC);