From dfb06db17b9f2c8467fb0514896727149bfd2904 Mon Sep 17 00:00:00 2001 From: Fryguy Date: Mon, 8 Jan 2024 12:11:04 -0500 Subject: [PATCH] [Rule] Over Taunt Hate (#3900) * [Rule] Over taunt hate rule Rule to add additional hate when taunt succeeds. This can help tune snap aggro on taunt classes. Only works when taunt succeeds and not already top hate. * Requested Adjustments * Add default +1 on rule * Revert back to 0 default on rule with +1 on the standard formula * formatting fix --- common/ruletypes.h | 1 + zone/mob.h | 2 +- zone/special_attacks.cpp | 93 ++++++++++++++++++++++------------------ 3 files changed, 53 insertions(+), 43 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 09c3798f4..eef40aff7 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -515,6 +515,7 @@ RULE_REAL(Combat, AvgDefProcsPerMinute, 2.0, "Average defense procs per minute") RULE_REAL(Combat, DefProcPerMinAgiContrib, 0.075, "How much agility contributes to defensive proc rate") RULE_INT(Combat, NPCFlurryChance, 20, "Chance for NPC to flurry") RULE_BOOL(Combat, TauntOverLevel, 1, "Allows you to taunt NPC's over warriors level") +RULE_INT(Combat, TauntOverAggro, 0, "+ amount over hate_top it will add before any bonus hate.") RULE_REAL(Combat, TauntSkillFalloff, 0.33, "For every taunt skill point that's not maxed you lose this percentage chance to taunt") RULE_BOOL(Combat, EXPFromDmgShield, false, "Determine if damage from a damage shield counts for experience gain") RULE_INT(Combat, QuiverHasteCap, 1000, "Quiver haste cap 1000 on live for a while, currently 700 on live") diff --git a/zone/mob.h b/zone/mob.h index c3833c555..039cec200 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1147,7 +1147,7 @@ public: void StartEnrage(); void ProcessEnrage(); bool IsEnraged(); - void Taunt(NPC *who, bool always_succeed, int chance_bonus = 0, bool FromSpell = false, int32 bonus_hate = 0); + void Taunt(NPC *who, bool always_succeed, int chance_bonus = 0, bool from_spell = false, int32 bonus_hate = 0); virtual void AI_Init(); virtual void AI_Start(uint32 iMoveDelay = 0); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index b642b3faa..8de2e5d22 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -2128,19 +2128,15 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) } } -void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool FromSpell, int32 bonus_hate) +void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool from_spell, int32 bonus_hate) { - if (who == nullptr) + if (!who || DivineAura() || (!from_spell && !CombatRange(who))) { return; + } - if (DivineAura()) - return; - - if (!FromSpell && !CombatRange(who)) - return; - - if (!always_succeed && IsClient()) + if (!always_succeed && IsClient()) { CastToClient()->CheckIncreaseSkill(EQ::skills::SkillTaunt, who, 10); + } Mob *hate_top = who->GetHateMost(); @@ -2148,57 +2144,63 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool FromSpell, bool success = false; // Support for how taunt worked pre 2000 on LIVE - Can not taunt NPC over your level. - if ((RuleB(Combat, TauntOverLevel) == false) && (level_difference < 0) || - who->GetSpecialAbility(IMMUNE_TAUNT)) { + if ( + !RuleB(Combat, TauntOverLevel) && + level_difference < 0 || + who->GetSpecialAbility(IMMUNE_TAUNT) + ) { MessageString(Chat::SpellFailure, FAILED_TAUNT); return; } // All values used based on live parses after taunt was updated in 2006. - if ((hate_top && hate_top->GetHPRatio() >= 20) || hate_top == nullptr || chance_bonus) { + if ( + (hate_top && hate_top->GetHPRatio() >= 20) || + !hate_top || + chance_bonus + ) { // SE_Taunt this is flat chance if (chance_bonus) { success = zone->random.Roll(chance_bonus); } else { - float tauntchance = 50.0f; - - if (always_succeed) - tauntchance = 101.0f; - - else { + float taunt_chance = 50.0f; + if (always_succeed) { + taunt_chance = 101.0f; + } else { if (level_difference < 0) { - tauntchance += static_cast(level_difference) * 3.0f; - if (tauntchance < 20) - tauntchance = 20.0f; - } - - else { - tauntchance += static_cast(level_difference) * 5.0f; - if (tauntchance > 65) - tauntchance = 65.0f; + taunt_chance += static_cast(level_difference) * 3.0f; + if (taunt_chance < 20) { + taunt_chance = 20.0f; + } + } else { + taunt_chance += static_cast(level_difference) * 5.0f; + if (taunt_chance > 65) { + taunt_chance = 65.0f; + } } } // TauntSkillFalloff rate is not based on any real data. Default of 33% gives a reasonable // result. - if (IsClient() && !always_succeed) - tauntchance -= (RuleR(Combat, TauntSkillFalloff) * + if (IsClient() && !always_succeed) { + taunt_chance -= (RuleR(Combat, TauntSkillFalloff) * (CastToClient()->MaxSkill(EQ::skills::SkillTaunt) - GetSkill(EQ::skills::SkillTaunt))); + } - if (tauntchance < 1) - tauntchance = 1.0f; + if (taunt_chance < 1) { + taunt_chance = 1.0f; + } - tauntchance /= 100.0f; - - success = tauntchance > zone->random.Real(0, 1); + taunt_chance /= 100.0f; + success = taunt_chance > zone->random.Real(0, 1); LogHate( - "Taunter mob {} target npc {} tauntchance [{}] success [{}] hate_top [{}]", + "Taunter mob {} target npc {} taunt_chance [{}] success [{}] hate_top [{}]", GetMobDescription(), who->GetMobDescription(), - tauntchance, + taunt_chance, success ? "true" : "false", hate_top ? hate_top->GetMobDescription() : "not found" ); @@ -2206,27 +2208,34 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool FromSpell, if (success) { if (hate_top && hate_top != this) { - int64 newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1 + bonus_hate; + int64 new_hate = ( + (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + + bonus_hate + + RuleI(Combat, TauntOverAggro) + + 1 + ); LogHate( - "Taunter mob {} target npc {} newhate [{}] hated_top {} hate_of_top [{}] this_hate [{}] bonus_hate [{}]", + "Not Top Hate - Taunter [{}] Target [{}] Hated Top [{}] Hate Top Amt [{}] This Character Amt [{}] Bonus_Hate Amt [{}] TauntOverAggro Amt [{}] - Total [{}]", GetMobDescription(), who->GetMobDescription(), - newhate, hate_top->GetMobDescription(), who->GetNPCHate(hate_top), who->GetNPCHate(this), - bonus_hate + bonus_hate, + RuleI(Combat, TauntOverAggro), + new_hate ); - who->CastToNPC()->AddToHateList(this, newhate); + who->CastToNPC()->AddToHateList(this, new_hate); success = true; } else { who->CastToNPC()->AddToHateList(this, 12); } - if (who->CanTalk()) + if (who->CanTalk()) { who->SayString(SUCCESSFUL_TAUNT, GetCleanName()); + } } else { MessageString(Chat::SpellFailure, FAILED_TAUNT); }