Merge pull request #1557 from KayenEQ/spa395fix2

[Spells] Healing focuses effects update and Fix for SPA 395
This commit is contained in:
KayenEQ 2021-10-01 15:52:25 -04:00 committed by GitHub
commit 30c7ed7e45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 110 additions and 92 deletions

View File

@ -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)

View File

@ -1078,9 +1078,9 @@ typedef enum {
#define SE_FcTimerLockout 390 // implemented, @Fc, On Caster, set a spell to be on recast timer, base: recast duration milliseconds, Note: Applied from casted spells only
#define SE_LimitManaMax 391 // implemented, @Ff, Mininum mana of spell that can be focused, base1: mana amt
#define SE_FcHealAmt 392 // implemented, @Fc, On Caster, spell healing mod flat amt, base: amt
#define SE_FcHealPctIncoming 393 // implemented, @Fc, On Target, heal received critical chance mod, base: chance pct
#define SE_FcHealPctIncoming 393 // implemented, @Fc, On Target, heal received mod pct, base: pct, limit: random max pct
#define SE_FcHealAmtIncoming 394 // implemented, @Fc, On Target, heal received mod flat amt, base: amt
#define SE_FcHealPctCritIncoming 395 // implemented, @Fc, On Target, heal received mod pct, base: pct
#define SE_FcHealPctCritIncoming 395 // implemented, @Fc, On Target, heal received mod pct, base: pct, limit: random max pct
#define SE_FcHealAmtCrit 396 // implemented, @Fc, On Caster, spell healing mod flat amt, base: amt
#define SE_PetMeleeMitigation 397 // implemented[AA] - additional mitigation to your pets. Adds AC
#define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets

View File

@ -6776,7 +6776,7 @@ int32 Bot::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5)
value += (GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier);
value += (value * target->GetHealRate(spell_id, this) / 100);
value += (value * target->GetHealRate() / 100);
if (Critical)
entity_list.MessageClose(this, false, 100, Chat::SpellCrit, "%s performs an exceptional heal! (%d)", GetName(), value);

View File

@ -134,7 +134,7 @@ typedef enum { //focus types
focusSwarmPetDuration, //@Fc, SPA: 398, SE_SwarmPetDuration, On Caster, swarm pet duration mod, base: milliseconds
focusReduceRecastTime, //@Fc, SPA: 310, SE_ReduceReuseTimer, On Caster, disc reuse time mod, base: milliseconds
focusBlockNextSpell, //@Fc, SPA: 335, SE_BlockNextSpellFocus, On Caster, chance to block next spell, base: chance
focusFcHealPctIncoming, //@Fc, SPA: 395, SE_FcHealPctCritIncoming, On Target, heal received mod pct, base: pct
focusFcHealPctIncoming, //@Fc, SPA: 393, SE_FcHealPctIncoming, On Target, heal received mod pct, base: pct
focusFcDamageAmtIncoming, //@Fc, SPA: 297, SE_FcDamageAmtIncoming, On Target, damage taken flat amt, base: amt
focusFcSpellDamageAmtIncomingPC, //@Fc, SPA: 484, SE_Fc_Spell_Damage_Amt_IncomingPC, On Target, damage taken flat amt, base: amt
focusFcCastSpellOnLand, //@Fc, SPA: 481, SE_Fc_Cast_Spell_On_Land, On Target, cast spell if hit by spell, base: chance pct, limit: spellid
@ -151,7 +151,7 @@ typedef enum { //focus types
focusFcAmplifyAmt, //@Fc, SPA: 508, SE_Fc_Amplify_Amt, On Caster, damage-heal-dot mod flat amt, base: amt
focusFcCastTimeMod2, //@Fc, SPA: 500, SE_Fc_CastTimeMod2, On Caster, cast time mod pct, base: pct
focusFcCastTimeAmt, //@Fc, SPA: 501, SE_Fc_CastTimeAmt, On Caster, cast time mod flat amt, base: milliseconds
focusFcHealPctCritIncoming, //@Fc, SPA: 393, SE_FcHealPctCritIncoming, On Target, heal received critical chance mod, base: chance pct
focusFcHealPctCritIncoming, //@Fc, SPA: 395, SE_FcHealPctCritIncoming, On Target, spell healing mod pct, base: pct
focusFcHealAmt, //@Fc, SPA: 392, SE_FcHealAmt, On Caster, spell healing mod flat amt, base: amt
focusFcHealAmtCrit, //@Fc, SPA: 396, SE_FcHealAmtCrit, On Caster, spell healing mod flat amt, base: amt
} focusType; //Any new FocusType needs to be added to the Mob::IsFocus function

View File

@ -267,63 +267,93 @@ 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->GetFocusEffect(focusFcHealPctIncoming, spell_id)/100); //SPA 393 Add before critical
value += int(value_BaseEffect + target->GetFocusEffect(focusFcHealPctCritIncoming, spell_id)/100); //SPA 395 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) {
value += value * target->GetHealRate() / 100; //SPA 120 modifies value after Focus Applied but before critical
}
/*
Apply critical hit modifier
*/
value += value*target->GetHealRate(spell_id, this)/100;
value *= critical_modifier;
value += GetFocusEffect(focusFcHealAmt, spell_id); //SPA 392 Add after critical
value += GetFocusEffect(focusFcAmplifyAmt, spell_id); //SPA 508 ? Add after critical
if (IsNPC() && CastToNPC()->GetHealScale())
if (target) {
value += target->GetFocusEffect(focusFcHealAmtIncoming, spell_id); //SPA 394 Add after critical
}
if (IsNPC() && CastToNPC()->GetHealScale()) {
value = int(static_cast<float>(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 +361,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<float>(value) * CastToNPC()->GetHealScale() / 100.0f);
}
return value;
}

