[Feature] Classic Taunt (Pre 2006) style of taunt (#3942)

* DRAFT - Classic Taunt (Pre 2006) style of taunt

RULE: ClassicTauntSystem

Completely seperate logic for each system. Could potentially be re-writte to be more inline but there are a good bit of minor differences.

* Consolidate Logic

Still needs in-game testing

* Feedback Request

* Updates per feedback
This commit is contained in:
Fryguy 2024-02-10 04:22:08 -05:00 committed by GitHub
parent 26693992b6
commit 14d4a2610f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 127 additions and 82 deletions

View File

@ -529,6 +529,8 @@ RULE_REAL(Combat, DefProcPerMinAgiContrib, 0.075, "How much agility contributes
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_INT(Combat, TauntChanceBonus, 0, "Bonus to taunt chance")
RULE_BOOL(Combat, ClassicTauntSystem, false, "Enable to use the pre 2006 taunt system.")
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

@ -2134,9 +2134,22 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
}
}
/* Classic Taunt Methodology
* This is not how Sony did it. This is a guess that fits the very limited data available.
* Low level players with maxed taunt for their level taunted about 50% on white cons.
* A 65 ranger with 150 taunt skill (max) taunted about 50% on level 60 and under NPCs.
* A 65 warrior with maxed taunt (230) was taunting around 50% on SSeru NPCs. */
/* Rashere in 2006: "your taunt skill was irrelevant if you were above level 60 and taunting
* something that was also above level 60."
* Also: "The chance to taunt an NPC higher level than yourself dropped off at double the rate
* if you were above level 60 than if you were below level 60 making it very hard to taunt creature
* higher level than yourself if you were above level 60."
*
* See http://www.elitegamerslounge.com/home/soearchive/viewtopic.php?t=81156 */
void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool from_spell, int32 bonus_hate)
{
if (!who || DivineAura() || (!from_spell && !CombatRange(who))) {
if (!who || DivineAura() || (!from_spell && !CombatRange(who)) || (IsNPC() && IsCharmed())) {
return;
}
@ -2144,10 +2157,10 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool from_spell
CastToClient()->CheckIncreaseSkill(EQ::skills::SkillTaunt, who, 10);
}
Mob *hate_top = who->GetHateMost();
Mob *hate_top = who->GetHateMost();
int level_difference = GetLevel() - who->GetLevel();
bool success = false;
bool success = false;
int taunt_chance = 0;
// Support for how taunt worked pre 2000 on LIVE - Can not taunt NPC over your level.
if (
@ -2159,104 +2172,133 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool from_spell
return;
}
// All values used based on live parses after taunt was updated in 2006.
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 taunt_chance = 50.0f;
if (always_succeed) {
taunt_chance = 101.0f;
if (always_succeed) {
taunt_chance = 100;
}
// Modern Taunt
if (!RuleB(Combat, ClassicTauntSystem)) {
if (
(hate_top && hate_top->GetHPRatio() >= 20) ||
!hate_top ||
chance_bonus
) {
if (chance_bonus) {
taunt_chance = chance_bonus;
} else {
if (level_difference < 0) {
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;
}
taunt_chance = 50;
}
} else {
if (level_difference < 0) {
taunt_chance += level_difference * 3;
if (taunt_chance < 20) {
taunt_chance = 20;
}
} else {
taunt_chance += level_difference * 5;
if (taunt_chance > 65) {
taunt_chance = 65;
}
}
// TauntSkillFalloff rate is not based on any real data. Default of 33% gives a reasonable
// result.
if (IsClient() && !always_succeed) {
taunt_chance -= (RuleR(Combat, TauntSkillFalloff) *
(CastToClient()->MaxSkill(EQ::skills::SkillTaunt) -
GetSkill(EQ::skills::SkillTaunt)));
(CastToClient()->MaxSkill(EQ::skills::SkillTaunt) -
GetSkill(EQ::skills::SkillTaunt)));
}
if (taunt_chance < 1) {
taunt_chance = 1.0f;
taunt_chance = 1;
}
taunt_chance /= 100.0f;
success = taunt_chance > zone->random.Real(0, 1);
LogHate(
"Taunter mob {} target npc {} taunt_chance [{}] success [{}] hate_top [{}]",
GetMobDescription(),
who->GetMobDescription(),
taunt_chance,
success ? "true" : "false",
hate_top ? hate_top->GetMobDescription() : "not found"
);
}
if (success) {
if (hate_top && hate_top != this) {
int64 new_hate = (
(who->GetNPCHate(hate_top) - who->GetNPCHate(this)) +
bonus_hate +
RuleI(Combat, TauntOverAggro) +
1
);
LogHate(
"Not Top Hate - Taunter [{}] Target [{}] Hated Top [{}] Hate Top Amt [{}] This Character Amt [{}] Bonus_Hate Amt [{}] TauntOverAggro Amt [{}] - Total [{}]",
GetMobDescription(),
who->GetMobDescription(),
hate_top->GetMobDescription(),
who->GetNPCHate(hate_top),
who->GetNPCHate(this),
bonus_hate,
RuleI(Combat, TauntOverAggro),
new_hate
);
who->CastToNPC()->AddToHateList(this, new_hate);
success = true;
} else { // Classic Taunt
if (GetLevel() >= 60 && level_difference < 0) {
if (level_difference < -5) {
taunt_chance = 0;
} else if (level_difference == -5) {
taunt_chance = 10;
} else {
who->CastToNPC()->AddToHateList(this, 12);
}
if (who->CanTalk()) {
who->SayString(SUCCESSFUL_TAUNT, GetCleanName());
taunt_chance = 50 + level_difference * 10;
}
} else {
MessageString(Chat::SpellFailure, FAILED_TAUNT);
// this will make the skill difference between the tank classes actually affect success rates
// but only for NPCs near the player's level. Mid to low blues will start to taunt at 50%
// even with lower skill
taunt_chance = 50 * GetSkill(EQ::skills::SkillTaunt) / (who->GetLevel() * 5 + 5);
taunt_chance += level_difference * 5;
if (taunt_chance > 50) {
taunt_chance = 50;
} else if (taunt_chance < 10) {
taunt_chance = 10;
}
}
// Taunt Chance Rule Bonus
taunt_chance += RuleI(Combat, TauntChanceBonus);
}
//success roll
success = zone->random.Roll(taunt_chance);
// Log result
LogHate(
"Taunter mob [{}] target npc [{}] taunt_chance [{}] success [{}] hate_top [{}]",
GetMobDescription(),
who->GetMobDescription(),
taunt_chance,
success ? "true" : "false",
hate_top ? hate_top->GetMobDescription() : "not found"
);
// Actual Taunting
if (success) {
if (hate_top && hate_top != this) {
int64 new_hate = (
(who->GetNPCHate(hate_top) - who->GetNPCHate(this)) +
bonus_hate +
RuleI(Combat, TauntOverAggro) +
1
);
LogHate(
"Not Top Hate - Taunter [{}] Target [{}] Hated Top [{}] Hate Top Amt [{}] This Character Amt [{}] Bonus_Hate Amt [{}] TauntOverAggro Amt [{}] - Total [{}]",
GetMobDescription(),
who->GetMobDescription(),
hate_top->GetMobDescription(),
who->GetNPCHate(hate_top),
who->GetNPCHate(this),
bonus_hate,
RuleI(Combat, TauntOverAggro),
new_hate
);
who->CastToNPC()->AddToHateList(this, new_hate);
} else {
LogHate("Already Hate Top");
who->CastToNPC()->AddToHateList(this, 12);
}
if (who->CanTalk()) {
who->SayString(SUCCESSFUL_TAUNT, GetCleanName());
}
MessageString(Chat::Skills, TAUNT_SUCCESS, who->GetCleanName());
} else {
MessageString(Chat::SpellFailure, FAILED_TAUNT);
MessageString(Chat::Skills, FAILED_TAUNT);
}
TryCastOnSkillUse(who, EQ::skills::SkillTaunt);
// Modern Abilities
if (!RuleB(Combat, ClassicTauntSystem)) {
TryCastOnSkillUse(who, EQ::skills::SkillTaunt);
if (HasSkillProcs()) {
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000);
}
if (HasSkillProcs()) {
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000);
}
if (success && HasSkillProcSuccess()) {
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000, true);
if (success && HasSkillProcSuccess()) {
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000, true);
}
}
}

View File

@ -140,6 +140,7 @@
#define SONG_NEEDS_BRASS 408 //You need to play a brass instrument for this song
#define AA_GAIN_ABILITY 410 //You have gained the ability "%T1" at a cost of %2 ability %T3.
#define AA_IMPROVE 411 //You have improved %T1 %2 at a cost of %3 ability %T4.
#define TAUNT_SUCCESS 412 //You taunt %1 to ignore others and attack you!
#define AA_REUSE_MSG 413 //You can use the ability %B1(1) again in %2 hour(s) %3 minute(s) %4 seconds.
#define AA_REUSE_MSG2 414 //You can use the ability %B1(1) again in %2 minute(s) %3 seconds.
#define YOU_HEALED 419 //%1 has healed you for %2 points of damage.