diff --git a/common/ruletypes.h b/common/ruletypes.h index 5fc08a149..45cd1a9ee 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -211,6 +211,7 @@ RULE_BOOL(Character, IgnoreLevelBasedHasteCaps, false, "Ignores hard coded level RULE_BOOL(Character, EnableRaidEXPModifier, true, "Enable or disable the raid experience modifier, default is true") RULE_BOOL(Character, EnableRaidMemberEXPModifier, true, "Enable or disable the raid experience modifier based on members in raid, default is true") RULE_BOOL(Character, LeaveCursorMoneyOnCorpse, false, "Enable or disable leaving cursor money on player corpses") +RULE_BOOL(Character, ItemExtraSkillDamageCalcAsPercent, false, "If enabled, apply Item Extra Skill Damage as Percentage-based modifiers") RULE_CATEGORY_END() RULE_CATEGORY(Mercs) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 004a4f5ab..9ee25918e 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -520,12 +520,15 @@ void Client::AddItemBonuses(const EQ::ItemInstance *inst, StatBonuses *newbon, b } } - if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) { - if ((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > - RuleI(Character, ItemExtraDmgCap)) + if (item->ExtraDmgAmt != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) { + if ( + RuleI(Character, ItemExtraDmgCap) >= 0 && + (newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap) + ) { newbon->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap); - else + } else { newbon->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt; + } } } diff --git a/zone/bot.cpp b/zone/bot.cpp index dc63a0028..0744ce94e 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -7339,11 +7339,15 @@ void Bot::AddItemBonuses(const EQ::ItemInstance *inst, StatBonuses* newbon, bool } } - if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) { - if ((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)) + if (item->ExtraDmgAmt != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) { + if ( + RuleI(Character, ItemExtraDmgCap) >= 0 && + (newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap) + ) { newbon->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap); - else + } else { newbon->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt; + } } if (!isAug) diff --git a/zone/merc.cpp b/zone/merc.cpp index 028416596..558c2fc7b 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -563,11 +563,15 @@ void Merc::AddItemBonuses(const EQ::ItemData *item, StatBonuses* newbon) { } } - if (item->ExtraDmgSkill != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) { - if((newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap)) + if (item->ExtraDmgAmt != 0 && item->ExtraDmgSkill <= EQ::skills::HIGHEST_SKILL) { + if ( + RuleI(Character, ItemExtraDmgCap) >= 0 && + (newbon->SkillDamageAmount[item->ExtraDmgSkill] + item->ExtraDmgAmt) > RuleI(Character, ItemExtraDmgCap) + ) { newbon->SkillDamageAmount[item->ExtraDmgSkill] = RuleI(Character, ItemExtraDmgCap); - else + } else { newbon->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt; + } } } diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index b71166176..1243d0eb6 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -34,110 +34,169 @@ int Mob::GetBaseSkillDamage(EQ::skills::SkillType skill, Mob *target) int base = EQ::skills::GetBaseDamage(skill); auto skill_level = GetSkill(skill); switch (skill) { - case EQ::skills::SkillDragonPunch: - case EQ::skills::SkillEagleStrike: - case EQ::skills::SkillTigerClaw: - case EQ::skills::SkillRoundKick: - if (skill_level >= 25) - base++; - if (skill_level >= 75) - base++; - if (skill_level >= 125) - base++; - if (skill_level >= 175) - base++; - return base; - case EQ::skills::SkillFrenzy: - if (IsClient() && CastToClient()->GetInv().GetItem(EQ::invslot::slotPrimary)) { - if (GetLevel() > 15) - base += GetLevel() - 15; - if (base > 23) - base = 23; - if (GetLevel() > 50) - base += 2; - if (GetLevel() > 54) + case EQ::skills::SkillDragonPunch: + case EQ::skills::SkillEagleStrike: + case EQ::skills::SkillTigerClaw: + case EQ::skills::SkillRoundKick: + if (skill_level >= 25) { base++; - if (GetLevel() > 59) + } + + if (skill_level >= 75) { base++; - } - return base; - case EQ::skills::SkillFlyingKick: { - float skill_bonus = skill_level / 9.0f; - float ac_bonus = 0.0f; - if (IsClient()) { - auto inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotFeet); - if (inst) - ac_bonus = inst->GetItemArmorClass(true) / 25.0f; - } - if (ac_bonus > skill_bonus) - ac_bonus = skill_bonus; - return static_cast(ac_bonus + skill_bonus); - } - case EQ::skills::SkillKick: { - // there is some base *= 4 case in here? - float skill_bonus = skill_level / 10.0f; - float ac_bonus = 0.0f; - if (IsClient()) { - auto inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotFeet); - if (inst) - ac_bonus = inst->GetItemArmorClass(true) / 25.0f; - } - if (ac_bonus > skill_bonus) - ac_bonus = skill_bonus; - return static_cast(ac_bonus + skill_bonus); - } - case EQ::skills::SkillBash: { - float skill_bonus = skill_level / 10.0f; - float ac_bonus = 0.0f; - const EQ::ItemInstance *inst = nullptr; - if (IsClient()) { - if (HasShieldEquiped()) - inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotSecondary); - else if (HasTwoHanderEquipped()) - inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotPrimary); - } - if (inst) - ac_bonus = inst->GetItemArmorClass(true) / 25.0f; - else - return 0; // return 0 in cases where we don't have an item - if (ac_bonus > skill_bonus) - ac_bonus = skill_bonus; - return static_cast(ac_bonus + skill_bonus); - } - case EQ::skills::SkillBackstab: { - float skill_bonus = static_cast(skill_level) * 0.02f; - base = 3; // There seems to be a base 3 for NPCs or some how BS w/o weapon? - // until we get a better inv system for NPCs they get nerfed! - if (IsClient()) { - auto *inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotPrimary); - if (inst && inst->GetItem() && inst->GetItem()->ItemType == EQ::item::ItemType1HPiercing) { - base = inst->GetItemBackstabDamage(true); - if (!inst->GetItemBackstabDamage()) { - base += inst->GetItemWeaponDamage(true); + } + + if (skill_level >= 125) { + base++; + } + + if (skill_level >= 175) { + base++; + } + + if (RuleB(Character, ItemExtraSkillDamageCalcAsPercent) && GetSkillDmgAmt(skill) > 0) { + base *= std::abs(GetSkillDmgAmt(skill) / 100); + } + + return base; + case EQ::skills::SkillFrenzy: + if (IsClient() && CastToClient()->GetInv().GetItem(EQ::invslot::slotPrimary)) { + if (GetLevel() > 15) { + base += GetLevel() - 15; } - if (target) { - if (inst->GetItemElementalFlag(true) && inst->GetItemElementalDamage(true) && !RuleB(Combat, BackstabIgnoresElemental)) { - base += target->ResistElementalWeaponDmg(inst); - } + if (base > 23) { + base = 23; + } - if ((inst->GetItemBaneDamageBody(true) || inst->GetItemBaneDamageRace(true)) && !RuleB(Combat, BackstabIgnoresBane)) { - base += target->CheckBaneDamage(inst); - } + if (GetLevel() > 50) { + base += 2; + } + + if (GetLevel() > 54) { + base++; + } + + if (GetLevel() > 59) { + base++; } } - } else if (IsNPC()) { - auto *npc = CastToNPC(); - base = std::max(base, npc->GetBaseDamage()); - // parses show relatively low BS mods from lots of NPCs, so either their BS skill is super low - // or their mod is divided again, this is probably not the right mod, but it's better - skill_bonus /= 3.0f; + + if (RuleB(Character, ItemExtraSkillDamageCalcAsPercent) && GetSkillDmgAmt(skill) > 0) { + base *= std::abs(GetSkillDmgAmt(skill) / 100); + } + + return base; + case EQ::skills::SkillFlyingKick: { + float skill_bonus = skill_level / 9.0f; + float ac_bonus = 0.0f; + if (IsClient()) { + auto inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotFeet); + if (inst) { + ac_bonus = inst->GetItemArmorClass(true) / 25.0f; + } + } + + if (ac_bonus > skill_bonus) { + ac_bonus = skill_bonus; + } + + if (RuleB(Character, ItemExtraSkillDamageCalcAsPercent) && GetSkillDmgAmt(skill) > 0) { + return static_cast(ac_bonus + skill_bonus) * std::abs(GetSkillDmgAmt(skill) / 100); + } + + return static_cast(ac_bonus + skill_bonus); + } + case EQ::skills::SkillKick: { + // there is some base *= 4 case in here? + float skill_bonus = skill_level / 10.0f; + float ac_bonus = 0.0f; + if (IsClient()) { + auto inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotFeet); + if (inst) { + ac_bonus = inst->GetItemArmorClass(true) / 25.0f; + } + } + + if (ac_bonus > skill_bonus) { + ac_bonus = skill_bonus; + } + + if (RuleB(Character, ItemExtraSkillDamageCalcAsPercent) && GetSkillDmgAmt(skill) > 0) { + return static_cast(ac_bonus + skill_bonus) * std::abs(GetSkillDmgAmt(skill) / 100); + } + + return static_cast(ac_bonus + skill_bonus); + } + case EQ::skills::SkillBash: { + float skill_bonus = skill_level / 10.0f; + float ac_bonus = 0.0f; + const EQ::ItemInstance *inst = nullptr; + if (IsClient()) { + if (HasShieldEquiped()) { + inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotSecondary); + } else if (HasTwoHanderEquipped()) { + inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotPrimary); + } + } + + if (inst) { + ac_bonus = inst->GetItemArmorClass(true) / 25.0f; + } else { + return 0; + } // return 0 in cases where we don't have an item + + if (ac_bonus > skill_bonus) { + ac_bonus = skill_bonus; + } + + if (RuleB(Character, ItemExtraSkillDamageCalcAsPercent) && GetSkillDmgAmt(skill) > 0) { + return static_cast(ac_bonus + skill_bonus) * std::abs(GetSkillDmgAmt(skill) / 100); + } + + return static_cast(ac_bonus + skill_bonus); + } + case EQ::skills::SkillBackstab: { + float skill_bonus = static_cast(skill_level) * 0.02f; + base = 3; // There seems to be a base 3 for NPCs or some how BS w/o weapon? + // until we get a better inv system for NPCs they get nerfed! + if (IsClient()) { + auto *inst = CastToClient()->GetInv().GetItem(EQ::invslot::slotPrimary); + if (inst && inst->GetItem() && inst->GetItem()->ItemType == EQ::item::ItemType1HPiercing) { + base = inst->GetItemBackstabDamage(true); + if (!inst->GetItemBackstabDamage()) { + base += inst->GetItemWeaponDamage(true); + } + + if (target) { + if (inst->GetItemElementalFlag(true) && inst->GetItemElementalDamage(true) && + !RuleB(Combat, BackstabIgnoresElemental)) { + base += target->ResistElementalWeaponDmg(inst); + } + + if ((inst->GetItemBaneDamageBody(true) || inst->GetItemBaneDamageRace(true)) && + !RuleB(Combat, BackstabIgnoresBane)) { + base += target->CheckBaneDamage(inst); + } + } + } + } else if (IsNPC()) { + auto *npc = CastToNPC(); + base = std::max(base, npc->GetBaseDamage()); + // parses show relatively low BS mods from lots of NPCs, so either their BS skill is super low + // or their mod is divided again, this is probably not the right mod, but it's better + skill_bonus /= 3.0f; + } + + if (RuleB(Character, ItemExtraSkillDamageCalcAsPercent) && GetSkillDmgAmt(skill) > 0) { + return static_cast(static_cast(base) * (skill_bonus + 2.0f)) * std::abs(GetSkillDmgAmt(skill) / 100); + } + + return static_cast(static_cast(base) * (skill_bonus + 2.0f)); + } + default: { + return 0; } - // ahh lets make sure everything is casted right :P ugly but w/e - return static_cast(static_cast(base) * (skill_bonus + 2.0f)); - } - default: - return 0; } }