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); }