mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 23:01:30 +00:00
[Bug Fix] Slay Adjustments (#4389)
Previous change did not account for the modern slay undead and holyforge spells. Reverted some of the changes and cleaned up others. Rule Renamed (Default value was incorrect, this was a clean way to fix that) - SlayDamageAdjustment -> SlayDamageMultiplier Also added a rate multiplier RULE_REAL(Combat, SlayRateMultiplier, 1.0, "Slay Rate Adjustments - Multiply final slay rate check by this value. Default: 1.0") Fixed the ordering of the constants for the slay undead SPA that were backwards and causing major headaches with tuning and setting up slay undead correctly. Base = Damage Mod (100 is base, so 240 = 140% more) Limit = Proc Rate - Value is divided by 10000 for a Float %. e.g. 1700 becomes 0.17 (Or 17% proc rate). Damage bonus should be additive not std::max as AA, Spells and Item bonuses should stack. e.g. Slay Undead RK3 240 + Holy Forge 140 should = 380 (280% damage)
This commit is contained in:
parent
a85f4fb703
commit
95cbadade5
@ -619,7 +619,8 @@ RULE_INT(Combat, PCAccuracyAvoidanceMod2Scale, 100, "Scale Factor for PC Accurac
|
|||||||
RULE_BOOL(Combat, AllowRaidTargetBlind, false, "Toggle to allow raid targets to be blinded, default is false (Live-like)")
|
RULE_BOOL(Combat, AllowRaidTargetBlind, false, "Toggle to allow raid targets to be blinded, default is false (Live-like)")
|
||||||
RULE_BOOL(Combat, RogueBackstabHasteCorrection, false, "Toggle to enable correction for Haste impacting Backstab DPS too much. DEFAULT: false")
|
RULE_BOOL(Combat, RogueBackstabHasteCorrection, false, "Toggle to enable correction for Haste impacting Backstab DPS too much. DEFAULT: false")
|
||||||
RULE_BOOL(Combat, LegacyComputeDefense, false, "Trim AGI Scaling of defense mostly for lower levels to help compensate for the newer agi based defense system. Default: False")
|
RULE_BOOL(Combat, LegacyComputeDefense, false, "Trim AGI Scaling of defense mostly for lower levels to help compensate for the newer agi based defense system. Default: False")
|
||||||
RULE_REAL(Combat, SlayDamageAdjustment, 0.5, "Slay Damage Adjustment - Multiply final slay damage by this value. Default: 0.5")
|
RULE_REAL(Combat, SlayDamageMultiplier, 1.0, "Slay Damage Adjustment - Multiply final slay damage by this value. Default: 1.0")
|
||||||
|
RULE_REAL(Combat, SlayRateMultiplier, 1.0, "Slay Rate Adjustments - Multiply final slay rate check by this value. Default: 1.0")
|
||||||
RULE_INT(Combat, MaximumLevelStunsCripplingBlow, 55, "Maximum level that Crippling Blows will stun a npc. Default: 55")
|
RULE_INT(Combat, MaximumLevelStunsCripplingBlow, 55, "Maximum level that Crippling Blows will stun a npc. Default: 55")
|
||||||
RULE_INT(Combat, ArcheryBaseDamage, 0, "Archery base damage, default is 0")
|
RULE_INT(Combat, ArcheryBaseDamage, 0, "Archery base damage, default is 0")
|
||||||
RULE_INT(Combat, BackstabBaseDamage, 0, "Backstab base damage, default is 0")
|
RULE_INT(Combat, BackstabBaseDamage, 0, "Backstab base damage, default is 0")
|
||||||
|
|||||||
251
zone/attack.cpp
251
zone/attack.cpp
@ -5388,101 +5388,6 @@ void Mob::TryPetCriticalHit(Mob *defender, DamageHitInfo &hit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::RollMeleeCritCheck(Mob *defender, EQ::skills::SkillType skill)
|
|
||||||
{
|
|
||||||
// We either require an innate crit chance or some SPA 169 to crit
|
|
||||||
bool innate_crit = false;
|
|
||||||
int crit_chance = GetCriticalChanceBonus(skill);
|
|
||||||
// Paladin check
|
|
||||||
if (defender->IsUndeadForSlay()) {
|
|
||||||
crit_chance = crit_chance + GetUndeadSlayRate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetLevel() >= 12) {
|
|
||||||
if (
|
|
||||||
GetClass() == Class::Warrior ||
|
|
||||||
(GetClass() == Class::Ranger && skill == EQ::skills::SkillArchery) ||
|
|
||||||
(GetClass() == Class::Rogue && skill == EQ::skills::SkillThrowing) ||
|
|
||||||
GetClass() == Class::Berserker
|
|
||||||
) {
|
|
||||||
innate_crit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we have a chance to crit!
|
|
||||||
if (innate_crit || crit_chance) {
|
|
||||||
int difficulty = 0;
|
|
||||||
|
|
||||||
if (skill == EQ::skills::SkillArchery) {
|
|
||||||
difficulty = RuleI(Combat, ArcheryCritDifficulty);
|
|
||||||
} else if (skill == EQ::skills::SkillThrowing) {
|
|
||||||
difficulty = RuleI(Combat, ThrowingCritDifficulty);
|
|
||||||
} else {
|
|
||||||
difficulty = RuleI(Combat, MeleeCritDifficulty);
|
|
||||||
}
|
|
||||||
|
|
||||||
int roll = zone->random.Int(1, difficulty);
|
|
||||||
|
|
||||||
int dex_bonus = GetDEX();
|
|
||||||
|
|
||||||
if (dex_bonus > 255) {
|
|
||||||
dex_bonus = 255 + ((dex_bonus - 255) / 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
dex_bonus += 45; // chances did not match live without a small boost
|
|
||||||
|
|
||||||
// so if we have an innate crit we have a better chance, except for ber throwing
|
|
||||||
if (!innate_crit || (GetClass() == Class::Berserker && skill == EQ::skills::SkillThrowing)) {
|
|
||||||
dex_bonus = dex_bonus * 3 / 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogCombat("Crit Chance: dex_bonus ({}) * crit_chance ({}) / 100", dex_bonus, crit_chance);
|
|
||||||
|
|
||||||
if (crit_chance) {
|
|
||||||
dex_bonus += dex_bonus * crit_chance / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we crited
|
|
||||||
LogCombat("Final Roll! Difficulty = [{}] -- Dex_Bonus = [{}] ", difficulty, dex_bonus);
|
|
||||||
return (roll < dex_bonus);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Mob::GetUndeadSlayRate()
|
|
||||||
{
|
|
||||||
return aabonuses.SlayUndead[0] + itembonuses.SlayUndead[0] + spellbonuses.SlayUndead[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mob::DoUndeadSlay(DamageHitInfo &hit, int crit_mod)
|
|
||||||
{
|
|
||||||
|
|
||||||
int slay_damage_bonus = std::max(
|
|
||||||
{ aabonuses.SlayUndead[1], itembonuses.SlayUndead[1], spellbonuses.SlayUndead[1] });
|
|
||||||
|
|
||||||
LogCombatDetail("Slayundead bonus [{}]", slay_damage_bonus);
|
|
||||||
|
|
||||||
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
|
||||||
hit.damage_done = (hit.damage_done * slay_damage_bonus * crit_mod) / 100;
|
|
||||||
hit.damage_done = static_cast<int>(hit.damage_done * RuleR(Combat, SlayDamageAdjustment));
|
|
||||||
|
|
||||||
LogCombatDetail("Slayundead damage [{}]", hit.damage_done);
|
|
||||||
|
|
||||||
int slay_sex = GetGender() == Gender::Female ? FEMALE_SLAYUNDEAD : MALE_SLAYUNDEAD;
|
|
||||||
|
|
||||||
entity_list.FilteredMessageString(
|
|
||||||
this, /* Sender */
|
|
||||||
false, /* Skip Sender */
|
|
||||||
Chat::MeleeCrit, /* Type: 301 */
|
|
||||||
FilterMeleeCrits, /* FilterType: 12 */
|
|
||||||
slay_sex, /* MessageFormat: %1's holy blade cleanses her target!(%2) */
|
|
||||||
GetCleanName(), /* Message1 */
|
|
||||||
itoa(hit.damage_done) /* Message2 */
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// a lot of good info: http://giline.versus.jp/shiden/damage_e.htm, http://giline.versus.jp/shiden/su.htm
|
|
||||||
void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts)
|
||||||
{
|
{
|
||||||
#ifdef LUA_EQEMU
|
#ifdef LUA_EQEMU
|
||||||
@ -5494,8 +5399,9 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (hit.damage_done < 1 || !defender)
|
if (hit.damage_done < 1 || !defender) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// decided to branch this into it's own function since it's going to be duplicating a lot of the
|
// decided to branch this into it's own function since it's going to be duplicating a lot of the
|
||||||
// code in here, but could lead to some confusion otherwise
|
// code in here, but could lead to some confusion otherwise
|
||||||
@ -5513,43 +5419,127 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1: Check if we are critting
|
// 1: Try Slay Undead
|
||||||
if (!RollMeleeCritCheck(defender, hit.skill)) {
|
if (defender->GetBodyType() == BodyType::Undead || defender->GetBodyType() == BodyType::SummonedUndead ||
|
||||||
|
defender->GetBodyType() == BodyType::Vampire) {
|
||||||
|
int slay_rate_bonus = aabonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] + itembonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] + spellbonuses.SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD];
|
||||||
|
|
||||||
|
LogCombatDetail("Slayundead hit rate [{}]", slay_rate_bonus);
|
||||||
|
|
||||||
|
if (slay_rate_bonus) {
|
||||||
|
float slay_chance = ((static_cast<float>(slay_rate_bonus) / 10000.0f) * RuleR(Combat, SlayRateMultiplier));
|
||||||
|
|
||||||
|
if (zone->random.Roll(slay_chance)) {
|
||||||
|
int slay_damage_bonus = aabonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] + itembonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] + spellbonuses.SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD];
|
||||||
|
|
||||||
|
LogCombatDetail("Slayundead damage bonus [{}]", slay_damage_bonus);
|
||||||
|
|
||||||
|
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
||||||
|
hit.damage_done = (hit.damage_done * slay_damage_bonus) / 100;
|
||||||
|
hit.damage_done = static_cast<int>(hit.damage_done * RuleR(Combat, SlayDamageMultiplier));
|
||||||
|
|
||||||
|
int min_slay = (hit.min_damage + 5) * slay_damage_bonus / 100;
|
||||||
|
|
||||||
|
LogCombatDetail(" Calculated Slayundead damage [{}] - Min Slay Undead Damage [{}]", hit.damage_done, min_slay);
|
||||||
|
|
||||||
|
if (hit.damage_done < min_slay) {
|
||||||
|
hit.damage_done = min_slay;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogCombatDetail("Final Slayundead damage [{}]", hit.damage_done);
|
||||||
|
|
||||||
|
int slay_sex = GetGender() == Gender::Female ? FEMALE_SLAYUNDEAD : MALE_SLAYUNDEAD;
|
||||||
|
|
||||||
|
entity_list.FilteredMessageCloseString(
|
||||||
|
this, /* Sender */
|
||||||
|
false, /* Skip Sender */
|
||||||
|
RuleI(Range, CriticalDamage),
|
||||||
|
Chat::MeleeCrit, /* Type: 301 */
|
||||||
|
FilterMeleeCrits, /* FilterType: 12 */
|
||||||
|
slay_sex,
|
||||||
|
0,
|
||||||
|
GetCleanName(), /* Message1 */
|
||||||
|
itoa(hit.damage_done) /* Message2 */
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2: Try Melee Critical
|
||||||
|
// a lot of good info: http://giline.versus.jp/shiden/damage_e.htm, http://giline.versus.jp/shiden/su.htm
|
||||||
|
|
||||||
|
// We either require an innate crit chance or some SPA 169 to crit
|
||||||
|
bool innate_crit = false;
|
||||||
|
int crit_chance = GetCriticalChanceBonus(hit.skill);
|
||||||
|
if ((GetClass() == Class::Warrior || GetClass() == Class::Berserker) && GetLevel() >= 12) {
|
||||||
|
innate_crit = true;
|
||||||
|
} else if (GetClass() == Class::Ranger && GetLevel() >= 12 && hit.skill == EQ::skills::SkillArchery) {
|
||||||
|
innate_crit = true;
|
||||||
|
} else if (GetClass() == Class::Rogue && GetLevel() >= 12 && hit.skill == EQ::skills::SkillThrowing) {
|
||||||
|
innate_crit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have a chance to crit!
|
||||||
|
if (innate_crit || crit_chance) {
|
||||||
|
int difficulty = 0;
|
||||||
|
|
||||||
|
if (hit.skill == EQ::skills::SkillArchery) {
|
||||||
|
difficulty = RuleI(Combat, ArcheryCritDifficulty);
|
||||||
|
} else if (hit.skill == EQ::skills::SkillThrowing) {
|
||||||
|
difficulty = RuleI(Combat, ThrowingCritDifficulty);
|
||||||
|
} else {
|
||||||
|
difficulty = RuleI(Combat, MeleeCritDifficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
int roll = zone->random.Int(1, difficulty);
|
||||||
|
int dex_bonus = GetDEX();
|
||||||
|
|
||||||
|
if (dex_bonus > 255) {
|
||||||
|
dex_bonus = 255 + ((dex_bonus - 255) / 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
dex_bonus += 45; // chances did not match live without a small boost
|
||||||
|
|
||||||
|
// so if we have an innate crit we have a better chance, except for ber throwing
|
||||||
|
if (!innate_crit || (GetClass() == Class::Berserker && hit.skill == EQ::skills::SkillThrowing)) {
|
||||||
|
dex_bonus = dex_bonus * 3 / 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crit_chance) {
|
||||||
|
dex_bonus += dex_bonus * crit_chance / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we crited
|
||||||
|
if (roll < dex_bonus) {
|
||||||
|
// step 1: check for finishing blow
|
||||||
|
if (TryFinishingBlow(defender, hit.damage_done)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int crit_mod = EQ::ClampLower((170 + GetCritDmgMod(hit.skill)), 100);
|
// step 2: calculate damage
|
||||||
|
|
||||||
// Step 2: Calculate damage
|
|
||||||
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
|
||||||
int og_damage = hit.damage_done;
|
int og_damage = hit.damage_done;
|
||||||
|
int crit_mod = 170 + GetCritDmgMod(hit.skill);
|
||||||
|
|
||||||
|
if (crit_mod < 100) {
|
||||||
|
crit_mod = 100;
|
||||||
|
}
|
||||||
|
|
||||||
hit.damage_done = hit.damage_done * crit_mod / 100;
|
hit.damage_done = hit.damage_done * crit_mod / 100;
|
||||||
|
LogCombatDetail("Crit success roll [{}] dex chance [{}] og dmg [{}] crit_mod [{}] new dmg [{}]", roll, dex_bonus, og_damage, crit_mod, hit.damage_done);
|
||||||
|
|
||||||
LogCombatDetail("Crit info: [{}] scaled from: [{}] - IsUndeadForSlay: [{}]", hit.damage_done, og_damage, IsUndeadForSlay() ? "true" : "false");
|
// step 3: check deadly strike
|
||||||
|
if (GetClass() == Class::Rogue && hit.skill == EQ::skills::SkillThrowing) {
|
||||||
// Try Slay Undead
|
if (BehindMob(defender, GetX(), GetY())) {
|
||||||
if (defender->IsUndeadForSlay()) {
|
|
||||||
float chance = GetUndeadSlayRate() / 100.0f;
|
|
||||||
LogCombatDetail("Trying Undead slay: Chance: [{}]", chance);
|
|
||||||
|
|
||||||
if(zone->random.Roll(chance)) {
|
|
||||||
DoUndeadSlay(hit, crit_mod);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 3: Check deadly strike
|
|
||||||
if (GetClass() == Class::Rogue && hit.skill == EQ::skills::SkillThrowing && BehindMob(defender, GetX(), GetY())) {
|
|
||||||
int chance = GetLevel() * 12;
|
int chance = GetLevel() * 12;
|
||||||
if (zone->random.Int(1, 1000) < chance) {
|
if (zone->random.Int(1, 1000) < chance) {
|
||||||
// Check assassinate
|
// step 3a: check assassinate
|
||||||
int assassinate_damage = TryAssassinate(defender, hit.skill);
|
int assassinate_damage = TryAssassinate(defender, hit.skill); // I don't think this is right
|
||||||
|
|
||||||
if (assassinate_damage) {
|
if (assassinate_damage) {
|
||||||
hit.damage_done = assassinate_damage;
|
hit.damage_done = assassinate_damage;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hit.damage_done = hit.damage_done * 200 / 100;
|
hit.damage_done = hit.damage_done * 200 / 100;
|
||||||
|
|
||||||
entity_list.FilteredMessageCloseString(
|
entity_list.FilteredMessageCloseString(
|
||||||
@ -5561,22 +5551,25 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
|||||||
DEADLY_STRIKE, /* MessageFormat: %1 scores a Deadly Strike!(%2) */
|
DEADLY_STRIKE, /* MessageFormat: %1 scores a Deadly Strike!(%2) */
|
||||||
0,
|
0,
|
||||||
GetCleanName(), /* Message1 */
|
GetCleanName(), /* Message1 */
|
||||||
itoa(hit.damage_done) /* Message2 */
|
itoa(hit.damage_done + hit.min_damage) /* Message2 */
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Step 4: check cripple
|
// step 4: check crips
|
||||||
|
// this SPA was reused on live ...
|
||||||
bool berserk = spellbonuses.BerserkSPA || itembonuses.BerserkSPA || aabonuses.BerserkSPA;
|
bool berserk = spellbonuses.BerserkSPA || itembonuses.BerserkSPA || aabonuses.BerserkSPA;
|
||||||
|
if (!berserk) {
|
||||||
if (!berserk && zone->random.Roll(GetCrippBlowChance())) {
|
if (zone->random.Roll(GetCrippBlowChance())) {
|
||||||
berserk = true;
|
berserk = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (IsBerserk() || berserk) {
|
if (IsBerserk() || berserk) {
|
||||||
hit.damage_done += og_damage * 119 / 100;
|
hit.damage_done += og_damage * 119 / 100;
|
||||||
LogCombatDetail("Crippling damage [{}]", hit.damage_done);
|
LogCombat("Crip damage [{}]", hit.damage_done);
|
||||||
|
|
||||||
entity_list.FilteredMessageCloseString(
|
entity_list.FilteredMessageCloseString(
|
||||||
this, /* Sender */
|
this, /* Sender */
|
||||||
@ -5587,13 +5580,13 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
|||||||
CRIPPLING_BLOW, /* MessageFormat: %1 lands a Crippling Blow!(%2) */
|
CRIPPLING_BLOW, /* MessageFormat: %1 lands a Crippling Blow!(%2) */
|
||||||
0,
|
0,
|
||||||
GetCleanName(), /* Message1 */
|
GetCleanName(), /* Message1 */
|
||||||
itoa(hit.damage_done) /* Message2 */
|
itoa(hit.damage_done + hit.min_damage) /* Message2 */
|
||||||
);
|
);
|
||||||
|
|
||||||
// Crippling blows also have a chance to stun
|
// Crippling blows also have a chance to stun
|
||||||
// Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a
|
// Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a
|
||||||
// staggers message.
|
// staggers message.
|
||||||
if (defender->GetLevel() <= RuleI(Combat, MaximumLevelStunsCripplingBlow) && !defender->GetSpecialAbility(SpecialAbility::StunImmunity)) {
|
if (defender->GetLevel() <= 55 && !defender->GetSpecialAbility(SpecialAbility::StunImmunity)) {
|
||||||
entity_list.MessageCloseString(
|
entity_list.MessageCloseString(
|
||||||
defender,
|
defender,
|
||||||
true,
|
true,
|
||||||
@ -5617,9 +5610,11 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
|
|||||||
CRITICAL_HIT, /* MessageFormat: %1 scores a critical hit! (%2) */
|
CRITICAL_HIT, /* MessageFormat: %1 scores a critical hit! (%2) */
|
||||||
0,
|
0,
|
||||||
GetCleanName(), /* Message1 */
|
GetCleanName(), /* Message1 */
|
||||||
itoa(hit.damage_done) /* Message2 */
|
itoa(hit.damage_done + hit.min_damage) /* Message2 */
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Mob::TryFinishingBlow(Mob *defender, int64 &damage)
|
bool Mob::TryFinishingBlow(Mob *defender, int64 &damage)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1439,8 +1439,8 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
|
|
||||||
case SE_SlayUndead: {
|
case SE_SlayUndead: {
|
||||||
if (newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] < base_value) {
|
if (newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] < base_value) {
|
||||||
newbon->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = base_value; // Rate
|
newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = base_value; // Rate
|
||||||
newbon->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = limit_value; // Damage Modifier
|
newbon->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = limit_value; // Damage Modifier
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3589,8 +3589,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
|||||||
|
|
||||||
case SE_SlayUndead: {
|
case SE_SlayUndead: {
|
||||||
if (new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] < effect_value) {
|
if (new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] < effect_value) {
|
||||||
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = effect_value; // Rate
|
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_RATE_MOD] = limit_value; // Rate
|
||||||
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = limit_value; // Damage Modifier
|
new_bonus->SlayUndead[SBIndex::SLAYUNDEAD_DMG_MOD] = effect_value; // Damage Modifier
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -633,8 +633,8 @@ namespace SBIndex {
|
|||||||
constexpr uint16 SKILLATK_PROC_SPELL_ID = 0; // SPA 288
|
constexpr uint16 SKILLATK_PROC_SPELL_ID = 0; // SPA 288
|
||||||
constexpr uint16 SKILLATK_PROC_CHANCE = 1; // SPA 288
|
constexpr uint16 SKILLATK_PROC_CHANCE = 1; // SPA 288
|
||||||
constexpr uint16 SKILLATK_PROC_SKILL = 2; // SPA 288
|
constexpr uint16 SKILLATK_PROC_SKILL = 2; // SPA 288
|
||||||
constexpr uint16 SLAYUNDEAD_RATE_MOD = 0; // SPA 219
|
constexpr uint16 SLAYUNDEAD_DMG_MOD = 0; // SPA 219
|
||||||
constexpr uint16 SLAYUNDEAD_DMG_MOD = 1; // SPA 219
|
constexpr uint16 SLAYUNDEAD_RATE_MOD = 1; // SPA 219
|
||||||
constexpr uint16 DOUBLE_RIPOSTE_CHANCE = 0; // SPA 223
|
constexpr uint16 DOUBLE_RIPOSTE_CHANCE = 0; // SPA 223
|
||||||
constexpr uint16 DOUBLE_RIPOSTE_SKILL_ATK_CHANCE = 1; // SPA 223
|
constexpr uint16 DOUBLE_RIPOSTE_SKILL_ATK_CHANCE = 1; // SPA 223
|
||||||
constexpr uint16 DOUBLE_RIPOSTE_SKILL = 2; // SPA 223
|
constexpr uint16 DOUBLE_RIPOSTE_SKILL = 2; // SPA 223
|
||||||
|
|||||||
@ -234,13 +234,7 @@ public:
|
|||||||
int compute_defense();
|
int compute_defense();
|
||||||
int GetTotalDefense(); // compute_defense + spell bonuses
|
int GetTotalDefense(); // compute_defense + spell bonuses
|
||||||
bool CheckHitChance(Mob* attacker, DamageHitInfo &hit);
|
bool CheckHitChance(Mob* attacker, DamageHitInfo &hit);
|
||||||
bool RollMeleeCritCheck(Mob *defender, EQ::skills::SkillType skill);
|
|
||||||
inline bool CanUndeadSlay() { return static_cast<bool>(GetUndeadSlayRate());}
|
|
||||||
inline bool IsUndeadForSlay() { return (GetBodyType() == BodyType::Undead || GetBodyType() == BodyType::SummonedUndead || GetBodyType() == BodyType::Vampire); }
|
|
||||||
int GetUndeadSlayRate();
|
|
||||||
void DoUndeadSlay(DamageHitInfo &hit, int crit_mod);
|
|
||||||
void TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
void TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
||||||
bool TryUndeadSlay(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
|
||||||
void TryPetCriticalHit(Mob *defender, DamageHitInfo &hit);
|
void TryPetCriticalHit(Mob *defender, DamageHitInfo &hit);
|
||||||
virtual bool TryFinishingBlow(Mob *defender, int64 &damage);
|
virtual bool TryFinishingBlow(Mob *defender, int64 &damage);
|
||||||
int TryHeadShot(Mob* defender, EQ::skills::SkillType skillInUse);
|
int TryHeadShot(Mob* defender, EQ::skills::SkillType skillInUse);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user