From 6a962f25915ef1473729a5cbca76e4de5f30bfd7 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 12 Oct 2021 15:30:36 -0400 Subject: [PATCH] [Spells] Update SPA158 Reflect (#1590) * update * updates * updates * update * update * Update ruletypes.h * Apply extra spell dmg Mob with the reflect effect apply its Extra Spell Damage from item stat to the reflected spell. Updated portion of formula for extra damage based on live parsing. * correct formula --- common/ruletypes.h | 2 +- common/spdat.h | 11 +++- zone/bonuses.cpp | 28 +++++++-- zone/common.h | 5 +- zone/effects.cpp | 42 ++++++++++--- zone/lua_stat_bonuses.cpp | 2 +- zone/mob.cpp | 17 +----- zone/mob.h | 6 +- zone/special_attacks.cpp | 2 +- zone/spell_effects.cpp | 9 ++- zone/spells.cpp | 120 ++++++++++++++++++++++++-------------- 11 files changed, 164 insertions(+), 80 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 7f463e733..40682abcd 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -319,7 +319,7 @@ RULE_INT(Spells, MaxDiscSlotsNPC, 0, "Maximum number of NPC disc slots. NPC don' RULE_INT(Spells, MaxTotalSlotsNPC, 60, "Maximum total of NPC slots. The default value is the limit of the Titanium client") RULE_INT(Spells, MaxTotalSlotsPET, 30, "Maximum total of pet slots. The default value is the limit of the Titanium client") RULE_BOOL (Spells, EnableBlockedBuffs, true, "Allow blocked spells") -RULE_INT(Spells, ReflectType, 3, "Reflect type. 0=disabled, 1=single target player spells only, 2=all player spells, 3=all single target spells, 4=all spells") +RULE_INT(Spells, ReflectType, 4, "Reflect type. 0=disabled, 1=single target player spells only, 2=all player spells, 3=all single target spells, 4=all spells") RULE_BOOL(Spells, ReflectMessagesClose, true, "True (Live functionality) is for Reflect messages to show to players within close proximity. False shows just player reflecting") RULE_INT(Spells, VirusSpreadDistance, 30, "The distance a viral spell will jump to its next victim") RULE_BOOL(Spells, LiveLikeFocusEffects, true, "Determines whether specific healing, dmg and mana reduction focuses are randomized") diff --git a/common/spdat.h b/common/spdat.h index 509170000..ebd39eed4 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -511,6 +511,15 @@ enum NegateSpellEffectType NEGATE_SPA_SPELLBONUS_AND_AABONUS = 5, NEGATE_SPA_ITEMBONUS_AND_AABONUS = 6, }; +//Used for rule RuleI(Spells, ReflectType)) +enum ReflectSpellType +{ + REFLECT_DISABLED = 0, + REFLECT_SINGLE_TARGET_SPELLS_ONLY = 1, + REFLECT_ALL_PLAYER_SPELLS = 2, + RELFECT_ALL_SINGLE_TARGET_SPELLS = 3, + REFLECT_ALL_SPELLS = 4, +}; enum SpellTypes : uint32 { @@ -843,7 +852,7 @@ typedef enum { #define SE_SpellCritDmgIncrease 155 // implemented - no known live spells use this currently #define SE_IllusionCopy 156 // implemented - Deception #define SE_SpellDamageShield 157 // implemented, @DS, causes non-melee damage on caster of a spell, base: Amt DS (negative), limit: none, max: unknown (same as base but +) -#define SE_Reflect 158 // implemented +#define SE_Reflect 158 // implemented, @SpellMisc, reflect casted detrimental spell back at caster, base: chance pct, limit: resist modifier (positive value reduces resists), max: pct of base dmg mod (50=50pct of base) #define SE_AllStats 159 // implemented //#define SE_MakeDrunk 160 // *not implemented - Effect works entirely client side (Should check against tolerance) #define SE_MitigateSpellDamage 161 // implemented - rune with max value diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 9a640196a..e56de4daf 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1672,6 +1672,17 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) newbon->ZoneSuspendMinion = base1; break; + + case SE_Reflect: + + if (newbon->reflect[SBIndex::REFLECT_CHANCE] < base1) { + newbon->reflect[SBIndex::REFLECT_CHANCE] = base1; + } + if (newbon->reflect[SBIndex::REFLECT_RESISTANCE_MOD] < base2) { + newbon->reflect[SBIndex::REFLECT_RESISTANCE_MOD] = base2; + } + break; + case SE_SpellDamageShield: newbon->SpellDamageShield += base1; break; @@ -2152,7 +2163,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne } case SE_Reflect: - new_bonus->reflect_chance += effect_value; + + if (AdditiveWornBonus) { + new_bonus->reflect[SBIndex::REFLECT_CHANCE] += effect_value; + } + + else if (new_bonus->reflect[SBIndex::REFLECT_CHANCE] < effect_value) { + new_bonus->reflect[SBIndex::REFLECT_CHANCE] = effect_value; + new_bonus->reflect[SBIndex::REFLECT_RESISTANCE_MOD] = base2; + new_bonus->reflect[SBIndex::REFLECT_DMG_EFFECTIVENESS] = max; + } break; case SE_Amplification: @@ -4381,9 +4401,9 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id) break; case SE_Reflect: - if (negate_spellbonus) { spellbonuses.reflect_chance = effect_value; } - if (negate_aabonus) { aabonuses.reflect_chance = effect_value; } - if (negate_itembonus) { itembonuses.reflect_chance = effect_value; } + if (negate_spellbonus) { spellbonuses.reflect[SBIndex::REFLECT_CHANCE] = effect_value; } + if (negate_aabonus) { aabonuses.reflect[SBIndex::REFLECT_CHANCE] = effect_value; } + if (negate_itembonus) { itembonuses.reflect[SBIndex::REFLECT_CHANCE] = effect_value; } break; case SE_Amplification: diff --git a/zone/common.h b/zone/common.h index 4c5bfa4df..937cffc51 100644 --- a/zone/common.h +++ b/zone/common.h @@ -404,7 +404,7 @@ struct StatBonuses { int32 skillmodmax[EQ::skills::HIGHEST_SKILL + 1]; int effective_casting_level; int adjusted_casting_skill; // SPA 112 for fizzles - int reflect_chance; // chance to reflect incoming spell + int reflect[3]; // chance to reflect incoming spell [0]=Chance [1]=Resist Mod [2]= % of Base Dmg uint32 singingMod; uint32 Amplification; // stacks with singingMod uint32 brassMod; @@ -680,6 +680,9 @@ namespace SBIndex { constexpr uint16 FINISHING_EFFECT_LEVEL_CHANCE_BONUS = 1; // SPA 440, 345, 346 constexpr uint16 DOUBLE_MELEE_ROUND_CHANCE = 0; // SPA 471 constexpr uint16 DOUBLE_MELEE_ROUND_DMG_BONUS = 1; // SPA 471 + constexpr uint16 REFLECT_CHANCE = 0; // SPA 158 + constexpr uint16 REFLECT_RESISTANCE_MOD = 1; // SPA 158 + constexpr uint16 REFLECT_DMG_EFFECTIVENESS = 2; // SPA 158 }; diff --git a/zone/effects.cpp b/zone/effects.cpp index b7319e793..4180d774c 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -117,10 +117,10 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcAmplifyAmt, spell_id); if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) - value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio / 100; + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value_BaseEffect)*ratio / 100; else if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) - value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value_BaseEffect)*ratio/100; else if (IsNPC() && CastToNPC()->GetSpellScale()) value = int(static_cast(value) * CastToNPC()->GetSpellScale() / 100.0f); @@ -156,10 +156,10 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { value -= GetFocusEffect(focusFcAmplifyAmt, spell_id); if (RuleB(Spells, IgnoreSpellDmgLvlRestriction) && !spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) - value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value_BaseEffect); else if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass() % 17) - 1] >= GetLevel() - 5) - value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value_BaseEffect); if (IsNPC() && CastToNPC()->GetSpellScale()) value = int(static_cast(value) * CastToNPC()->GetSpellScale() / 100.0f); @@ -167,6 +167,33 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { return value; } +int32 Mob::GetActReflectedSpellDamage(int32 spell_id, int32 value, int effectiveness) { + /* + Reflected spells use the spells base damage before any modifiers or formulas applied. + That value can then be modifier by the reflect spells 'max' value, defined here as effectiveness + Default effectiveness is set at 100. + Extra Spell Damage stat from the with the reflect effect will be applied to reflected damage + with no level limitation, this was confirmed with extensive parsing ~Kayen + */ + if (IsNPC()) { + value += value * CastToNPC()->GetSpellFocusDMG() / 100; + + if (CastToNPC()->GetSpellScale()) { + value = int(static_cast(value) * CastToNPC()->GetSpellScale() / 100.0f); + } + } + + int32 base_spell_dmg = value; + + value = value * effectiveness / 100; + + if (!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg) { + value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, base_spell_dmg); + } + + return value; +} + int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) { if (target == nullptr) @@ -259,8 +286,9 @@ int32 Mob::GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_s else extra_spell_amt = extra_spell_amt * total_cast_time / 7000; + //Confirmed with parsing 10/9/21 ~Kayen if (extra_spell_amt * 2 > abs(base_spell_dmg)) { - return 0; + extra_spell_amt = abs(base_spell_dmg) / 2; } return extra_spell_amt; @@ -324,7 +352,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) { 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 + value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value_BaseEffect); //Item Heal Amt Add before critical } if (target) { @@ -1020,7 +1048,7 @@ void EntityList::AESpell( } current_mob->CalcSpellPowerDistanceMod(spell_id, distance_to_target); - caster_mob->SpellOnTarget(spell_id, current_mob, false, true, resist_adjust); + caster_mob->SpellOnTarget(spell_id, current_mob, 0, true, resist_adjust); /** * Increment hit count if max targets diff --git a/zone/lua_stat_bonuses.cpp b/zone/lua_stat_bonuses.cpp index 40805d648..156a320f9 100644 --- a/zone/lua_stat_bonuses.cpp +++ b/zone/lua_stat_bonuses.cpp @@ -342,7 +342,7 @@ int Lua_StatBonuses::Getadjusted_casting_skill() const { int Lua_StatBonuses::Getreflect_chance() const { Lua_Safe_Call_Int(); - return self->reflect_chance; + return self->reflect[SBIndex::REFLECT_CHANCE]; } uint32 Lua_StatBonuses::GetsingingMod() const { diff --git a/zone/mob.cpp b/zone/mob.cpp index d1c6ced3d..f0982115c 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3214,12 +3214,12 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on, if (IsBeneficialSpell(spell_id) && (!IsNPC() || (IsNPC() && CastToNPC()->GetInnateProcSpellID() != spell_id))) { // NPC innate procs don't take this path ever SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff, true, level_override); if(twinproc) - SpellOnTarget(spell_id, this, false, false, 0, true, level_override); + SpellOnTarget(spell_id, this, 0, false, 0, true, level_override); } else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients SpellFinished(spell_id, on, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].ResistDiff, true, level_override); if(twinproc) - SpellOnTarget(spell_id, on, false, false, 0, true, level_override); + SpellOnTarget(spell_id, on, 0, false, 0, true, level_override); } return; } @@ -4596,19 +4596,6 @@ bool Mob::TryDoubleMeleeRoundEffect() { return false; } -bool Mob::TryReflectSpell(uint32 spell_id) -{ - if (!spells[spell_id].reflectable) - return false; - - int chance = itembonuses.reflect_chance + spellbonuses.reflect_chance + aabonuses.reflect_chance; - - if(chance && zone->random.Roll(chance)) - return true; - - return false; -} - void Mob::DoGravityEffect() { Mob *caster = nullptr; diff --git a/zone/mob.h b/zone/mob.h index b9e3bfd85..3d207ee26 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -306,6 +306,7 @@ public: virtual int32 GetActSpellCost(uint16 spell_id, int32 cost){ return cost;} virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration); virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime); + virtual int32 GetActReflectedSpellDamage(int32 spell_id, int32 value, int effectiveness); float ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use_resist_override = false, int resist_override = 0, bool CharismaCheck = false, bool CharmTick = false, bool IsRoot = false, int level_override = -1); @@ -331,9 +332,9 @@ public: bool SpellFinished(uint16 spell_id, Mob *target, EQ::spells::CastingSlot slot = EQ::spells::CastingSlot::Item, uint16 mana_used = 0, uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1); void SendBeginCast(uint16 spell_id, uint32 casttime); - virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect = false, + virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, int reflect_effectiveness = 0, bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1); - virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1); + virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1, int reflect_effectiveness = 0); virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction, EQ::spells::CastingSlot slot, bool isproc = false); virtual bool CheckFizzle(uint16 spell_id); @@ -827,7 +828,6 @@ public: int GetCriticalChanceBonus(uint16 skill); int16 GetSkillDmgAmt(uint16 skill); int16 GetPositionalDmgAmt(Mob* defender); - bool TryReflectSpell(uint32 spell_id); inline bool CanBlockSpell() const { return(spellbonuses.FocusEffects[focusBlockNextSpell]); } bool DoHPToManaCovert(uint16 mana_cost = 0); int32 ApplySpellEffectiveness(int16 spell_id, int32 value, bool IsBard = false, uint16 caster_id=0); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 4d614731a..1aa87288c 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -2043,7 +2043,7 @@ void Mob::InstillDoubt(Mob *who) { //temporary hack... //cast fear on them... should prolly be a different spell //and should be un-resistable. - SpellOnTarget(229, who, false, true, -2000); + SpellOnTarget(229, who, 0, true, -2000); //is there a success message? } else { MessageString(Chat::LightBlue,NOT_SCARING); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 088d4b2a2..5caab6d0d 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -46,7 +46,7 @@ extern WorldServer worldserver; // the spell can still fail here, if the buff can't stack // in this case false will be returned, true otherwise -bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_override) +bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_override, int reflect_effectiveness) { int caster_level, buffslot, effect, effect_value, i; EQ::ItemInstance *SummonedItem=nullptr; @@ -259,7 +259,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove //handles AAs and what not... if(caster) { - dmg = caster->GetActSpellDamage(spell_id, dmg, this); + if (reflect_effectiveness) { + dmg = caster->GetActReflectedSpellDamage(spell_id, (int32)(spells[spell_id].base[i] * partial / 100), reflect_effectiveness); + } + else { + dmg = caster->GetActSpellDamage(spell_id, dmg, this); + } caster->ResourceTap(-dmg, spell_id); } diff --git a/zone/spells.cpp b/zone/spells.cpp index 97caa49c7..b7affc35f 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2274,14 +2274,14 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, CastingSlot slot, ui return(false); } if (isproc) { - SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, true, level_override); + SpellOnTarget(spell_id, spell_target, 0, true, resist_adjust, true, level_override); } else { if (spells[spell_id].targettype == ST_TargetOptional){ if (!TrySpellProjectile(spell_target, spell_id)) return false; } - else if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false, level_override)) { + else if(!SpellOnTarget(spell_id, spell_target, 0, true, resist_adjust, false, level_override)) { if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) { // Prevent mana usage/timers being set for beneficial buffs if(casting_spell_aa_id) @@ -3513,7 +3513,7 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite) // and if you don't want effects just return false. interrupting here will // break stuff // -bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_resist_adjust, int16 resist_adjust, +bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, int reflect_effectiveness, bool use_resist_adjust, int16 resist_adjust, bool isproc, int level_override) { @@ -3641,7 +3641,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r parse->EventPlayer(EVENT_CAST_ON, spelltar->CastToClient(),temp1, 0); } - mod_spell_cast(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc); + mod_spell_cast(spell_id, spelltar, reflect_effectiveness, use_resist_adjust, resist_adjust, isproc); // now check if the spell is allowed to land if (RuleB(Spells, EnableBlockedBuffs)) { @@ -3860,69 +3860,101 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r } } } - // Reflect - if(spelltar && spelltar->TryReflectSpell(spell_id) && !reflect && IsDetrimentalSpell(spell_id) && this != spelltar) { - int reflect_chance = 0; + /* + Reflect + base= % Chance to Reflect + Limit= Resist Modifier (+Value for decrease chance to resist) + Max= % of base spell damage (this is the base before any formula or focus is applied) + On live any type of detrimental spell can be reflected as long as the Reflectable spell field is set, this includes AOE. + The 'caster' of the reflected spell is owner of the reflect effect. Caster's focus effects are NOT applied to reflected spell. + + reflect_effectiveness is applied to damage spells, a value of 100 is no change to base damage. Other values change by percent. (50=50% of damage) + we this variable to both check if a spell being applied is from a reflection and for the damage modifier. + + There are a few spells in database that are not detrimental that have Reflectable field set, however from testing, they do not actually reflect. + */ + if(spells[spell_id].reflectable && !reflect_effectiveness && spelltar && this != spelltar && IsDetrimentalSpell(spell_id) && + (spelltar->spellbonuses.reflect[SBIndex::REFLECT_CHANCE] || spelltar->aabonuses.reflect[SBIndex::REFLECT_CHANCE] || spelltar->itembonuses.reflect[SBIndex::REFLECT_CHANCE])) { + bool can_spell_reflect = false; switch(RuleI(Spells, ReflectType)) { - case 0: + case REFLECT_DISABLED: break; - case 1: + case REFLECT_SINGLE_TARGET_SPELLS_ONLY: { if(spells[spell_id].targettype == ST_Target) { for(int y = 0; y < 16; y++) { - if(spells[spell_id].classes[y] < 255) - reflect_chance = 1; + if (spells[spell_id].classes[y] < 255) { + can_spell_reflect = true; + } } } break; } - case 2: + case REFLECT_ALL_PLAYER_SPELLS: { for(int y = 0; y < 16; y++) { - if(spells[spell_id].classes[y] < 255) - reflect_chance = 1; + if (spells[spell_id].classes[y] < 255) { + can_spell_reflect = true; + } } break; } - case 3: + case RELFECT_ALL_SINGLE_TARGET_SPELLS: { - if(spells[spell_id].targettype == ST_Target) - reflect_chance = 1; - + if (spells[spell_id].targettype == ST_Target) { + can_spell_reflect = true; + } break; } - case 4: - reflect_chance = 1; + case REFLECT_ALL_SPELLS: //This is live like behavior + can_spell_reflect = true; default: break; } - if (reflect_chance) { + if (can_spell_reflect) { - if (RuleB(Spells, ReflectMessagesClose)) { - entity_list.MessageCloseString( - this, /* Sender */ - false, /* Skip Sender */ - RuleI(Range, SpellMessages), /* Range */ - Chat::Spells, /* Type */ - SPELL_REFLECT, /* String ID */ - GetCleanName(), /* Message 1 */ - spelltar->GetCleanName() /* Message 2 */ - ); + int reflect_resist_adjust = 0; + int reflect_effectiveness_mod = 0; //Need value of 100 to do baseline unmodified damage. + + if (spelltar->spellbonuses.reflect[SBIndex::REFLECT_CHANCE] && zone->random.Roll(spelltar->spellbonuses.reflect[SBIndex::REFLECT_CHANCE])) { + reflect_resist_adjust = spelltar->spellbonuses.reflect[SBIndex::REFLECT_RESISTANCE_MOD]; + reflect_effectiveness_mod = spelltar->spellbonuses.reflect[SBIndex::REFLECT_DMG_EFFECTIVENESS] ? spelltar->spellbonuses.reflect[SBIndex::REFLECT_DMG_EFFECTIVENESS] : 100; } - else { - MessageString(Chat::Spells, SPELL_REFLECT, GetCleanName(), spelltar->GetCleanName()); + else if (spelltar->aabonuses.reflect[SBIndex::REFLECT_CHANCE] && zone->random.Roll(spelltar->aabonuses.reflect[SBIndex::REFLECT_CHANCE])) { + reflect_effectiveness_mod = 100; + reflect_resist_adjust = spelltar->aabonuses.reflect[SBIndex::REFLECT_RESISTANCE_MOD]; + } + else if (spelltar->itembonuses.reflect[SBIndex::REFLECT_CHANCE] && zone->random.Roll(spelltar->itembonuses.reflect[SBIndex::REFLECT_CHANCE])) { + reflect_resist_adjust = spelltar->itembonuses.reflect[SBIndex::REFLECT_RESISTANCE_MOD]; + reflect_effectiveness_mod = spelltar->itembonuses.reflect[SBIndex::REFLECT_DMG_EFFECTIVENESS] ? spelltar->itembonuses.reflect[SBIndex::REFLECT_DMG_EFFECTIVENESS] : 100; } - CheckNumHitsRemaining(NumHit::ReflectSpell); - // caster actually appears to change - // ex. During OMM fight you click your reflect mask and you get the recourse from the reflected - // spell - spelltar->SpellOnTarget(spell_id, this, true, use_resist_adjust, resist_adjust); - safe_delete(action_packet); - return false; + if (reflect_effectiveness_mod) { + + if (RuleB(Spells, ReflectMessagesClose)) { + entity_list.MessageCloseString( + this, /* Sender */ + false, /* Skip Sender */ + RuleI(Range, SpellMessages), /* Range */ + Chat::Spells, /* Type */ + SPELL_REFLECT, /* String ID */ + GetCleanName(), /* Message 1 */ + spelltar->GetCleanName() /* Message 2 */ + ); + } + else { + MessageString(Chat::Spells, SPELL_REFLECT, GetCleanName(), spelltar->GetCleanName()); + } + + CheckNumHitsRemaining(NumHit::ReflectSpell); + + spelltar->SpellOnTarget(spell_id, this, reflect_effectiveness_mod, use_resist_adjust, (resist_adjust - reflect_resist_adjust)); + safe_delete(action_packet); + return false; + } } } @@ -4022,7 +4054,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r } // cause the effects to the target - if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness, level_override)) + if(!spelltar->SpellEffect(this, spell_id, spell_effectiveness, level_override, reflect_effectiveness)) { // if SpellEffect returned false there's a problem applying the // spell. It's most likely a buff that can't stack. @@ -6071,7 +6103,7 @@ void Mob::BeamDirectional(uint16 spell_id, int16 resist_adjust) if (d <= spells[spell_id].aoerange) { if (CheckLosFN((*iter)) || spells[spell_id].npc_no_los) { (*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this); - SpellOnTarget(spell_id, (*iter), false, true, resist_adjust); + SpellOnTarget(spell_id, (*iter), 0, true, resist_adjust); maxtarget_count++; } @@ -6145,7 +6177,7 @@ void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust) (heading_to_target >= 0.0f && heading_to_target <= angle_end)) { if (CheckLosFN((*iter)) || spells[spell_id].npc_no_los) { (*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this); - SpellOnTarget(spell_id, (*iter), false, true, resist_adjust); + SpellOnTarget(spell_id, (*iter), 0, true, resist_adjust); maxtarget_count++; } } @@ -6153,7 +6185,7 @@ void Mob::ConeDirectional(uint16 spell_id, int16 resist_adjust) if (heading_to_target >= angle_start && heading_to_target <= angle_end) { if (CheckLosFN((*iter)) || spells[spell_id].npc_no_los) { (*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this); - SpellOnTarget(spell_id, (*iter), false, true, resist_adjust); + SpellOnTarget(spell_id, (*iter), 0, true, resist_adjust); maxtarget_count++; } }