[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
This commit is contained in:
Fryguy 2024-01-08 12:11:04 -05:00 committed by GitHub
parent 3e958c575b
commit dfb06db17b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 43 deletions

View File

@ -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")

View File

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

View File

@ -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<float>(level_difference) * 3.0f;
if (tauntchance < 20)
tauntchance = 20.0f;
}
else {
tauntchance += static_cast<float>(level_difference) * 5.0f;
if (tauntchance > 65)
tauntchance = 65.0f;
taunt_chance += static_cast<float>(level_difference) * 3.0f;
if (taunt_chance < 20) {
taunt_chance = 20.0f;
}
} else {
taunt_chance += static_cast<float>(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);
}