[Rules] Add HasteCap and Hastev3Cap rules for NPCs, Bots and Mercs (#4406)

* [Rules] Add HasteCap and Hastev3Cap rules for NPCs, Bots and Mercs

Previously NPCs, bots and mercs all had a flat haste cap of 150 whereas clients were capped at 100.

NPCs, bots and mercs used the character rule for v3 cap, they now each have their own.

Rules for v3 cap are the default of 25 as they were using.
Rules for haste caps are the default of 150 for NPCs they were using but lowered to 100 for bots and mercs, the same as clients.

This also adds haste output to the GM target stat window

* Fix for stat windows to account for client haste
This commit is contained in:
nytmyr 2024-07-22 05:06:49 -05:00 committed by GitHub
parent 3bfdc0cf71
commit c73a1e8bea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 63 additions and 14 deletions

View File

@ -242,6 +242,9 @@ RULE_INT(Mercs, AggroRadiusPuller, 25, "Determines the distance from which a mer
RULE_INT(Mercs, ResurrectRadius, 50, "Determines the distance from which a healer merc will attempt to resurrect a group member's corpse")
RULE_INT(Mercs, ScaleRate, 100, "Merc scale factor")
RULE_BOOL(Mercs, AllowMercSuspendInCombat, true, "Allow merc suspend in combat")
RULE_BOOL(Mercs, MercsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_INT(Mercs, MercsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
RULE_INT(Mercs, MercsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_CATEGORY_END()
RULE_CATEGORY(Guild)
@ -668,6 +671,9 @@ RULE_REAL(NPC, NPCHealOnGateAmount, 25, "How much the NPC will heal on gate if e
RULE_BOOL(NPC, AnimalsOpenDoors, true, "Determines or not whether animals open doors or not when they approach them")
RULE_INT(NPC, MaxRaceID, 732, "Maximum Race ID, RoF2 by default supports up to 732")
RULE_BOOL(NPC, DisableLastNames, false, "Enable to disable NPC Last Names")
RULE_BOOL(NPC, NPCIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_INT(NPC, NPCHasteCap, 150, "Haste cap for non-v3(over haste) haste")
RULE_INT(NPC, NPCHastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_CATEGORY_END()
RULE_CATEGORY(Aggro)
@ -759,6 +765,9 @@ RULE_BOOL(Bots, CazicTouchBotsOwner, true, "Default True. Cazic Touch/DT will hi
RULE_INT(Bots, BotsClickItemsMinLvl, 1, "Minimum level for bots to be able to use ^clickitem. Default 1.")
RULE_BOOL(Bots, BotsCanClickItems, true, "Enables the ability for bots to click items they have equipped. Default TRUE")
RULE_BOOL(Bots, CanClickMageEpicV1, true, "Whether or not bots are allowed to click Mage Epic 1.0. Default TRUE")
RULE_BOOL(Bots, BotsIgnoreLevelBasedHasteCaps, false, "Ignores hard coded level based haste caps.")
RULE_INT(Bots, BotsHasteCap, 100, "Haste cap for non-v3(over haste) haste")
RULE_INT(Bots, BotsHastev3Cap, 25, "Haste cap for v3(over haste) haste")
RULE_CATEGORY_END()
RULE_CATEGORY(Chat)

View File

@ -2415,7 +2415,7 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
DialogueWindow::TableCell(
fmt::format(
"{} ({})",
Strings::Commify(GetHaste()),
IsClient() ? Strings::Commify(CastToClient()->GetHaste()) : Strings::Commify(GetHaste()),
Strings::Commify(RuleI(Character, HasteCap))
)
)
@ -2682,12 +2682,12 @@ void Mob::SendStatsWindow(Client* c, bool use_window)
).c_str()
);
if (GetHaste()) {
if ((IsClient() && CastToClient()->GetHaste()) || (!IsClient() && GetHaste())) {
c->Message(
Chat::White,
fmt::format(
"Haste: {}/{} (Item: {} + Spell: {} + Over: {})",
Strings::Commify(GetHaste()),
IsClient() ? Strings::Commify(CastToClient()->GetHaste()) : Strings::Commify(GetHaste()),
Strings::Commify(RuleI(Character, HasteCap)),
Strings::Commify(itembonuses.haste),
Strings::Commify(spellbonuses.haste + spellbonuses.hastetype2),
@ -3217,6 +3217,14 @@ void Mob::ShowStats(Client* c)
).c_str()
);
c->Message(
Chat::White,
fmt::format(
"Combat Stats | Haste: {}",
GetHaste()
).c_str()
);
// Stats
c->Message(
Chat::White,
@ -5431,10 +5439,19 @@ int Mob::GetHaste()
h += spellbonuses.hastetype2 > 10 ? 10 : spellbonuses.hastetype2;
// 26+ no cap, 1-25 10
if (level > 25 || (IsClient() && RuleB(Character, IgnoreLevelBasedHasteCaps))) // 26+
if (
level > 25 ||
(
(IsNPC() && RuleB(NPC, NPCIgnoreLevelBasedHasteCaps)) ||
(IsBot() && RuleB(Bots, BotsIgnoreLevelBasedHasteCaps)) ||
(IsMerc() && RuleB(Mercs, MercsIgnoreLevelBasedHasteCaps))
)
) {
h += itembonuses.haste;
else // 1-25
}
else { // 1-25
h += itembonuses.haste > 10 ? 10 : itembonuses.haste;
}
// mobs are different!
Mob *owner = nullptr;
@ -5446,23 +5463,36 @@ int Mob::GetHaste()
cap = 10 + level;
cap += std::max(0, owner->GetLevel() - 39) + std::max(0, owner->GetLevel() - 60);
} else {
cap = 150;
cap = (IsNPC() ? RuleI(NPC, NPCHasteCap) : IsBot() ? RuleI(Bots, BotsHasteCap) : IsMerc() ? RuleI(Mercs, MercsHasteCap) : 150);
}
if(h > cap)
h = cap;
// 51+ 25 (despite there being higher spells...), 1-50 10
if (level > 50 || (IsClient() && RuleB(Character, IgnoreLevelBasedHasteCaps))) { // 51+
cap = RuleI(Character, Hastev3Cap);
if (spellbonuses.hastetype3 > cap) {
h += cap;
} else {
h += spellbonuses.hastetype3;
if (
(IsNPC() && !RuleB(NPC, NPCIgnoreLevelBasedHasteCaps)) ||
(IsBot() && !RuleB(Bots, BotsIgnoreLevelBasedHasteCaps)) ||
(IsMerc() && !RuleB(Mercs, MercsIgnoreLevelBasedHasteCaps))
) {
if (level > 50) { // 51+
cap = (IsNPC() ? RuleI(NPC, NPCHastev3Cap) : IsBot() ? RuleI(Bots, BotsHastev3Cap) : IsMerc() ? RuleI(Mercs, MercsHastev3Cap) : RuleI(Character, Hastev3Cap));
if (spellbonuses.hastetype3 > cap) {
h += cap;
}
else {
h += spellbonuses.hastetype3;
}
}
else { // 1-50
h += spellbonuses.hastetype3 > 10 ? 10 : spellbonuses.hastetype3;
}
} else { // 1-50
h += spellbonuses.hastetype3 > 10 ? 10 : spellbonuses.hastetype3;
}
else {
h += spellbonuses.hastetype3;
}
h += extra_haste; //GM granted haste.
return 100 + h;

View File

@ -234,6 +234,15 @@ inline std::string GetMobAttributeByString(Mob *mob, const std::string &attribut
return std::to_string(mob->GetMitigationAC());
}
if (attribute == "haste") {
if (mob->IsClient()) {
return Strings::Commify(std::to_string(mob->CastToClient()->GetHaste()));
}
else {
return Strings::Commify(std::to_string(mob->GetHaste()));
}
}
if (mob->IsNPC()) {
NPC *npc = mob->CastToNPC();
@ -700,6 +709,7 @@ void Mob::DisplayInfo(Mob *mob)
"total_defense",
"offense",
"mitigation_ac",
"haste",
};
window_text += WriteDisplayInfoSection(mob, "Calculations", calculations, 1, true);