View File

@ -3878,20 +3878,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);

View File

@ -803,10 +803,9 @@ 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);
int32 GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id); //**** This can be removed when bot healing focus code is updated ****
int32 GetSkillDmgTaken(const EQ::skills::SkillType skill_used, ExtraAttackOptions *opts = nullptr);
int32 GetPositionalDmgTaken(Mob *attacker);
int32 GetPositionalDmgTakenAmt(Mob *attacker);
@ -846,8 +845,10 @@ public:
bool HarmonySpellLevelCheck(int32 spell_id, Mob* target = nullptr);
bool CanFocusUseRandomEffectivenessByType(focusType type);
int GetFocusRandomEffectivenessValue(int focus_base, int focus_base2, bool best_focus = 0);
int GetHealRate() const { return itembonuses.HealRate + spellbonuses.HealRate + aabonuses.HealRate; }
int GetMemoryBlurChance(int base_chance);
bool TryDoubleMeleeRoundEffect();
bool GetUseDoubleMeleeRoundDmgBonus() const { return use_double_melee_round_dmg_bonus; }
inline void SetUseDoubleMeleeRoundDmgBonus(bool val) { use_double_melee_round_dmg_bonus = val; }

View File

@ -5743,7 +5743,7 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
case SE_FcHealPctCritIncoming:
if (type == focusFcHealPctCritIncoming) {
value = focus_spell.base[i];
value = GetFocusRandomEffectivenessValue(focus_spell.base[i], focus_spell.base2[i], best_focus);
}
break;
@ -5761,7 +5761,7 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
case SE_FcHealPctIncoming:
if (type == focusFcHealPctIncoming) {
value = focus_spell.base[i];
value = GetFocusRandomEffectivenessValue(focus_spell.base[i], focus_spell.base2[i], best_focus);
}
break;
@ -5925,7 +5925,7 @@ void Mob::TryTriggerOnCastFocusEffect(focusType type, uint16 spell_id)
}
}
// Only use of this focus per AA effect.
// Only use one of this focus per AA effect.
if (IsClient() && aabonuses.FocusEffects[type]) {
for (const auto &aa : aa_ranks) {
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
@ -6372,8 +6372,9 @@ int32 NPC::GetFocusEffect(focusType type, uint16 spell_id) {
//Improved Healing, Damage & Mana Reduction are handled differently in that some are random percentages
//In these cases we need to find the most powerful effect, so that each piece of gear wont get its own chance
if(RuleB(Spells, LiveLikeFocusEffects) && (type == focusManaCost || type == focusImprovedHeal || type == focusImprovedDamage || type == focusImprovedDamage2))
if (RuleB(Spells, LiveLikeFocusEffects) && CanFocusUseRandomEffectivenessByType(type)) {
rand_effectiveness = true;
}
if (RuleB(Spells, NPC_UseFocusFromItems) && itembonuses.FocusEffects[type]){
@ -6933,50 +6934,54 @@ int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill,
int32 Mob::GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id) {
//**** This can be removed when bot healing focus code is updated ****
/*
This is a general function for calculating best focus effect values for focus effects that exist on targets but modify incoming spells.
Should be used when checking for foci that can exist on clients or npcs ect.
Example: When your target has a focus limited buff that increases amount of healing on them.
*/
if (!caster)
if (!caster) {
return 0;
}
int value = 0;
if (spellbonuses.FocusEffects[type]){
int32 tmp_focus = 0;
int tmp_buffslot = -1;
int32 tmp_focus = 0;
int tmp_buffslot = -1;
int buff_count = GetMaxTotalSlots();
for(int i = 0; i < buff_count; i++) {
int buff_count = GetMaxTotalSlots();
for(int i = 0; i < buff_count; i++) {
if((IsValidSpell(buffs[i].spellid) && IsEffectInSpell(buffs[i].spellid, effect))){
if((IsValidSpell(buffs[i].spellid) && IsEffectInSpell(buffs[i].spellid, effect))){
int32 focus = caster->CalcFocusEffect(type, buffs[i].spellid, spell_id);
int32 focus = caster->CalcFocusEffect(type, buffs[i].spellid, spell_id);
if (!focus)
continue;
if (!focus) {
continue;
}
if (tmp_focus && focus > tmp_focus){
tmp_focus = focus;
tmp_buffslot = i;
}
if (tmp_focus && focus > tmp_focus){
tmp_focus = focus;
tmp_buffslot = i;
}
else if (!tmp_focus){
tmp_focus = focus;
tmp_buffslot = i;
}
else if (!tmp_focus){
tmp_focus = focus;
tmp_buffslot = i;
}
}
value = tmp_focus;
if (tmp_buffslot >= 0)
CheckNumHitsRemaining(NumHit::MatchingSpells, tmp_buffslot);
}
value = tmp_focus;
if (tmp_buffslot >= 0)
CheckNumHitsRemaining(NumHit::MatchingSpells, tmp_buffslot);
}
return value;
}
@ -8498,6 +8503,8 @@ bool Mob::CanFocusUseRandomEffectivenessByType(focusType type)
case focusSpellHateMod:
case focusSpellVulnerability:
case focusFcSpellDamagePctIncomingPC:
case focusFcHealPctIncoming:
case focusFcHealPctCritIncoming:
return true;
}