diff --git a/common/ruletypes.h b/common/ruletypes.h index 50554fa50..2d1f2b9f1 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -93,6 +93,12 @@ RULE_INT(Character, ItemEnduranceRegenCap, 15, "Limit on endurance regeneration RULE_INT(Character, ItemExtraDmgCap, 150, "Cap for bonuses to melee skills like Bash, Frenzy, etc.") RULE_INT(Character, HasteCap, 100, "Haste cap for non-v3(over haste) haste") RULE_INT(Character, Hastev3Cap, 25, "Haste cap for v3(over haste) haste") +RULE_REAL(Character, HeroicStrengthMultiplier, 1.00, "Multplier scales benefits from Heroic Strength. Grants 25 Base Endurance, 0.05 Endurance Regen, 1 Melee Damage each Hit, and 1 Shield AC per 10 Heroic Strength.") +RULE_REAL(Character, HeroicStaminaMultiplier, 1.00, "Multplier scales benefits from Heroic Stamina. Grants 25 Base Endurance, 0.05 Endurance Regen, 100 Base HP, and 0.5 HP Regen per 10 Heroic Stamina.") +RULE_REAL(Character, HeroicAgilityMultiplier, 1.00, "Multplier scales benefits from Heroic Agility. Grants 25 Base Endurance, 0.05 Endurance Regen, and 1 Avoidance AC per 10 Heroic Agility. (Rule does not change Dodge Chance)") +RULE_REAL(Character, HeroicDexterityMultiplier, 1.00, "Multplier scales benefits from Heroic Dexterity. Grants 25 Base Endurance, 0.05 Endurance Regen, and 1 Archery/Throwing Damage each hit per 10 Heroic Dexterity. (Rule does not change Assassinate/Headshot/Block/Parry/Riposte Chances)") +RULE_REAL(Character, HeroicWisdomMultiplier, 1.00, "Multplier scales benefits from Heroic Wisdom. Grants 250 Base Mana, 1 Mana Regen per 25 Heroic Wisdom.") +RULE_REAL(Character, HeroicIntelligenceMultiplier, 1.00, "Multplier scales benefits from Heroic Intelligence. Grants 250 Base Mana, 1 Mana Regen per 25 Heroic Intelligence.") RULE_INT(Character, SkillUpModifier, 100, "The probability for a skill-up is multiplied by value/100") RULE_BOOL(Character, SharedBankPlat, false, "Shared bank platinum. Off by default to prevent duplication") RULE_BOOL(Character, BindAnywhere, false, "Allows players to bind their soul anywhere in the world") diff --git a/zone/attack.cpp b/zone/attack.cpp index d5bf700e7..4ed5897f2 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -250,7 +250,7 @@ int Mob::compute_defense() int defense = GetSkill(EQ::skills::SkillDefense) * 400 / 225; defense += (8000 * (GetAGI() - 40)) / 36000; if (IsOfClientBot()) { - defense += GetHeroicAGI() / 10; + defense += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 10; } //516 SE_AC_Mitigation_Max_Percent @@ -883,7 +883,7 @@ int Mob::ACSum(bool skip_caps) shield_ac = CalcRecommendedLevelBonus(GetLevel(), inst->GetItemRecommendedLevel(true), inst->GetItemArmorClass(true)); } } - shield_ac += GetHeroicSTR() / 10; + shield_ac += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10; } // EQ math ac = (ac * 4) / 3; @@ -5897,10 +5897,10 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac switch (hit.skill) { case EQ::skills::SkillThrowing: case EQ::skills::SkillArchery: - extra = GetHeroicDEX() / 10; + extra = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 10; break; default: - extra = GetHeroicSTR() / 10; + extra = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10; break; } hit.damage_done += extra; diff --git a/zone/bot.cpp b/zone/bot.cpp index a42b033f8..fb79f333e 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -6693,10 +6693,10 @@ int64 Bot::CalcManaRegenCap() { int64 cap = RuleI(Character, ItemManaRegenCap) + aabonuses.ItemManaRegenCap; switch(GetCasterClass()) { case 'I': - cap += (itembonuses.HeroicINT / 25); + cap += itembonuses.HeroicINT * RuleR(Character, HeroicIntelligenceMultiplier) / 25; break; case 'W': - cap += (itembonuses.HeroicWIS / 25); + cap += itembonuses.HeroicWIS * RuleR(Character, HeroicWisdomMultiplier) / 25; break; } return (cap * RuleI(Character, ManaRegenMultiplier) / 100); @@ -7088,8 +7088,9 @@ int32 Bot::LevelRegen() { int64 Bot::CalcHPRegen() { int32 regen = (LevelRegen() + itembonuses.HPRegen + spellbonuses.HPRegen); - regen += GetHeroicSTA() / 20; + regen += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 20; regen += (aabonuses.HPRegen + GroupLeadershipAAHealthRegeneration()); + regen = ((regen * RuleI(Character, HPRegenMultiplier)) / 100); return regen; } @@ -7109,9 +7110,9 @@ int64 Bot::CalcManaRegen() { regen = (2 + spellbonuses.ManaRegen + itembonuses.ManaRegen); if(GetCasterClass() == 'I') - regen += (itembonuses.HeroicINT / 25); + regen += itembonuses.HeroicINT * RuleR(Character, HeroicIntelligenceMultiplier) / 25; else if(GetCasterClass() == 'W') - regen += (itembonuses.HeroicWIS / 25); + regen += itembonuses.HeroicWIS * RuleR(Character, HeroicWisdomMultiplier) / 25; else regen = 0; @@ -7160,7 +7161,7 @@ int64 Bot::CalcMaxHP() { int32 bot_hp = 0; uint32 nd = 10000; bot_hp += (GenerateBaseHitPoints() + itembonuses.HP); - bot_hp += (GetHeroicSTA() * 10); + bot_hp += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) * 10; nd += aabonuses.MaxHP; bot_hp = ((float)bot_hp * (float)nd / (float)10000); bot_hp += (spellbonuses.HP + aabonuses.HP); @@ -7200,35 +7201,42 @@ int64 Bot::CalcMaxEndurance() { int64 Bot::CalcBaseEndurance() { int32 base_end = 0; int32 base_endurance = 0; - int32 ConvertedStats = 0; + int32 converted_stats = 0; int32 sta_end = 0; - int Stats = 0; + int stats = 0; if (GetOwner() && GetOwner()->CastToClient() && GetOwner()->CastToClient()->ClientVersion() >= EQ::versions::ClientVersion::SoD && RuleB(Character, SoDClientUseSoDHPManaEnd)) { - int HeroicStats = 0; - Stats = ((GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4); - HeroicStats = ((GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4); - if (Stats > 100) { - ConvertedStats = (((Stats - 100) * 5 / 2) + 100); - if (Stats > 201) - ConvertedStats -= ((Stats - 201) * 5 / 4); - } else - ConvertedStats = Stats; + double heroic_stats = 0; + stats = ((GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4); + double heroic_str = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier); + double heroic_sta = GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier); + double heroic_dex = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier); + double heroic_agi = GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier); + heroic_stats = (heroic_str + heroic_sta + heroic_dex + heroic_agi) / 4; + + if (stats > 100) { + converted_stats = (((stats - 100) * 5 / 2) + 100); + if (stats > 201) { + converted_stats -= ((stats - 201) * 5 / 4); + } + } else { + converted_stats = stats; + } if (GetLevel() < 41) { - sta_end = (GetLevel() * 75 * ConvertedStats / 1000); + sta_end = (GetLevel() * 75 * converted_stats / 1000); base_endurance = (GetLevel() * 15); } else if (GetLevel() < 81) { - sta_end = ((3 * ConvertedStats) + ((GetLevel() - 40) * 15 * ConvertedStats / 100)); + sta_end = ((3 * converted_stats) + ((GetLevel() - 40) * 15 * converted_stats / 100)); base_endurance = (600 + ((GetLevel() - 40) * 30)); } else { - sta_end = (9 * ConvertedStats); + sta_end = (9 * converted_stats); base_endurance = (1800 + ((GetLevel() - 80) * 18)); } - base_end = (base_endurance + sta_end + (HeroicStats * 10)); + base_end = (base_endurance + sta_end + (heroic_stats * 10)); } else { - Stats = (GetSTR()+GetSTA()+GetDEX()+GetAGI()); - int LevelBase = (GetLevel() * 15); - int at_most_800 = Stats; + stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI()); + int level_base = (GetLevel() * 15); + int at_most_800 = stats; if(at_most_800 > 800) at_most_800 = 800; @@ -7237,16 +7245,16 @@ int64 Bot::CalcBaseEndurance() { int Bonus800plus = 0; int HalfBonus800plus = 0; int BonusUpto800 = int(at_most_800 / 4) ; - if(Stats > 400) { + if(stats > 400) { Bonus400to800 = int((at_most_800 - 400) / 4); HalfBonus400to800 = int(std::max((at_most_800 - 400), 0) / 8); - if(Stats > 800) { - Bonus800plus = (int((Stats - 800) / 8) * 2); - HalfBonus800plus = int((Stats - 800) / 16); + if(stats > 800) { + Bonus800plus = (int((stats - 800) / 8) * 2); + HalfBonus800plus = int((stats - 800) / 16); } } int bonus_sum = (BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus); - base_end = LevelBase; + base_end = level_base; base_end += ((bonus_sum * 3 * GetLevel()) / 40); } return base_end; diff --git a/zone/client.cpp b/zone/client.cpp index 6e40b33b5..10e6adf8b 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6381,7 +6381,7 @@ void Client::SendStatsWindow(Client* client, bool use_window) if(CalcMaxMana() > 0) { cur_name = " M: "; cur_field = itoa(GetMana()); - total_field = itoa(CalcMaxMana()); + total_field = itoa(GetMaxMana()); } else { continue; } @@ -6436,7 +6436,8 @@ void Client::SendStatsWindow(Client* client, bool use_window) regen_row_color = color_red; base_regen_field = itoa(LevelRegen()); - item_regen_field = itoa(itembonuses.HPRegen); + item_regen_field = itoa( + itembonuses.HPRegen +(GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 20)); cap_regen_field = itoa(CalcHPRegenCap()); spell_regen_field = itoa(spellbonuses.HPRegen); aa_regen_field = itoa(aabonuses.HPRegen); @@ -6444,12 +6445,15 @@ void Client::SendStatsWindow(Client* client, bool use_window) break; } case 1: { - if(CalcMaxMana() > 0) { + if(GetMaxMana() > 0) { regen_row_header = "M: "; regen_row_color = color_blue; base_regen_field = itoa(CalcBaseManaRegen()); - item_regen_field = itoa(itembonuses.ManaRegen); + int32 heroic_mana_regen = (GetCasterClass() == 'W') ? + GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier) / 25 : + GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier) / 25; + item_regen_field = itoa(itembonuses.ManaRegen + heroic_mana_regen); cap_regen_field = itoa(CalcManaRegenCap()); spell_regen_field = itoa(spellbonuses.ManaRegen); aa_regen_field = itoa(aabonuses.ManaRegen); @@ -6463,7 +6467,12 @@ void Client::SendStatsWindow(Client* client, bool use_window) regen_row_color = color_green; base_regen_field = itoa(((GetLevel() * 4 / 10) + 2)); - item_regen_field = itoa(itembonuses.EnduranceRegen); + double heroic_str = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier); + double heroic_sta = GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier); + double heroic_dex = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier); + double heroic_agi = GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier); + double heroic_stats = (heroic_str + heroic_sta + heroic_dex + heroic_agi) / 4; + item_regen_field = itoa(itembonuses.EnduranceRegen + heroic_stats); cap_regen_field = itoa(CalcEnduranceRegenCap()); spell_regen_field = itoa(spellbonuses.EnduranceRegen); aa_regen_field = itoa(aabonuses.EnduranceRegen); diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 1470052a9..054978986 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -234,7 +234,7 @@ int32 Client::LevelRegen() int64 Client::CalcHPRegen(bool bCombat) { int64 item_regen = itembonuses.HPRegen; // worn spells and +regen, already capped - item_regen += GetHeroicSTA() / 20; + item_regen += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) / 20; item_regen += aabonuses.HPRegen; @@ -491,7 +491,7 @@ int64 Client::CalcBaseHP() auto base_data = database.GetBaseData(GetLevel(), GetClass()); if (base_data) { base_hp += base_data->base_hp + (base_data->hp_factor * stats); - base_hp += (GetHeroicSTA() * 10); + base_hp += GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier) * 10; } } else { @@ -623,7 +623,9 @@ int64 Client::CalcBaseMana() } auto base_data = database.GetBaseData(GetLevel(), GetClass()); if (base_data) { - max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicINT() * 10); + max_m = base_data->base_mana + + (ConvertedWisInt * base_data->mana_factor) + + (GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier) * 10); } } else { @@ -655,7 +657,9 @@ int64 Client::CalcBaseMana() } auto base_data = database.GetBaseData(GetLevel(), GetClass()); if (base_data) { - max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicWIS() * 10); + max_m = base_data->base_mana + + (ConvertedWisInt * base_data->mana_factor) + + ((GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier)) * 10); } } else { @@ -752,10 +756,10 @@ int64 Client::CalcManaRegen(bool bCombat) switch (GetCasterClass()) { case 'W': - heroic_bonus = GetHeroicWIS(); + heroic_bonus = GetHeroicWIS() * RuleR(Character, HeroicWisdomMultiplier); break; default: - heroic_bonus = GetHeroicINT(); + heroic_bonus = GetHeroicINT() * RuleR(Character, HeroicIntelligenceMultiplier); break; } @@ -1686,8 +1690,13 @@ int64 Client::CalcBaseEndurance() { int64 base_end = 0; if (ClientVersion() >= EQ::versions::ClientVersion::SoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) { - double heroic_stats = (GetHeroicSTR() + GetHeroicSTA() + GetHeroicDEX() + GetHeroicAGI()) / 4.0f; + double heroic_str = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier); + double heroic_sta = GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier); + double heroic_dex = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier); + double heroic_agi = GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier); + double heroic_stats = (heroic_str + heroic_sta + heroic_dex + heroic_agi) / 4; double stats = (GetSTR() + GetSTA() + GetDEX() + GetAGI()) / 4.0f; + if (stats > 201.0f) { stats = 1.25f * (stats - 201.0f) + 352.5f; } @@ -1785,7 +1794,11 @@ int64 Client::CalcEnduranceRegen(bool bCombat) if (encumbered) base += level / -15; - auto item_bonus = GetHeroicAGI() + GetHeroicDEX() + GetHeroicSTA() + GetHeroicSTR(); + double heroic_str = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier); + double heroic_sta = GetHeroicSTA() * RuleR(Character, HeroicStaminaMultiplier); + double heroic_dex = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier); + double heroic_agi = GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier); + int32 item_bonus = heroic_str + heroic_sta + heroic_dex + heroic_agi; item_bonus = item_bonus / 4 / 50; item_bonus += itembonuses.EnduranceRegen; // this is capped already base += item_bonus; diff --git a/zone/tune.cpp b/zone/tune.cpp index 952b2c3b3..beb428f10 100644 --- a/zone/tune.cpp +++ b/zone/tune.cpp @@ -1049,7 +1049,7 @@ int64 Mob::TuneACSum(bool skip_caps, int ac_override, int add_ac) shield_ac = CalcRecommendedLevelBonus(GetLevel(), inst->GetItemRecommendedLevel(true),inst->GetItemArmorClass(true)); } } - shield_ac += GetHeroicSTR() / 10; + shield_ac += GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10; } // EQ math ac = (ac * 4) / 3; @@ -1353,7 +1353,7 @@ int64 Mob::Tunecompute_defense(int avoidance_override, int add_avoidance) defense = avoidance_override; } else { - defense += GetHeroicAGI() / 10; + defense += GetHeroicAGI() * RuleR(Character, HeroicAgilityMultiplier) / 10; } defense += add_avoidance; //1 pt = 10 heroic agi } @@ -1493,13 +1493,13 @@ void Mob::TuneCommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraA if (IsOfClientBot()) { int extra = 0; switch (hit.skill) { - case EQ::skills::SkillThrowing: - case EQ::skills::SkillArchery: - extra = GetHeroicDEX() / 10; - break; - default: - extra = GetHeroicSTR() / 10; - break; + case EQ::skills::SkillThrowing: + case EQ::skills::SkillArchery: + extra = GetHeroicDEX() * RuleR(Character, HeroicDexterityMultiplier) / 10; + break; + default: + extra = GetHeroicSTR() * RuleR(Character, HeroicStrengthMultiplier) / 10; + break; } hit.damage_done += extra; }