diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 683d7f7ba..6e0e10d41 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2903,10 +2903,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove if (zone->random.Roll(spells[spell_id].base[i]) && IsValidSpell(spells[spell_id].base2[i])) caster->SpellFinished(spells[spell_id].base2[i], this, EQ::spells::CastingSlot::Item, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff); - + break; } - + case SE_Hatelist_To_Tail_Index: { if (caster && zone->random.Roll(spells[spell_id].base[i])) caster->SetBottomRampageList(); @@ -2940,7 +2940,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove else Stun(spells[spell_id].base[i]); } - else + else caster->MessageString(Chat::SpellFailure, FEAR_TOO_HIGH); break; } @@ -2949,7 +2949,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove buffs[buffslot].focusproclimit_procamt = spells[spell_id].base[i]; //Set max amount of procs before lockout timer break; } - + case SE_PersistentEffect: MakeAura(spell_id); break; @@ -3941,11 +3941,11 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster) int32 amt = abs(GetMaxHP() * effect_value / 100); if (spells[buff.spellid].max[i] && amt > spells[buff.spellid].max[i]) amt = spells[buff.spellid].max[i]; - - if (effect_value < 0) { + + if (effect_value < 0) { Damage(this, amt, 0, EQ::skills::SkillEvocation, false); } - else { + else { HealDamage(amt); } break; @@ -3958,7 +3958,7 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster) amt = spells[buff.spellid].max[i]; if (effect_value < 0) { - + SetMana(GetMana() - amt); } else { @@ -4440,18 +4440,18 @@ int16 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id) bool not_focusable = spells[spell_id].not_focusable; - int16 value = 0; - int lvlModifier = 100; - int spell_level = 0; - int lvldiff = 0; - uint32 effect = 0; - int32 base1 = 0; - int32 base2 = 0; - uint32 slot = 0; + int16 value = 0; + int lvlModifier = 100; + int spell_level = 0; + int lvldiff = 0; + uint32 effect = 0; + int32 base1 = 0; + int32 base2 = 0; + uint32 slot = 0; int index_id = -1; - bool LimitFailure = false; + bool LimitFailure = false; bool LimitInclude[MaxLimitInclude] = {false}; /* Certain limits require only one of several Include conditions to be true. Ie. Add damage to fire OR ice spells. @@ -4465,13 +4465,13 @@ int16 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id) 14/15 SE_LimitSpellSubClass: Remember: Update MaxLimitInclude in spdat.h if adding new limits that require Includes */ - int FocusCount = 0; + int FocusCount = 0; for (const auto &e : rank.effects) { effect = e.effect_id; - base1 = e.base1; - base2 = e.base2; - slot = e.slot; + base1 = e.base1; + base2 = e.base2; + slot = e.slot; /* AA Foci's can contain multiple focus effects within the same AA. @@ -4486,12 +4486,13 @@ int16 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id) if (FocusCount > 1) { for (int e = 0; e < MaxLimitInclude; e += 2) { - if (LimitInclude[e] && !LimitInclude[e + 1]) + if (LimitInclude[e] && !LimitInclude[e + 1]) { LimitFailure = true; + } } if (LimitFailure) { - value = 0; + value = 0; LimitFailure = false; for (int e = 0; e < MaxLimitInclude; e++) { @@ -4506,509 +4507,597 @@ int16 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id) } switch (effect) { - case SE_Blank: - break; + case SE_Blank: + break; - // Handle Focus Limits + // Handle Focus Limits - case SE_LimitResist: - if (base1 < 0) { - if (spell.resisttype == -base1) // Exclude - LimitFailure = true; - } - else { - LimitInclude[0] = true; - if (spell.resisttype == base1) // Include - LimitInclude[1] = true; - } - break; - - case SE_LimitInstant: - if (base1 == 1 && spell.buffduration) // Fail if not instant - LimitFailure = true; - if (base1 == 0 && (spell.buffduration == 0)) // Fail if instant - LimitFailure = true; - - break; - - case SE_LimitMaxLevel: - spell_level = spell.classes[(GetClass() % 17) - 1]; - lvldiff = spell_level - base1; - // every level over cap reduces the effect by base2 percent unless from a clicky when - // ItemCastsUseFocus is true - if (lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || - RuleB(Character, ItemCastsUseFocus) == false)) { - if (base2 > 0) { - lvlModifier -= base2 * lvldiff; - if (lvlModifier < 1) + case SE_LimitResist: + if (base1 < 0) { + if (spell.resisttype == -base1) { // Exclude LimitFailure = true; - } - else - LimitFailure = true; - } - break; - - case SE_LimitMinLevel: - if ((spell.classes[(GetClass() % 17) - 1]) < base1) - LimitFailure = true; - break; - - case SE_LimitCastTimeMin: - if (static_cast(spell.cast_time) < base1) - LimitFailure = true; - break; - - case SE_LimitCastTimeMax: - if (static_cast(spell.cast_time) > base1) - LimitFailure = true; - break; - - case SE_LimitSpell: - if (base1 < 0) { // Exclude - if (spell_id == -base1) - LimitFailure = true; - } - else { - LimitInclude[2] = true; - if (spell_id == base1) // Include - LimitInclude[3] = true; - } - break; - - case SE_LimitMinDur: - if (base1 > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) - LimitFailure = true; - - break; - - case SE_LimitEffect: - if (base1 < 0) { - if (IsEffectInSpell(spell_id, -base1)) // Exclude - LimitFailure = true; - } - else { - LimitInclude[4] = true; - // they use 33 here for all classes ... unsure if the type check is really needed - if (base1 == SE_SummonPet && type == focusReagentCost) { - if (IsSummonPetSpell(spell_id) || IsSummonSkeletonSpell(spell_id)) - LimitInclude[5] = true; + } } else { - if (IsEffectInSpell(spell_id, base1)) // Include - LimitInclude[5] = true; + LimitInclude[0] = true; + if (spell.resisttype == base1) { // Include + LimitInclude[1] = true; + } } - } - break; - - case SE_LimitSpellType: - switch (base1) { - case 0: - if (!IsDetrimentalSpell(spell_id)) - LimitFailure = true; break; - case 1: - if (!IsBeneficialSpell(spell_id)) + + case SE_LimitInstant: + if (base1 == 1 && spell.buffduration) { // Fail if not instant LimitFailure = true; + } + if (base1 == 0 && (spell.buffduration == 0)) { // Fail if instant + LimitFailure = true; + } + break; - } - break; - case SE_LimitManaMin: - if (spell.mana < base1) - LimitFailure = true; - break; - - case SE_LimitManaMax: - if (spell.mana > base1) - LimitFailure = true; - break; - - case SE_LimitTarget: - if (base1 < 0) { - if (-base1 == spell.targettype) // Exclude - LimitFailure = true; - } - else { - LimitInclude[6] = true; - if (base1 == spell.targettype) // Include - LimitInclude[7] = true; - } - break; - - case SE_LimitCombatSkills: - if (base1 == 0 && (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) // Exclude Discs / Procs - LimitFailure = true; - else if (base1 == 1 && (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) // Exclude Spells - LimitFailure = true; - - break; - - case SE_LimitSpellGroup: - if (base1 < 0) { - if (-base1 == spell.spellgroup) // Exclude - LimitFailure = true; - } - else { - LimitInclude[8] = true; - if (base1 == spell.spellgroup) // Include - LimitInclude[9] = true; - } - break; - - case SE_LimitCastingSkill: - if (base1 < 0) { - if (-base1 == spell.skill) - LimitFailure = true; - } - else { - LimitInclude[10] = true; - if (base1 == spell.skill) - LimitInclude[11] = true; - } - break; - - case SE_LimitSpellClass: - if (base1 < 0) { // Exclude - if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) - LimitFailure = true; - } - else { - LimitInclude[12] = true; - if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) // Include - LimitInclude[13] = true; - } - break; - - case SE_LimitSpellSubclass: - if (base1 < 0) { // Exclude - if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) - LimitFailure = true; - } - else { - LimitInclude[14] = true; - if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) // Include - LimitInclude[15] = true; - } - break; - - case SE_LimitClass: - // Do not use this limit more then once per spell. If multiple class, treat value like items - // would. - if (!PassLimitClass(base1, GetClass())) - LimitFailure = true; - break; - - case SE_LimitRace: - if (base1 != GetRace()) - LimitFailure = true; - break; - - case SE_LimitUseMin: - if (base1 > spell.numhits) - LimitFailure = true; - break; - - case SE_LimitUseType: - if (base1 != spell.numhitstype) - LimitFailure = true; - break; - - case SE_Ff_DurationMax: - if (base1 > spell.buffduration) - LimitFailure = true; - break; - - case SE_Ff_Endurance_Min: - if (spell.EndurCost < base1) - LimitFailure = true; - break; - - case SE_Ff_Endurance_Max: - if (spell.EndurCost > base1) - LimitFailure = true; - break; - - case SE_Ff_ReuseTimeMin: - if (spell.recast_time < base1) - LimitFailure = true; - break; - - case SE_Ff_ReuseTimeMax: - if (spell.recast_time > base1) - LimitFailure = true; - break; - - case SE_Ff_Value_Min: - index_id = GetSpellEffectIndex(spell_id, base2); - if (index_id >= 0 && spell.base[index_id] < base1) - LimitFailure = true; - break; - - case SE_Ff_Value_Max: - index_id = GetSpellEffectIndex(spell_id, base2); - if (index_id >= 0 && spell.base[index_id] > base1) - LimitFailure = true; - break; - - case SE_Ff_Override_NotFocusable: - if (base1 == 1) - not_focusable = false; - break; - - - /* These are not applicable to AA's because there is never a 'caster' of the 'buff' with the focus effect. - case SE_Ff_Same_Caster: - case SE_Ff_CasterClass: - */ - - // Handle Focus Effects - case SE_ImprovedDamage: - if (type == focusImprovedDamage && base1 > value) - value = base1; - break; - - case SE_ImprovedDamage2: - if (type == focusImprovedDamage2 && base1 > value) - value = base1; - break; - - case SE_Fc_Amplify_Mod: - if (type == focusFcAmplifyMod && base1 > value) - value = base1; - break; - - case SE_ImprovedHeal: - if (type == focusImprovedHeal && base1 > value) - value = base1; - break; - - case SE_ReduceManaCost: - if (type == focusManaCost) - value = base1; - break; - - case SE_IncreaseSpellHaste: - if (type == focusSpellHaste && base1 > value) - value = base1; - break; - - case SE_Fc_CastTimeMod2: - if (type == focusFcCastTimeMod2 && base1 > value) - value = base1; - break; - - case SE_Fc_CastTimeAmt: - if (type == focusFcCastTimeAmt && base1 > value) - value = base1; - break; - - case SE_IncreaseSpellDuration: - if (type == focusSpellDuration && base1 > value) - value = base1; - break; - - case SE_SpellDurationIncByTic: - if (type == focusSpellDurByTic && base1 > value) - value = base1; - break; - - case SE_SwarmPetDuration: - if (type == focusSwarmPetDuration && base1 > value) - value = base1; - break; - - case SE_IncreaseRange: - if (type == focusRange && base1 > value) - value = base1; - break; - - case SE_ReduceReagentCost: - if (type == focusReagentCost && base1 > value) - value = base1; - break; - - case SE_PetPowerIncrease: - if (type == focusPetPower && base1 > value) - value = base1; - break; - - case SE_SpellResistReduction: - if (type == focusResistRate && base1 > value) - value = base1; - break; - - case SE_Fc_ResistIncoming: - if (type == focusFcResistIncoming && base1 > value) - value = base1; - break; - - case SE_SpellHateMod: - if (type == focusSpellHateMod) { - if (value != 0) { - if (value > 0) { - if (base1 > value) - value = base1; + case SE_LimitMaxLevel: + spell_level = spell.classes[(GetClass() % 17) - 1]; + lvldiff = spell_level - base1; + // every level over cap reduces the effect by base2 percent unless from a clicky when + // ItemCastsUseFocus is true + if (lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || + RuleB(Character, ItemCastsUseFocus) == false)) { + if (base2 > 0) { + lvlModifier -= base2 * lvldiff; + if (lvlModifier < 1) { + LimitFailure = true; + } } else { - if (base1 < value) - value = base1; + LimitFailure = true; } } - else - value = base1; - } - break; + break; - case SE_ReduceReuseTimer: - if (type == focusReduceRecastTime) - value = base1 / 1000; - break; - - case SE_TriggerOnCast: - if (type == focusTriggerOnCast) { - if (zone->random.Roll(base1)) { - value = base2; - } - else { - value = 0; + case SE_LimitMinLevel: + if ((spell.classes[(GetClass() % 17) - 1]) < base1) { LimitFailure = true; } break; - } - case SE_FcSpellVulnerability: - if (type == focusSpellVulnerability) - value = base1; - break; + case SE_LimitCastTimeMin: + if (static_cast(spell.cast_time) < base1) { + LimitFailure = true; + } + break; - case SE_Fc_Spell_Damage_Pct_IncomingPC: - if (type == focusFcSpellDamagePctIncomingPC) - value = base1; - break; + case SE_LimitCastTimeMax: + if (static_cast(spell.cast_time) > base1) { + LimitFailure = true; + } + break; - case SE_BlockNextSpellFocus: - if (type == focusBlockNextSpell) { - if (zone->random.Roll(base1)) - value = 1; - } - break; + case SE_LimitSpell: + if (base1 < 0) { // Exclude + if (spell_id == -base1) { + LimitFailure = true; + } + } + else { + LimitInclude[2] = true; + if (spell_id == base1) { // Include + LimitInclude[3] = true; + } + } + break; - case SE_FcTwincast: - if (type == focusTwincast && !IsEffectInSpell(spell_id, SE_TwinCastBlocker)) - value = base1; - break; + case SE_LimitMinDur: + if (base1 > CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) { + LimitFailure = true; + } - // Note if using these as AA, make sure this is first focus used. - case SE_SympatheticProc: - if (type == focusSympatheticProc) - value = base2; - break; + break; - case SE_FcDamageAmt: - if (type == focusFcDamageAmt) - value = base1; - break; + case SE_LimitEffect: + if (base1 < 0) { + if (IsEffectInSpell(spell_id, -base1)) { // Exclude + LimitFailure = true; + } + } + else { + LimitInclude[4] = true; + // they use 33 here for all classes ... unsure if the type check is really needed + if (base1 == SE_SummonPet && type == focusReagentCost) { + if (IsSummonPetSpell(spell_id) || IsSummonSkeletonSpell(spell_id)) { + LimitInclude[5] = true; + } + } + else { + if (IsEffectInSpell(spell_id, base1)) { // Include + LimitInclude[5] = true; + } + } + } + break; - case SE_FcDamageAmt2: - if (type == focusFcDamageAmt2) - value = base1; - break; + case SE_LimitSpellType: + switch (base1) { + case 0: + if (!IsDetrimentalSpell(spell_id)) { + LimitFailure = true; + } + break; + case 1: + if (!IsBeneficialSpell(spell_id)) { + LimitFailure = true; + } + break; + } + break; - case SE_Fc_Amplify_Amt: - if (type == focusFcAmplifyAmt) - value = base1; - break; + case SE_LimitManaMin: + if (spell.mana < base1) { + LimitFailure = true; + } + break; - case SE_FcDamageAmtCrit: - if (type == focusFcDamageAmtCrit) - value = base1; - break; + case SE_LimitManaMax: + if (spell.mana > base1) { + LimitFailure = true; + } + break; - case SE_FcDamageAmtIncoming: - if (type == focusFcDamageAmtIncoming) - value = base1; - break; + case SE_LimitTarget: + if (base1 < 0) { + if (-base1 == spell.targettype) { // Exclude + LimitFailure = true; + } + } + else { + LimitInclude[6] = true; + if (base1 == spell.targettype) { // Include + LimitInclude[7] = true; + } + } + break; - case SE_Fc_Spell_Damage_Amt_IncomingPC: - if (type == focusFcSpellDamageAmtIncomingPC) - value = base1; - break; + case SE_LimitCombatSkills: + if (base1 == 0 && (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) { // Exclude Discs / Procs + LimitFailure = true; + } + else if (base1 == 1 && (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) { // Exclude Spells + LimitFailure = true; + } - case SE_FcHealAmtIncoming: - if (type == focusFcHealAmtIncoming) - value = base1; - break; + break; - case SE_FcHealPctCritIncoming: - if (type == focusFcHealPctCritIncoming) - value = base1; - break; + case SE_LimitSpellGroup: + if (base1 < 0) { + if (-base1 == spell.spellgroup) { // Exclude + LimitFailure = true; + } + } + else { + LimitInclude[8] = true; + if (base1 == spell.spellgroup) { // Include + LimitInclude[9] = true; + } + } + break; - case SE_FcHealAmtCrit: - if (type == focusFcHealAmtCrit) - value = base1; - break; + case SE_LimitCastingSkill: + if (base1 < 0) { + if (-base1 == spell.skill) { + LimitFailure = true; + } + } + else { + LimitInclude[10] = true; + if (base1 == spell.skill) { + LimitInclude[11] = true; + } + } + break; - case SE_FcHealAmt: - if (type == focusFcHealAmt) - value = base1; - break; + case SE_LimitSpellClass: + if (base1 < 0) { // Exclude + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) { + LimitFailure = true; + } + } + else { + LimitInclude[12] = true; + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)) { // Include + LimitInclude[13] = true; + } + } + break; - case SE_FcHealPctIncoming: - if (type == focusFcHealPctIncoming) - value = base1; - break; + case SE_LimitSpellSubclass: + if (base1 < 0) { // Exclude + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) { + LimitFailure = true; + } + } + else { + LimitInclude[14] = true; + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)) { // Include + LimitInclude[15] = true; + } + } + break; - case SE_FcBaseEffects: - if (type == focusFcBaseEffects) - value = base1; - break; + case SE_LimitClass: + // Do not use this limit more then once per spell. If multiple class, treat value like items + // would. + if (!PassLimitClass(base1, GetClass())) { + LimitFailure = true; + } + break; - case SE_FcDamagePctCrit: - if (type == focusFcDamagePctCrit) - value = base1; - break; + case SE_LimitRace: + if (base1 != GetRace()) { + LimitFailure = true; + } + break; - case SE_FcIncreaseNumHits: - if (type == focusIncreaseNumHits) - value = base1; - break; + case SE_LimitUseMin: + if (base1 > spell.numhits) { + LimitFailure = true; + } + break; - case SE_FcLimitUse: - if (type == focusFcLimitUse) - value = base1; - break; + case SE_LimitUseType: + if (base1 != spell.numhitstype) { + LimitFailure = true; + } + break; - case SE_FcMute: - if (type == focusFcMute) - value = base1; - break; + case SE_Ff_DurationMax: + if (base1 > spell.buffduration) { + LimitFailure = true; + } + break; - case SE_FcStunTimeMod: - if (type == focusFcStunTimeMod) - value = base1; - break; + case SE_Ff_Endurance_Min: + if (spell.EndurCost < base1) { + LimitFailure = true; + } + break; - case SE_Fc_Cast_Spell_On_Land: - if (type == focusFcCastSpellOnLand) { - if (zone->random.Roll(base1)) { + case SE_Ff_Endurance_Max: + if (spell.EndurCost > base1) { + LimitFailure = true; + } + break; + + case SE_Ff_ReuseTimeMin: + if (spell.recast_time < base1) { + LimitFailure = true; + } + break; + + case SE_Ff_ReuseTimeMax: + if (spell.recast_time > base1) { + LimitFailure = true; + } + break; + + case SE_Ff_Value_Min: + index_id = GetSpellEffectIndex(spell_id, base2); + if (index_id >= 0 && spell.base[index_id] < base1) { + LimitFailure = true; + } + break; + + case SE_Ff_Value_Max: + index_id = GetSpellEffectIndex(spell_id, base2); + if (index_id >= 0 && spell.base[index_id] > base1) { + LimitFailure = true; + } + break; + + case SE_Ff_Override_NotFocusable: + if (base1 == 1) { + not_focusable = false; + } + break; + + + /* These are not applicable to AA's because there is never a 'caster' of the 'buff' with the focus effect. + case SE_Ff_Same_Caster: + case SE_Ff_CasterClass: + */ + + // Handle Focus Effects + case SE_ImprovedDamage: + if (type == focusImprovedDamage && base1 > value) { + value = base1; + } + break; + + case SE_ImprovedDamage2: + if (type == focusImprovedDamage2 && base1 > value) { + value = base1; + } + break; + + case SE_Fc_Amplify_Mod: + if (type == focusFcAmplifyMod && base1 > value) { + value = base1; + } + break; + + case SE_ImprovedHeal: + if (type == focusImprovedHeal && base1 > value) { + value = base1; + } + break; + + case SE_ReduceManaCost: + if (type == focusManaCost) { + value = base1; + } + break; + + case SE_IncreaseSpellHaste: + if (type == focusSpellHaste && base1 > value) { + value = base1; + } + break; + + case SE_Fc_CastTimeMod2: + if (type == focusFcCastTimeMod2 && base1 > value) { + value = base1; + } + break; + + case SE_Fc_CastTimeAmt: + if (type == focusFcCastTimeAmt && base1 > value) { + value = base1; + } + break; + + case SE_IncreaseSpellDuration: + if (type == focusSpellDuration && base1 > value) { + value = base1; + } + break; + + case SE_SpellDurationIncByTic: + if (type == focusSpellDurByTic && base1 > value) { + value = base1; + } + break; + + case SE_SwarmPetDuration: + if (type == focusSwarmPetDuration && base1 > value) { + value = base1; + } + break; + + case SE_IncreaseRange: + if (type == focusRange && base1 > value) { + value = base1; + } + break; + + case SE_ReduceReagentCost: + if (type == focusReagentCost && base1 > value) { + value = base1; + } + break; + + case SE_PetPowerIncrease: + if (type == focusPetPower && base1 > value) { + value = base1; + } + break; + + case SE_SpellResistReduction: + if (type == focusResistRate && base1 > value) { + value = base1; + } + break; + + case SE_Fc_ResistIncoming: + if (type == focusFcResistIncoming && base1 > value) { + value = base1; + } + break; + + case SE_SpellHateMod: + if (type == focusSpellHateMod) { + if (value != 0) { + if (value > 0) { + if (base1 > value) { + value = base1; + } + } + else { + if (base1 < value) { + value = base1; + } + } + } + else { + value = base1; + } + } + break; + + case SE_ReduceReuseTimer: + if (type == focusReduceRecastTime) { + value = base1 / 1000; + } + break; + + case SE_TriggerOnCast: + if (type == focusTriggerOnCast) { + if (zone->random.Roll(base1)) { + value = base2; + } + else { + value = 0; + LimitFailure = true; + } + break; + } + + case SE_FcSpellVulnerability: + if (type == focusSpellVulnerability) { + value = base1; + } + break; + + case SE_Fc_Spell_Damage_Pct_IncomingPC: + if (type == focusFcSpellDamagePctIncomingPC) { + value = base1; + } + break; + + case SE_BlockNextSpellFocus: + if (type == focusBlockNextSpell) { + if (zone->random.Roll(base1)) { + value = 1; + } + } + break; + + case SE_FcTwincast: + if (type == focusTwincast && !IsEffectInSpell(spell_id, SE_TwinCastBlocker)) { + value = base1; + } + break; + + // Note if using these as AA, make sure this is first focus used. + case SE_SympatheticProc: + if (type == focusSympatheticProc) { value = base2; } break; - } + + case SE_FcDamageAmt: + if (type == focusFcDamageAmt) { + value = base1; + } + break; + + case SE_FcDamageAmt2: + if (type == focusFcDamageAmt2) { + value = base1; + } + break; + + case SE_Fc_Amplify_Amt: + if (type == focusFcAmplifyAmt) { + value = base1; + } + break; + + case SE_FcDamageAmtCrit: + if (type == focusFcDamageAmtCrit) { + value = base1; + } + break; + + case SE_FcDamageAmtIncoming: + if (type == focusFcDamageAmtIncoming) { + value = base1; + } + break; + + case SE_Fc_Spell_Damage_Amt_IncomingPC: + if (type == focusFcSpellDamageAmtIncomingPC) { + value = base1; + } + break; + + case SE_FcHealAmtIncoming: + if (type == focusFcHealAmtIncoming) { + value = base1; + } + break; + + case SE_FcHealPctCritIncoming: + if (type == focusFcHealPctCritIncoming) { + value = base1; + } + break; + + case SE_FcHealAmtCrit: + if (type == focusFcHealAmtCrit) { + value = base1; + } + break; + + case SE_FcHealAmt: + if (type == focusFcHealAmt) { + value = base1; + } + break; + + case SE_FcHealPctIncoming: + if (type == focusFcHealPctIncoming) { + value = base1; + } + break; + + case SE_FcBaseEffects: + if (type == focusFcBaseEffects) { + value = base1; + } + break; + + case SE_FcDamagePctCrit: + if (type == focusFcDamagePctCrit) { + value = base1; + } + break; + + case SE_FcIncreaseNumHits: + if (type == focusIncreaseNumHits) { + value = base1; + } + break; + + case SE_FcLimitUse: + if (type == focusFcLimitUse) { + value = base1; + } + break; + + case SE_FcMute: + if (type == focusFcMute) { + value = base1; + } + break; + + case SE_FcStunTimeMod: + if (type == focusFcStunTimeMod) { + value = base1; + } + break; + + case SE_Fc_Cast_Spell_On_Land: + if (type == focusFcCastSpellOnLand) { + if (zone->random.Roll(base1)) { + value = base2; + } + break; + } } } for (int e = 0; e < MaxLimitInclude; e += 2) { - if (LimitInclude[e] && !LimitInclude[e + 1]) + if (LimitInclude[e] && !LimitInclude[e + 1]) { return 0; + } } - if (LimitFailure) + if (LimitFailure) { return 0; + } - if (not_focusable) + if (not_focusable) { return 0; + } return (value * lvlModifier / 100); } @@ -5022,22 +5111,24 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo 'casterid' is the casterid of the caster of spell_id, used when spell_id is cast on a target with a focus effect that is checked by incoming spell. */ - if (!IsValidSpell(focus_id) || !IsValidSpell(spell_id)) + if (!IsValidSpell(focus_id) || !IsValidSpell(spell_id)) { return 0; + } //No further checks if spell_id no_focusable, unless spell focus_id contains an override limiter. - if (spells[spell_id].not_focusable && !IsEffectInSpell(focus_id, SE_Ff_Override_NotFocusable)) + if (spells[spell_id].not_focusable && !IsEffectInSpell(focus_id, SE_Ff_Override_NotFocusable)) { return 0; + } const SPDat_Spell_Struct &focus_spell = spells[focus_id]; - const SPDat_Spell_Struct &spell = spells[spell_id]; + const SPDat_Spell_Struct &spell = spells[spell_id]; - int16 value = 0; - int lvlModifier = 100; - int spell_level = 0; - int lvldiff = 0; + int16 value = 0; + int lvlModifier = 100; + int spell_level = 0; + int lvldiff = 0; uint32 Caston_spell_id = 0; - int index_id = -1; + int index_id = -1; bool LimitInclude[MaxLimitInclude] = {false}; /* Certain limits require only one of several Include conditions to be true. Determined by limits being negative or positive @@ -5058,603 +5149,724 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo switch (focus_spell.effectid[i]) { - case SE_Blank: - break; - - case SE_LimitResist: - if (focus_spell.base[i] < 0) { - if (spell.resisttype == -focus_spell.base[i]) // Exclude - return 0; - } else { - LimitInclude[0] = true; - if (spell.resisttype == focus_spell.base[i]) // Include - LimitInclude[1] = true; - } - break; - - case SE_LimitInstant: - if (focus_spell.base[i] == 1 && spell.buffduration) // Fail if not instant - return 0; - if (focus_spell.base[i] == 0 && (spell.buffduration == 0)) // Fail if instant - return 0; - - break; - - case SE_LimitMaxLevel: - if (IsNPC()) + case SE_Blank: break; - spell_level = spell.classes[(GetClass() % 17) - 1]; - lvldiff = spell_level - focus_spell.base[i]; - // every level over cap reduces the effect by focus_spell.base2[i] percent unless from a clicky - // when ItemCastsUseFocus is true - if (lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || - RuleB(Character, ItemCastsUseFocus) == false)) { - if (focus_spell.base2[i] > 0) { - lvlModifier -= focus_spell.base2[i] * lvldiff; - if (lvlModifier < 1) + + case SE_LimitResist: + if (focus_spell.base[i] < 0) { + if (spell.resisttype == -focus_spell.base[i]) { // Exclude return 0; - } else - return 0; - } - break; - - case SE_LimitMinLevel: - if (IsNPC()) - break; - if (spell.classes[(GetClass() % 17) - 1] < focus_spell.base[i]) - return (0); - break; - - case SE_LimitCastTimeMin: - if (spells[spell_id].cast_time < (uint16)focus_spell.base[i]) - return (0); - break; - - case SE_LimitCastTimeMax: - if (spells[spell_id].cast_time > (uint16)focus_spell.base[i]) - return (0); - break; - - case SE_LimitSpell: - if (focus_spell.base[i] < 0) { // Exclude - if (spell_id == -focus_spell.base[i]) - return (0); - } else { - LimitInclude[2] = true; - if (spell_id == focus_spell.base[i]) // Include - LimitInclude[3] = true; - } - break; - - case SE_LimitMinDur: - if (focus_spell.base[i] > - CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) - return (0); - break; - - case SE_LimitEffect: - if (focus_spell.base[i] < 0) { - if (IsEffectInSpell(spell_id, -focus_spell.base[i])) // Exclude - return 0; - } else { - LimitInclude[4] = true; - if (IsEffectInSpell(spell_id, focus_spell.base[i])) // Include - LimitInclude[5] = true; - } - break; - - case SE_LimitSpellType: - switch (focus_spell.base[i]) { - case 0: - if (!IsDetrimentalSpell(spell_id)) - return 0; - break; - case 1: - if (!IsBeneficialSpell(spell_id)) - return 0; - break; - default: - LogInfo("CalcFocusEffect: unknown limit spelltype [{}]", - focus_spell.base[i]); - } - break; - - case SE_LimitManaMin: - if (spell.mana < focus_spell.base[i]) - return 0; - break; - - case SE_LimitManaMax: - if (spell.mana > focus_spell.base[i]) - return 0; - break; - - case SE_LimitTarget: - if (focus_spell.base[i] < 0) { - if (-focus_spell.base[i] == spell.targettype) // Exclude - return 0; - } else { - LimitInclude[6] = true; - if (focus_spell.base[i] == spell.targettype) // Include - LimitInclude[7] = true; - } - break; - - case SE_LimitCombatSkills: - if (focus_spell.base[i] == 0 && - (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) // Exclude Discs / Procs - return 0; - else if (focus_spell.base[i] == 1 && - (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) // Exclude Spells - return 0; - - break; - - case SE_LimitSpellGroup: - if (focus_spell.base[i] < 0) { - if (-focus_spell.base[i] == spell.spellgroup) // Exclude - return 0; - } else { - LimitInclude[8] = true; - if (focus_spell.base[i] == spell.spellgroup) // Include - LimitInclude[9] = true; - } - break; - - case SE_LimitCastingSkill: - if (focus_spell.base[i] < 0) { - if (-focus_spell.base[i] == spell.skill) - return 0; - } else { - LimitInclude[10] = true; - if (focus_spell.base[i] == spell.skill) - LimitInclude[11] = true; - } - break; - - case SE_LimitClass: - // Do not use this limit more then once per spell. If multiple class, treat value like items - // would. - if (!PassLimitClass(focus_spell.base[i], GetClass())) - return 0; - break; - - case SE_LimitRace: - if (focus_spell.base[i] != GetRace()) - return 0; - break; - - case SE_LimitUseMin: - if (focus_spell.base[i] > spell.numhits) - return 0; - break; - - case SE_LimitUseType: - if (focus_spell.base[i] != spell.numhitstype) - return 0; - break; - - case SE_CastonFocusEffect: - if (focus_spell.base[i] > 0) - Caston_spell_id = focus_spell.base[i]; - break; - - case SE_LimitSpellClass: - if (focus_spell.base[i] < 0) { // Exclude - if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) - return (0); - } else { - LimitInclude[12] = true; - if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) // Include - LimitInclude[13] = true; - } - break; - - case SE_LimitSpellSubclass: - if (focus_spell.base[i] < 0) { // Exclude - if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) - return (0); - } else { - LimitInclude[14] = true; - if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) // Include - LimitInclude[15] = true; - } - break; - - case SE_Ff_Same_Caster://hmm do i need to pass casterid from buff slot here - if (focus_spell.base[i] == 0) { - if (casterid == GetID()) - return 0;//Mob casting is same as target, fail if you are casting on yourself. - } - else if (focus_spell.base[i] == 1) { - if (casterid != GetID()) - return 0;//Mob casting is not same as target, fail if you are not casting on yourself. - } - break; - - case SE_Ff_CasterClass: - // Do not use this limit more then once per spell. If multiple class, treat value like items would. - if (!PassLimitClass(focus_spell.base[i], GetClass())) - return 0; - break; - - case SE_Ff_DurationMax: - if (focus_spell.base[i] > spell.buffduration) - return 0; - break; - - case SE_Ff_Endurance_Min: - if (spell.EndurCost < focus_spell.base[i]) - return 0; - break; - - case SE_Ff_Endurance_Max: - if (spell.EndurCost > focus_spell.base[i]) - return 0; - break; - - case SE_Ff_ReuseTimeMin: - if (spell.recast_time < focus_spell.base[i]) - return 0; - break; - - case SE_Ff_ReuseTimeMax: - if (spell.recast_time > focus_spell.base[i]) - return 0; - break; - - case SE_Ff_Value_Min: - index_id = GetSpellEffectIndex(spell_id, focus_spell.base2[i]); - if (index_id >= 0 && spell.base[index_id] < focus_spell.base[i]) - return 0; - break; - - case SE_Ff_Value_Max: - index_id = GetSpellEffectIndex(spell_id, focus_spell.base2[i]); - if (index_id >= 0 && spell.base[index_id] > focus_spell.base[i]) - return 0; - break; - - // handle effects - case SE_ImprovedDamage: - if (type == focusImprovedDamage) { - // This is used to determine which focus should be used for the random calculation - if (best_focus) { - // If the spell contains a value in the base2 field then that is the max value - if (focus_spell.base2[i] != 0) { - value = focus_spell.base2[i]; } - // If the spell does not contain a base2 value, then its a straight non random - // value - else { - value = focus_spell.base[i]; - } - } - // Actual focus calculation starts here - else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; - } else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); - } - } - break; - - case SE_ImprovedDamage2: - if (type == focusImprovedDamage2) { - if (best_focus) { - if (focus_spell.base2[i] != 0) { - value = focus_spell.base2[i]; - } - else { - value = focus_spell.base[i]; - } - } - else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; - } else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); - } - } - break; - - case SE_Fc_Amplify_Mod: - if (type == focusFcAmplifyMod && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_ImprovedHeal: - if (type == focusImprovedHeal) { - if (best_focus) { - if (focus_spell.base2[i] != 0) { - value = focus_spell.base2[i]; - } else { - value = focus_spell.base[i]; - } - } else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; - } else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); - } - } - break; - - case SE_ReduceManaCost: - if (type == focusManaCost) { - if (best_focus) { - if (focus_spell.base2[i] != 0) { - value = focus_spell.base2[i]; - } else { - value = focus_spell.base[i]; - } - } else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; - } else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); - } - } - break; - - case SE_IncreaseSpellHaste: - if (type == focusSpellHaste && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_Fc_CastTimeMod2: - if (type == focusFcCastTimeMod2 && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_Fc_CastTimeAmt: - if (type == focusFcCastTimeAmt && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_IncreaseSpellDuration: - if (type == focusSpellDuration && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_SpellDurationIncByTic: - if (type == focusSpellDurByTic && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_SwarmPetDuration: - if (type == focusSwarmPetDuration && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_IncreaseRange: - if (type == focusRange && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_ReduceReagentCost: - if (type == focusReagentCost && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_PetPowerIncrease: - if (type == focusPetPower && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_SpellResistReduction: - if (type == focusResistRate) { - if (best_focus) { - if (focus_spell.base2[i] != 0) { - value = focus_spell.base2[i]; - } else { - value = focus_spell.base[i]; - } - } else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; - } else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); - } - } - break; - - case SE_Fc_ResistIncoming: - if (type == focusFcResistIncoming && focus_spell.base[i] > value) - value = focus_spell.base[i]; - break; - - case SE_SpellHateMod: - if (type == focusSpellHateMod) { - if (value != 0) { - if (value > 0) { - if (focus_spell.base[i] > value) - value = focus_spell.base[i]; - } else { - if (focus_spell.base[i] < value) - value = focus_spell.base[i]; - } - } else - value = focus_spell.base[i]; - } - break; - - case SE_ReduceReuseTimer: - if (type == focusReduceRecastTime) - value = focus_spell.base[i] / 1000; - break; - - case SE_TriggerOnCast: - if (type == focusTriggerOnCast) { - if (zone->random.Roll(focus_spell.base[i])) - value = focus_spell.base2[i]; - else - value = 0; - } - break; - - case SE_BlockNextSpellFocus: - if (type == focusBlockNextSpell) { - if (zone->random.Roll(focus_spell.base[i])) - value = 1; - } - break; - - case SE_SympatheticProc: - if (type == focusSympatheticProc) { - value = focus_id; - } - break; - - case SE_FcSpellVulnerability: - if (type == focusSpellVulnerability) { - if (best_focus) { - if (focus_spell.base2[i] != 0) - value = focus_spell.base2[i]; //max damage - else - value = focus_spell.base[i]; //min damage - } else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; //If no max damage set, then default to min damage - } else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); //else random for value - } - } - break; - - case SE_Fc_Spell_Damage_Pct_IncomingPC: - if (type == focusFcSpellDamagePctIncomingPC) { - if (best_focus) { - if (focus_spell.base2[i] != 0) - value = focus_spell.base2[i]; //max damage - else - value = focus_spell.base[i]; //min damage - } - else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { - value = focus_spell.base[i]; //If no max damage set, then default to min damage } else { - value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); //else random for value + LimitInclude[0] = true; + if (spell.resisttype == focus_spell.base[i]) { // Include + LimitInclude[1] = true; + } } - } - break; + break; - case SE_FcTwincast: - if (type == focusTwincast && !IsEffectInSpell(spell_id, SE_TwinCastBlocker)) - value = focus_spell.base[i]; - break; - - case SE_FcDamageAmt: - if (type == focusFcDamageAmt) - value = focus_spell.base[i]; - break; - - case SE_FcDamageAmt2: - if (type == focusFcDamageAmt2) - value = focus_spell.base[i]; - break; - - case SE_Fc_Amplify_Amt: - if (type == focusFcAmplifyAmt) - value = focus_spell.base[i]; - break; - - case SE_FcDamageAmtCrit: - if (type == focusFcDamageAmtCrit) - value = focus_spell.base[i]; - break; - - case SE_FcDamageAmtIncoming: - if (type == focusFcDamageAmtIncoming) - value = focus_spell.base[i]; - break; - - case SE_Fc_Spell_Damage_Amt_IncomingPC: - if (type == focusFcSpellDamageAmtIncomingPC) - value = focus_spell.base[i]; - break; - - case SE_FcHealAmtIncoming: - if (type == focusFcHealAmtIncoming) - value = focus_spell.base[i]; - break; - - case SE_FcDamagePctCrit: - if (type == focusFcDamagePctCrit) - value = focus_spell.base[i]; - break; - - case SE_FcHealPctCritIncoming: - if (type == focusFcHealPctCritIncoming) - value = focus_spell.base[i]; - break; - - case SE_FcHealAmtCrit: - if (type == focusFcHealAmtCrit) - value = focus_spell.base[i]; - break; - - case SE_FcHealAmt: - if (type == focusFcHealAmt) - value = focus_spell.base[i]; - break; - - case SE_FcHealPctIncoming: - if (type == focusFcHealPctIncoming) - value = focus_spell.base[i]; - break; - - case SE_FcBaseEffects: - if (type == focusFcBaseEffects) - value = focus_spell.base[i]; - break; - - case SE_FcIncreaseNumHits: - if (type == focusIncreaseNumHits) - value = focus_spell.base[i]; - break; - - case SE_FcLimitUse: - if (type == focusFcLimitUse) - value = focus_spell.base[i]; - break; - - case SE_FcMute: - if (type == focusFcMute) - value = focus_spell.base[i]; - break; - - case SE_FcStunTimeMod: - if (type == focusFcStunTimeMod) - value = focus_spell.base[i]; - break; - - case SE_FcTimerRefresh: - if (type == focusFcTimerRefresh) - value = focus_spell.base[i]; - break; - - case SE_Fc_Cast_Spell_On_Land: - if (type == focusFcCastSpellOnLand) { - if (zone->random.Roll(focus_spell.base[i])) { - value = focus_spell.base2[i]; + case SE_LimitInstant: + if (focus_spell.base[i] == 1 && spell.buffduration) { // Fail if not instant + return 0; + } + if (focus_spell.base[i] == 0 && (spell.buffduration == 0)) { // Fail if instant + return 0; + } + + break; + + case SE_LimitMaxLevel: + if (IsNPC()) { + break; + } + spell_level = spell.classes[(GetClass() % 17) - 1]; + lvldiff = spell_level - focus_spell.base[i]; + // every level over cap reduces the effect by focus_spell.base2[i] percent unless from a clicky + // when ItemCastsUseFocus is true + if (lvldiff > 0 && (spell_level <= RuleI(Character, MaxLevel) || + RuleB(Character, ItemCastsUseFocus) == false)) { + if (focus_spell.base2[i] > 0) { + lvlModifier -= focus_spell.base2[i] * lvldiff; + if (lvlModifier < 1) { + return 0; + } + } + else { + return 0; + } + } + break; + + case SE_LimitMinLevel: + if (IsNPC()) { + break; + } + if (spell.classes[(GetClass() % 17) - 1] < focus_spell.base[i]) { + return (0); + } + break; + + case SE_LimitCastTimeMin: + if (spells[spell_id].cast_time < (uint16) focus_spell.base[i]) { + return (0); + } + break; + + case SE_LimitCastTimeMax: + if (spells[spell_id].cast_time > (uint16) focus_spell.base[i]) { + return (0); + } + break; + + case SE_LimitSpell: + if (focus_spell.base[i] < 0) { // Exclude + if (spell_id == -focus_spell.base[i]) { + return (0); + } + } + else { + LimitInclude[2] = true; + if (spell_id == focus_spell.base[i]) { // Include + LimitInclude[3] = true; + } + } + break; + + case SE_LimitMinDur: + if (focus_spell.base[i] > + CalcBuffDuration_formula(GetLevel(), spell.buffdurationformula, spell.buffduration)) { + return (0); + } + break; + + case SE_LimitEffect: + if (focus_spell.base[i] < 0) { + if (IsEffectInSpell(spell_id, -focus_spell.base[i])) { // Exclude + return 0; + } + } + else { + LimitInclude[4] = true; + if (IsEffectInSpell(spell_id, focus_spell.base[i])) { // Include + LimitInclude[5] = true; + } + } + break; + + case SE_LimitSpellType: + switch (focus_spell.base[i]) { + case 0: + if (!IsDetrimentalSpell(spell_id)) { + return 0; + } + break; + case 1: + if (!IsBeneficialSpell(spell_id)) { + return 0; + } + break; + default: + LogInfo("CalcFocusEffect: unknown limit spelltype [{}]", + focus_spell.base[i]); + } + break; + + case SE_LimitManaMin: + if (spell.mana < focus_spell.base[i]) { + return 0; + } + break; + + case SE_LimitManaMax: + if (spell.mana > focus_spell.base[i]) { + return 0; + } + break; + + case SE_LimitTarget: + if (focus_spell.base[i] < 0) { + if (-focus_spell.base[i] == spell.targettype) { // Exclude + return 0; + } + } + else { + LimitInclude[6] = true; + if (focus_spell.base[i] == spell.targettype) { // Include + LimitInclude[7] = true; + } + } + break; + + case SE_LimitCombatSkills: + if (focus_spell.base[i] == 0 && + (IsCombatSkill(spell_id) || IsCombatProc(spell_id))) { // Exclude Discs / Procs + return 0; + } + else if (focus_spell.base[i] == 1 && + (!IsCombatSkill(spell_id) || !IsCombatProc(spell_id))) { // Exclude Spells + return 0; + } + + break; + + case SE_LimitSpellGroup: + if (focus_spell.base[i] < 0) { + if (-focus_spell.base[i] == spell.spellgroup) { // Exclude + return 0; + } + } + else { + LimitInclude[8] = true; + if (focus_spell.base[i] == spell.spellgroup) { // Include + LimitInclude[9] = true; + } + } + break; + + case SE_LimitCastingSkill: + if (focus_spell.base[i] < 0) { + if (-focus_spell.base[i] == spell.skill) { + return 0; + } + } + else { + LimitInclude[10] = true; + if (focus_spell.base[i] == spell.skill) { + LimitInclude[11] = true; + } + } + break; + + case SE_LimitClass: + // Do not use this limit more then once per spell. If multiple class, treat value like items + // would. + if (!PassLimitClass(focus_spell.base[i], GetClass())) { + return 0; + } + break; + + case SE_LimitRace: + if (focus_spell.base[i] != GetRace()) { + return 0; + } + break; + + case SE_LimitUseMin: + if (focus_spell.base[i] > spell.numhits) { + return 0; + } + break; + + case SE_LimitUseType: + if (focus_spell.base[i] != spell.numhitstype) { + return 0; + } + break; + + case SE_CastonFocusEffect: + if (focus_spell.base[i] > 0) { + Caston_spell_id = focus_spell.base[i]; + } + break; + + case SE_LimitSpellClass: + if (focus_spell.base[i] < 0) { // Exclude + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) { + return (0); + } + } + else { + LimitInclude[12] = true; + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)) { // Include + LimitInclude[13] = true; + } + } + break; + + case SE_LimitSpellSubclass: + if (focus_spell.base[i] < 0) { // Exclude + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) { + return (0); + } + } + else { + LimitInclude[14] = true; + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)) { // Include + LimitInclude[15] = true; + } + } + break; + + case SE_Ff_Same_Caster://hmm do i need to pass casterid from buff slot here + if (focus_spell.base[i] == 0) { + if (casterid == GetID()) { + return 0; + }//Mob casting is same as target, fail if you are casting on yourself. + } + else if (focus_spell.base[i] == 1) { + if (casterid != GetID()) { + return 0; + }//Mob casting is not same as target, fail if you are not casting on yourself. + } + break; + + case SE_Ff_CasterClass: + // Do not use this limit more then once per spell. If multiple class, treat value like items would. + if (!PassLimitClass(focus_spell.base[i], GetClass())) { + return 0; + } + break; + + case SE_Ff_DurationMax: + if (focus_spell.base[i] > spell.buffduration) { + return 0; + } + break; + + case SE_Ff_Endurance_Min: + if (spell.EndurCost < focus_spell.base[i]) { + return 0; + } + break; + + case SE_Ff_Endurance_Max: + if (spell.EndurCost > focus_spell.base[i]) { + return 0; + } + break; + + case SE_Ff_ReuseTimeMin: + if (spell.recast_time < focus_spell.base[i]) { + return 0; + } + break; + + case SE_Ff_ReuseTimeMax: + if (spell.recast_time > focus_spell.base[i]) { + return 0; + } + break; + + case SE_Ff_Value_Min: + index_id = GetSpellEffectIndex(spell_id, focus_spell.base2[i]); + if (index_id >= 0 && spell.base[index_id] < focus_spell.base[i]) { + return 0; + } + break; + + case SE_Ff_Value_Max: + index_id = GetSpellEffectIndex(spell_id, focus_spell.base2[i]); + if (index_id >= 0 && spell.base[index_id] > focus_spell.base[i]) { + return 0; + } + break; + + // handle effects + case SE_ImprovedDamage: + if (type == focusImprovedDamage) { + // This is used to determine which focus should be used for the random calculation + if (best_focus) { + // If the spell contains a value in the base2 field then that is the max value + if (focus_spell.base2[i] != 0) { + value = focus_spell.base2[i]; + } + // If the spell does not contain a base2 value, then its a straight non random + // value + else { + value = focus_spell.base[i]; + } + } + // Actual focus calculation starts here + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + value = focus_spell.base[i]; + } + else { + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); + } + } + break; + + case SE_ImprovedDamage2: + if (type == focusImprovedDamage2) { + if (best_focus) { + if (focus_spell.base2[i] != 0) { + value = focus_spell.base2[i]; + } + else { + value = focus_spell.base[i]; + } + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + value = focus_spell.base[i]; + } + else { + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); + } + } + break; + + case SE_Fc_Amplify_Mod: + if (type == focusFcAmplifyMod && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_ImprovedHeal: + if (type == focusImprovedHeal) { + if (best_focus) { + if (focus_spell.base2[i] != 0) { + value = focus_spell.base2[i]; + } + else { + value = focus_spell.base[i]; + } + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + value = focus_spell.base[i]; + } + else { + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); + } + } + break; + + case SE_ReduceManaCost: + if (type == focusManaCost) { + if (best_focus) { + if (focus_spell.base2[i] != 0) { + value = focus_spell.base2[i]; + } + else { + value = focus_spell.base[i]; + } + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + value = focus_spell.base[i]; + } + else { + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); + } + } + break; + + case SE_IncreaseSpellHaste: + if (type == focusSpellHaste && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_Fc_CastTimeMod2: + if (type == focusFcCastTimeMod2 && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_Fc_CastTimeAmt: + if (type == focusFcCastTimeAmt && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_IncreaseSpellDuration: + if (type == focusSpellDuration && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_SpellDurationIncByTic: + if (type == focusSpellDurByTic && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_SwarmPetDuration: + if (type == focusSwarmPetDuration && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_IncreaseRange: + if (type == focusRange && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_ReduceReagentCost: + if (type == focusReagentCost && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_PetPowerIncrease: + if (type == focusPetPower && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_SpellResistReduction: + if (type == focusResistRate) { + if (best_focus) { + if (focus_spell.base2[i] != 0) { + value = focus_spell.base2[i]; + } + else { + value = focus_spell.base[i]; + } + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + value = focus_spell.base[i]; + } + else { + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); + } + } + break; + + case SE_Fc_ResistIncoming: + if (type == focusFcResistIncoming && focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + break; + + case SE_SpellHateMod: + if (type == focusSpellHateMod) { + if (value != 0) { + if (value > 0) { + if (focus_spell.base[i] > value) { + value = focus_spell.base[i]; + } + } + else { + if (focus_spell.base[i] < value) { + value = focus_spell.base[i]; + } + } + } + else { + value = focus_spell.base[i]; + } + } + break; + + case SE_ReduceReuseTimer: + if (type == focusReduceRecastTime) { + value = focus_spell.base[i] / 1000; + } + break; + + case SE_TriggerOnCast: + if (type == focusTriggerOnCast) { + if (zone->random.Roll(focus_spell.base[i])) { + value = focus_spell.base2[i]; + } + else { + value = 0; + } + } + break; + + case SE_BlockNextSpellFocus: + if (type == focusBlockNextSpell) { + if (zone->random.Roll(focus_spell.base[i])) { + value = 1; + } + } + break; + + case SE_SympatheticProc: + if (type == focusSympatheticProc) { + value = focus_id; + } + break; + + case SE_FcSpellVulnerability: + if (type == focusSpellVulnerability) { + if (best_focus) { + if (focus_spell.base2[i] != 0) { + value = focus_spell.base2[i]; //max damage + } + else { + value = focus_spell.base[i]; + } //min damage + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + value = focus_spell.base[i]; //If no max damage set, then default to min damage + } + else { + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); //else random for value + } + } + break; + + case SE_Fc_Spell_Damage_Pct_IncomingPC: + if (type == focusFcSpellDamagePctIncomingPC) { + if (best_focus) { + if (focus_spell.base2[i] != 0) { + value = focus_spell.base2[i]; //max damage + } + else { + value = focus_spell.base[i]; + } //min damage + } + else if (focus_spell.base2[i] == 0 || focus_spell.base[i] == focus_spell.base2[i]) { + value = focus_spell.base[i]; //If no max damage set, then default to min damage + } + else { + value = zone->random.Int(focus_spell.base[i], focus_spell.base2[i]); //else random for value + } + } + break; + + case SE_FcTwincast: + if (type == focusTwincast && !IsEffectInSpell(spell_id, SE_TwinCastBlocker)) { + value = focus_spell.base[i]; + } + break; + + case SE_FcDamageAmt: + if (type == focusFcDamageAmt) { + value = focus_spell.base[i]; + } + break; + + case SE_FcDamageAmt2: + if (type == focusFcDamageAmt2) { + value = focus_spell.base[i]; + } + break; + + case SE_Fc_Amplify_Amt: + if (type == focusFcAmplifyAmt) { + value = focus_spell.base[i]; + } + break; + + case SE_FcDamageAmtCrit: + if (type == focusFcDamageAmtCrit) { + value = focus_spell.base[i]; + } + break; + + case SE_FcDamageAmtIncoming: + if (type == focusFcDamageAmtIncoming) { + value = focus_spell.base[i]; + } + break; + + case SE_Fc_Spell_Damage_Amt_IncomingPC: + if (type == focusFcSpellDamageAmtIncomingPC) { + value = focus_spell.base[i]; + } + break; + + case SE_FcHealAmtIncoming: + if (type == focusFcHealAmtIncoming) { + value = focus_spell.base[i]; + } + break; + + case SE_FcDamagePctCrit: + if (type == focusFcDamagePctCrit) { + value = focus_spell.base[i]; + } + break; + + case SE_FcHealPctCritIncoming: + if (type == focusFcHealPctCritIncoming) { + value = focus_spell.base[i]; + } + break; + + case SE_FcHealAmtCrit: + if (type == focusFcHealAmtCrit) { + value = focus_spell.base[i]; + } + break; + + case SE_FcHealAmt: + if (type == focusFcHealAmt) { + value = focus_spell.base[i]; + } + break; + + case SE_FcHealPctIncoming: + if (type == focusFcHealPctIncoming) { + value = focus_spell.base[i]; + } + break; + + case SE_FcBaseEffects: + if (type == focusFcBaseEffects) { + value = focus_spell.base[i]; + } + break; + + case SE_FcIncreaseNumHits: + if (type == focusIncreaseNumHits) { + value = focus_spell.base[i]; + } + break; + + case SE_FcLimitUse: + if (type == focusFcLimitUse) { + value = focus_spell.base[i]; + } + break; + + case SE_FcMute: + if (type == focusFcMute) { + value = focus_spell.base[i]; + } + break; + + case SE_FcStunTimeMod: + if (type == focusFcStunTimeMod) { + value = focus_spell.base[i]; + } + break; + + case SE_FcTimerRefresh: + if (type == focusFcTimerRefresh) { + value = focus_spell.base[i]; + } + break; + + case SE_Fc_Cast_Spell_On_Land: + if (type == focusFcCastSpellOnLand) { + if (zone->random.Roll(focus_spell.base[i])) { + value = focus_spell.base2[i]; + } + break; } - break; - } #if EQDEBUG >= 6 - // this spits up a lot of garbage when calculating spell focuses - // since they have all kinds of extra effects on them. - default: - LogInfo("CalcFocusEffect: unknown effectid [{}]", - focus_spell.effectid[i]); + // this spits up a lot of garbage when calculating spell focuses + // since they have all kinds of extra effects on them. + default: + LogInfo("CalcFocusEffect: unknown effectid [{}]", + focus_spell.effectid[i]); #endif } } for (int e = 0; e < MaxLimitInclude; e += 2) { - if (LimitInclude[e] && !LimitInclude[e + 1]) + if (LimitInclude[e] && !LimitInclude[e + 1]) { return 0; + } } if (Caston_spell_id) { - if (IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id)) - SpellFinished(Caston_spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[Caston_spell_id].ResistDiff); + if (IsValidSpell(Caston_spell_id) && (Caston_spell_id != spell_id)) { + SpellFinished( + Caston_spell_id, + this, + EQ::spells::CastingSlot::Item, + 0, + -1, + spells[Caston_spell_id].ResistDiff + ); + } } return (value * lvlModifier / 100); @@ -7337,7 +7549,7 @@ void Mob::CastSpellOnLand(Mob* caster, uint32 spell_id) the CalcFocusEffect function if not 100pct. ApplyFocusProcLimiter() function checks for SE_Proc_Timer_Modifier which allows for limiting how often a spell from effect can be triggered for example, if set to base=1 and base2= 1500, then for everyone 1 successful trigger, you will be unable to trigger again for 1.5 seconds. - + Live only has this focus in buffs/debuffs that can be placed on a target. TODO: Will consider adding support for it as AA and Item. */ if (!caster) @@ -7371,7 +7583,7 @@ void Mob::CastSpellOnLand(Mob* caster, uint32 spell_id) SpellFinished(trigger_spell_id, current_target, EQ::spells::CastingSlot::Item, 0, -1, spells[trigger_spell_id].ResistDiff); } } - + if (i >= 0) CheckNumHitsRemaining(NumHit::MatchingSpells, i); } @@ -7387,13 +7599,13 @@ bool Mob::ApplyFocusProcLimiter(uint32 spell_id, int buffslot) //Do not allow spell cast if timer is active. if (buffs[buffslot].focusproclimit_time > 0) - return false; + return false; /* - SE_Proc_Timer_Modifier + SE_Proc_Timer_Modifier base1= amount of total procs allowed until lock out timer is triggered, should be set to at least 1 in any spell for the effect to function. base2= lock out timer, which prevents any more procs set in ms 1500 = 1.5 seconds - This system allows easy scaling for multiple different buffs with same effects each having seperate active individual timer checks. Ie. + This system allows easy scaling for multiple different buffs with same effects each having seperate active individual timer checks. Ie. */ if (IsValidSpell(spell_id)) { @@ -7420,7 +7632,7 @@ bool Mob::ApplyFocusProcLimiter(uint32 spell_id, int buffslot) if (!focus_proc_limit_timer.Enabled()) { focus_proc_limit_timer.Start(250); } - + return true; } }