diff --git a/common/ruletypes.h b/common/ruletypes.h index b0c8074b1..533567b0e 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -380,6 +380,7 @@ RULE_BOOL(Spells, PreventFactionWarOnCharmBreak, false, "Enable spell interupts RULE_BOOL(Spells, AllowDoubleInvis, false, "Allows you to cast invisibility spells on a player that is already invisible") RULE_BOOL(Spells, AllowSpellMemorizeFromItem, false, "Allows players to memorize spells by right-clicking spell scrolls") RULE_BOOL(Spells, InvisRequiresGroup, false, "Invis requires the the target to be in group.") +RULE_INT(Spells, ClericInnateHealFocus, 5, "Clerics on live get a 5 pct innate heal focus") RULE_CATEGORY_END() RULE_CATEGORY(Combat) diff --git a/zone/effects.cpp b/zone/effects.cpp index 37726df12..7dc2c9efa 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -267,63 +267,98 @@ int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_s int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { - if (target == nullptr) - target = this; - if (IsNPC()) - value += value*CastToNPC()->GetSpellFocusHeal()/100; + if (IsNPC()) { + value += value * CastToNPC()->GetSpellFocusHeal() / 100; + } int32 value_BaseEffect = 0; - int16 chance = 0; - int8 modifier = 1; - bool Critical = false; + int16 critical_chance = 0; + int8 critical_modifier = 1; - value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); + if (spells[spell_id].buffduration < 1) { + critical_chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; + + if (spellbonuses.CriticalHealDecay) { + critical_chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); + } + } + else { + critical_chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; + + if (spellbonuses.CriticalRegenDecay) { + critical_chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); + } + } + + if (critical_chance) { + + if (spells[spell_id].override_crit_chance > 0 && critical_chance > spells[spell_id].override_crit_chance) { + critical_chance = spells[spell_id].override_crit_chance; + } + + if (zone->random.Roll(critical_chance)) { + critical_modifier = 2; //At present time no critical heal amount modifier SPA exists. + } + } + + value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id) / 100); value = value_BaseEffect; - value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100); + if (GetClass() == CLERIC) { + value += int(value_BaseEffect*RuleI(Spells, ClericInnateHealFocus) / 100); //confirmed on live parsing clerics get an innate 5 pct heal focus + } + value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id) / 100); value += int(value_BaseEffect*GetFocusEffect(focusFcAmplifyMod, spell_id) / 100); // Instant Heals - if(spells[spell_id].buffduration < 1) { + if (spells[spell_id].buffduration < 1) { - chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance; - - chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); - - if (spellbonuses.CriticalHealDecay) - chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay); - - if (spells[spell_id].override_crit_chance > 0 && chance > spells[spell_id].override_crit_chance) - chance = spells[spell_id].override_crit_chance; - - if(chance && (zone->random.Roll(chance))) { - Critical = true; - modifier = 2; //At present time no critical heal amount modifier SPA exists. + if (target) { + value += int(value_BaseEffect + target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id) / 100); //SPA 395 ? Add before critical + value += int(value_BaseEffect + target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctIncoming, this, spell_id) / 100); //SPA 393 Add before critical } - value *= modifier; - value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier; - value += GetFocusEffect(focusFcHealAmt, spell_id); - value += GetFocusEffect(focusFcAmplifyAmt, spell_id); - value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); + value += GetFocusEffect(focusFcHealAmtCrit, spell_id); //SPA 396 Add before critical + + if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) { + value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value); //Item Heal Amt Add before critical + } - if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%17) - 1] >= GetLevel() - 5) - value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier; + if (target) { + int incoming_heal_mod_percent = target->itembonuses.HealRate + target->spellbonuses.HealRate + target->aabonuses.HealRate; //SPA 120 modifies value after Focus Applied but before critical + incoming_heal_mod_percent = std::min(incoming_heal_mod_percent, -100); + value += value * incoming_heal_mod_percent / 100; + } - value += value*target->GetHealRate(spell_id, this)/100; + //value += value * target->GetHealRate(spell_id, this) / 100; //SPA 120 modifies value after Focus Applied but before critical + + /* + Apply critical hit modifier + */ - if (IsNPC() && CastToNPC()->GetHealScale()) + value *= critical_modifier; + value += GetFocusEffect(focusFcHealAmt, spell_id); //SPA 392 Add after critical + value += GetFocusEffect(focusFcAmplifyAmt, spell_id); //SPA 508 ? Add after critical + + if (target) { + value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id); //SPA 394 Add after critical + } + + + if (IsNPC() && CastToNPC()->GetHealScale()) { value = int(static_cast(value) * CastToNPC()->GetHealScale() / 100.0f); + } - if (Critical) { + if (critical_modifier > 1) { entity_list.MessageCloseString( this, true, 100, Chat::SpellCrit, OTHER_CRIT_HEAL, GetName(), itoa(value)); - if (IsClient()) + if (IsClient()) { MessageString(Chat::SpellCrit, YOU_CRIT_HEAL, itoa(value)); + } } return value; @@ -331,20 +366,13 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { //Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value] else { - - chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime; - - chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id); - - if (spellbonuses.CriticalRegenDecay) - chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay); - - if(chance && zone->random.Roll(chance)) - value *= 2; + if (critical_chance && zone->random.Roll(critical_chance)) + value *= critical_modifier; } - if (IsNPC() && CastToNPC()->GetHealScale()) + if (IsNPC() && CastToNPC()->GetHealScale()) { value = int(static_cast(value) * CastToNPC()->GetHealScale() / 100.0f); + } return value; } diff --git a/zone/mob.cpp b/zone/mob.cpp index 07d4cff7e..4f6673cb6 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3933,20 +3933,6 @@ int32 Mob::GetPositionalDmgTakenAmt(Mob *attacker) return total_amt; } - -int16 Mob::GetHealRate(uint16 spell_id, Mob* caster) { - - int16 heal_rate = 0; - - heal_rate += itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate; - heal_rate += GetFocusIncoming(focusFcHealPctIncoming, SE_FcHealPctIncoming, caster, spell_id); - - if(heal_rate < -99) - heal_rate = -99; - - return heal_rate; -} - void Mob::SetBottomRampageList() { auto &mob_list = entity_list.GetCloseMobList(this); diff --git a/zone/mob.h b/zone/mob.h index 53170b958..3b07bfcdf 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -801,7 +801,6 @@ public: void TrySympatheticProc(Mob *target, uint32 spell_id); bool TryFadeEffect(int slot); uint16 GetSpellEffectResistChance(uint16 spell_id); - int16 GetHealRate(uint16 spell_id, Mob* caster = nullptr); int32 GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining); int32 GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill = false, uint16 skill=0); int32 GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id);