diff --git a/src/game/Player.cpp b/src/game/Player.cpp index f293a4d5e..e87c39a34 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -271,26 +271,6 @@ std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi) ss << taxi.m_taximask[i] << " "; return ss; } - -SpellModifier::SpellModifier( SpellModOp _op, SpellModType _type, int32 _value, SpellEntry const* spellEntry, SpellEffectIndex eff, int16 _charges /*= 0*/ ) : op(_op), type(_type), charges(_charges), value(_value), spellId(spellEntry->Id), lastAffected(NULL) -{ - mask = spellEntry->GetEffectSpellClassMask(eff); -} - -SpellModifier::SpellModifier( SpellModOp _op, SpellModType _type, int32 _value, Aura const* aura, int16 _charges /*= 0*/ ) : op(_op), type(_type), charges(_charges), value(_value), spellId(aura->GetId()), lastAffected(NULL) -{ - mask = aura->GetAuraSpellClassMask(); -} - -bool SpellModifier::isAffectedOnSpell( SpellEntry const *spell ) const -{ - SpellEntry const *affect_spell = sSpellStore.LookupEntry(spellId); - // False if affect_spell == NULL or spellFamily not equal - if (!affect_spell || affect_spell->SpellFamilyName != spell->SpellFamilyName) - return false; - return spell->IsFitToFamilyMask(mask); -} - //== TradeData ================================================= TradeData* TradeData::GetTraderData() const @@ -439,8 +419,6 @@ Player::Player (WorldSession *session): Unit(), m_mover(this), m_camera(this), m clearResurrectRequestData(); - m_SpellModRemoveCount = 0; - memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT); m_social = NULL; @@ -18600,29 +18578,10 @@ void Player::RemovePetActionBar() SendDirectMessage(&data); } -bool Player::IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell) +void Player::AddSpellMod(Aura* aura, bool apply) { - if (!mod || !spellInfo) - return false; - - if(mod->charges == -1 && mod->lastAffected ) // marked as expired but locked until spell casting finish - { - // prevent apply to any spell except spell that trigger expire - if(spell) - { - if(mod->lastAffected != spell) - return false; - } - else if(mod->lastAffected != FindCurrentSpellBySpellId(spellInfo->Id)) - return false; - } - - return mod->isAffectedOnSpell(spellInfo); -} - -void Player::AddSpellMod(SpellModifier* mod, bool apply) -{ - uint16 Opcode= (mod->type == SPELLMOD_FLAT) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; + Modifier const* mod = aura->GetModifier(); + uint16 Opcode= (mod->m_auraname == SPELL_AURA_ADD_FLAT_MODIFIER) ? SMSG_SET_FLAT_SPELL_MODIFIER : SMSG_SET_PCT_SPELL_MODIFIER; for(int eff = 0; eff < 96; ++eff) { @@ -18634,81 +18593,27 @@ void Player::AddSpellMod(SpellModifier* mod, bool apply) else _mask2= uint32(1) << (eff - 64); - if (mod->mask.IsFitToFamilyMask(_mask, _mask2)) + if (aura->GetSpellProto()->IsFitToFamilyMask(_mask, _mask2)) { int32 val = 0; - for (SpellModList::const_iterator itr = m_spellMods[mod->op].begin(); itr != m_spellMods[mod->op].end(); ++itr) + for (AuraList::const_iterator itr = m_spellMods[mod->m_miscvalue].begin(); itr != m_spellMods[mod->m_miscvalue].end(); ++itr) { - if ((*itr)->type == mod->type && ((*itr)->mask.IsFitToFamilyMask(_mask, _mask2))) - val += (*itr)->value; + if ((*itr)->GetModifier()->m_auraname == mod->m_auraname && ((*itr)->GetSpellProto()->IsFitToFamilyMask(_mask, _mask2))) + val += (*itr)->GetModifier()->m_amount; } - val += apply ? mod->value : -(mod->value); + val += apply ? mod->m_amount : -(mod->m_amount); WorldPacket data(Opcode, (1+1+4)); data << uint8(eff); - data << uint8(mod->op); + data << uint8(mod->m_miscvalue); data << int32(val); SendDirectMessage(&data); } } if (apply) - m_spellMods[mod->op].push_back(mod); + m_spellMods[mod->m_miscvalue].push_back(aura); else - { - if (mod->charges == -1) - --m_SpellModRemoveCount; - m_spellMods[mod->op].remove(mod); - delete mod; - } -} - -void Player::RemoveSpellMods(Spell const* spell) -{ - if (!spell || (m_SpellModRemoveCount == 0)) - return; - - for(int i = 0; i < MAX_SPELLMOD; ++i) - { - for (SpellModList::const_iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end();) - { - SpellModifier *mod = *itr; - ++itr; - - if (mod && mod->charges == -1 && (mod->lastAffected == spell || mod->lastAffected==NULL)) - { - RemoveAurasDueToSpell(mod->spellId); - if (m_spellMods[i].empty()) - break; - else - itr = m_spellMods[i].begin(); - } - } - } -} - -void Player::ResetSpellModsDueToCanceledSpell (Spell const* spell) -{ - for(int i = 0; i < MAX_SPELLMOD; ++i ) - { - for (SpellModList::const_iterator itr = m_spellMods[i].begin(); itr != m_spellMods[i].end(); ++itr) - { - SpellModifier *mod = *itr; - - if (mod->lastAffected != spell) - continue; - - mod->lastAffected = NULL; - - if (mod->charges == -1) - { - mod->charges = 1; - if (m_SpellModRemoveCount > 0) - --m_SpellModRemoveCount; - } - else if (mod->charges > 0) - ++mod->charges; - } - } + m_spellMods[mod->m_miscvalue].remove(aura); } // send Proficiency diff --git a/src/game/Player.h b/src/game/Player.h index e53c233c8..0b5a80b48 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -38,6 +38,7 @@ #include "BattleGround.h" #include "DBCStores.h" #include "SharedDefines.h" +#include "SpellAuras.h" #include #include @@ -114,36 +115,6 @@ struct PlayerTalent typedef UNORDERED_MAP PlayerSpellMap; typedef UNORDERED_MAP PlayerTalentMap; -// Spell modifier (used for modify other spells) -struct SpellModifier -{ - SpellModifier() : charges(0), lastAffected(NULL) {} - - SpellModifier(SpellModOp _op, SpellModType _type, int32 _value, uint32 _spellId, uint64 _mask, uint32 _mask2 = 0, int16 _charges = 0) - : op(_op), type(_type), charges(_charges), value(_value), mask(_mask, _mask2), spellId(_spellId), lastAffected(NULL) - {} - - SpellModifier(SpellModOp _op, SpellModType _type, int32 _value, uint32 _spellId, ClassFamilyMask _mask, int16 _charges = 0) - : op(_op), type(_type), charges(_charges), value(_value), mask(_mask), spellId(_spellId), lastAffected(NULL) - {} - - SpellModifier(SpellModOp _op, SpellModType _type, int32 _value, SpellEntry const* spellEntry, SpellEffectIndex eff, int16 _charges = 0); - - SpellModifier(SpellModOp _op, SpellModType _type, int32 _value, Aura const* aura, int16 _charges = 0); - - bool isAffectedOnSpell(SpellEntry const *spell) const; - - SpellModOp op : 8; - SpellModType type : 8; - int16 charges : 16; - int32 value; - ClassFamilyMask mask; - uint32 spellId; - Spell const* lastAffected; // mark last charge user, used for cleanup delayed remove spellmods at spell success or restore charges at cast fail (Is one pointer only need for cases mixed castes?) -}; - -typedef std::list SpellModList; - struct SpellCooldown { time_t end; @@ -1643,11 +1614,8 @@ class MANGOS_DLL_SPEC Player : public Unit PlayerTalent const* GetKnownTalentById(int32 talentId) const; SpellEntry const* GetKnownTalentRankById(int32 talentId) const; - void AddSpellMod(SpellModifier* mod, bool apply); - bool IsAffectedBySpellmod(SpellEntry const *spellInfo, SpellModifier *mod, Spell const* spell = NULL); + void AddSpellMod(Aura* aura, bool apply); template T ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell const* spell = NULL); - void RemoveSpellMods(Spell const* spell); - void ResetSpellModsDueToCanceledSpell (Spell const* spell); static uint32 const infinityCooldownDelay = MONTH; // used for set "infinity cooldowns" for spells and check static uint32 const infinityCooldownDelayCheck = MONTH/2; @@ -2500,8 +2468,7 @@ class MANGOS_DLL_SPEC Player : public Unit float m_armorPenetrationPct; int32 m_spellPenetrationItemMod; - SpellModList m_spellMods[MAX_SPELLMOD]; - int32 m_SpellModRemoveCount; + AuraList m_spellMods[MAX_SPELLMOD]; EnchantDurationList m_enchantDuration; ItemDurationList m_itemDuration; @@ -2672,45 +2639,28 @@ template T Player::ApplySpellMod(uint32 spellId, SpellModOp op, T &bas if (!spellInfo) return 0; int32 totalpct = 0; int32 totalflat = 0; - for (SpellModList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr) + for (AuraList::iterator itr = m_spellMods[op].begin(); itr != m_spellMods[op].end(); ++itr) { - SpellModifier *mod = *itr; + Aura *aura = *itr; + + Modifier const* mod = aura->GetModifier(); - if(!IsAffectedBySpellmod(spellInfo,mod,spell)) + if (!aura->isAffectedOnSpell(spellInfo)) continue; - if (mod->type == SPELLMOD_FLAT) - totalflat += mod->value; - else if (mod->type == SPELLMOD_PCT) + + if (mod->m_auraname == SPELL_AURA_ADD_FLAT_MODIFIER) + totalflat += mod->m_amount; + else { // skip percent mods for null basevalue (most important for spell mods with charges ) - if(basevalue == T(0)) + if (basevalue == T(0)) continue; // special case (skip >10sec spell casts for instant cast setting) - if( mod->op==SPELLMOD_CASTING_TIME && basevalue >= T(10*IN_MILLISECONDS) && mod->value <= -100) + if (mod->m_miscvalue == SPELLMOD_CASTING_TIME && basevalue >= T(10*IN_MILLISECONDS) && mod->m_amount <= -100) continue; - totalpct += mod->value; - } - - if (mod->charges > 0) - { - if (!spell) - spell = FindCurrentSpellBySpellId(spellId); - - // avoid double use spellmod charge by same spell - if (!mod->lastAffected || mod->lastAffected != spell) - { - --mod->charges; - - if (mod->charges == 0) - { - mod->charges = -1; - ++m_SpellModRemoveCount; - } - - mod->lastAffected = spell; - } + totalpct += mod->m_amount; } } diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index fb770fcbe..44ca55b51 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -3216,9 +3216,17 @@ void Spell::cast(bool skipCheck) m_immediateHandled = false; m_spellState = SPELL_STATE_DELAYED; SetDelayStart(0); + + // on spell cast end proc, + // critical hit related part is currently done on hit so proc there, + // 0 damage since any damage based procs should be on hit + // 0 victim proc since there is no victim proc dependent on successfull cast for caster + m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), m_procAttacker, 0, PROC_EX_NORMAL_HIT, 0, m_attackType, m_spellInfo); } else { + m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), m_procAttacker, 0, PROC_EX_NORMAL_HIT, 0, m_attackType, m_spellInfo); + // Immediate spell, no big deal handle_immediate(); } @@ -3500,18 +3508,8 @@ void Spell::finish(bool ok) if (m_spellState == SPELL_STATE_FINISHED) return; - // remove/restore spell mods before m_spellState update - if (Player* modOwner = m_caster->GetSpellModOwner()) - { - if (ok || m_spellState != SPELL_STATE_PREPARING) // fail after start channeling or throw to target not affect spell mods - modOwner->RemoveSpellMods(this); - else - modOwner->ResetSpellModsDueToCanceledSpell(this); - } - m_spellState = SPELL_STATE_FINISHED; - // other code related only to successfully finished spells if (!ok) return; diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index b2275266a..62ae37197 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -372,7 +372,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]= static AuraType const frozenAuraTypes[] = { SPELL_AURA_MOD_ROOT, SPELL_AURA_MOD_STUN, SPELL_AURA_NONE }; Aura::Aura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 *currentBasePoints, SpellAuraHolder *holder, Unit *target, Unit *caster, Item* castItem) : -m_spellmod(NULL), m_periodicTimer(0), m_periodicTick(0), m_removeMode(AURA_REMOVE_BY_DEFAULT), +m_periodicTimer(0), m_periodicTick(0), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_effIndex(eff), m_positive(false), m_isPeriodic(false), m_isAreaAura(false), m_isPersistent(false), m_in_use(0), m_spellAuraHolder(holder) { @@ -855,7 +855,7 @@ bool Aura::isAffectedOnSpell(SpellEntry const *spell) const return spell->IsFitToFamily(SpellFamily(GetSpellProto()->SpellFamilyName), GetAuraSpellClassMask()); } -bool Aura::CanProcFrom(SpellEntry const *spell, uint32 EventProcEx, uint32 procEx, bool active, bool useClassMask) const +bool Aura::CanProcFrom(SpellEntry const *spell, uint32 procFlag, uint32 EventProcEx, uint32 procEx, bool active, bool useClassMask) const { // Check EffectClassMask ClassFamilyMask const& mask = GetAuraSpellClassMask(); @@ -865,6 +865,16 @@ bool Aura::CanProcFrom(SpellEntry const *spell, uint32 EventProcEx, uint32 procE { if (!(EventProcEx & PROC_EX_EX_TRIGGER_ALWAYS)) { + // modifier aura procs by default are not active and only allowed with non zero charges + // procEx == PROC_EX_NORMAL_HIT only for real "on cast" cases + if (!active && procEx == PROC_EX_NORMAL_HIT && (procFlag & SPELL_CAST_TRIGGER_MASK)) + { + if (GetHolder()->GetAuraCharges() > 0) + return true; + else + return false; + } + // Check for extra req (if none) and hit/crit if (EventProcEx == PROC_EX_NONE) { @@ -1015,30 +1025,24 @@ void Aura::HandleAddModifier(bool apply, bool Real) break; } - m_spellmod = new SpellModifier( - SpellModOp(m_modifier.m_miscvalue), - SpellModType(m_modifier.m_auraname), // SpellModType value == spell aura types - m_modifier.m_amount, - this, - // prevent expire spell mods with (charges > 0 && m_stackAmount > 1) - // all this spell expected expire not at use but at spell proc event check - GetSpellProto()->StackAmount > 1 ? 0 : GetHolder()->GetAuraCharges()); - // Everlasting Affliction, overwrite wrong data, if will need more better restore support of spell_affect table if (spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK && spellProto->SpellIconID == 3169) { // Corruption and Unstable Affliction - m_spellmod->mask = ClassFamilyMask(UI64LIT(0x0000010000000002)); + // TODO: drop when override will be possible + SpellEntry *entry = (SpellEntry*)(&(*spellProto)); + entry->EffectSpellClassMask[GetEffIndex()].Flags = UI64LIT(0x0000010000000002); } // Improved Flametongue Weapon, overwrite wrong data, maybe time re-add table else if (spellProto->Id == 37212) { // Flametongue Weapon (Passive) - m_spellmod->mask = ClassFamilyMask(UI64LIT(0x0000000000200000)); + // TODO: drop when override will be possible + SpellEntry *entry = (SpellEntry*)(&(*spellProto)); + entry->EffectSpellClassMask[GetEffIndex()].Flags = UI64LIT(0x0000000000200000); } } - - ((Player*)GetTarget())->AddSpellMod(m_spellmod, apply); + ((Player*)GetTarget())->AddSpellMod(this, apply); ReapplyAffectedPassiveAuras(); } @@ -2840,39 +2844,10 @@ void Aura::HandleAuraDummy(bool apply, bool Real) } break; } - case SPELLFAMILY_PRIEST: - { - // Pain and Suffering - if (GetSpellProto()->SpellIconID == 2874 && target->GetTypeId()==TYPEID_PLAYER) - { - if (apply) - { - // Reduce backfire damage (dot damage) from Shadow Word: Death - // aura have wrong effectclassmask, so use hardcoded value - m_spellmod = new SpellModifier(SPELLMOD_DOT,SPELLMOD_PCT,m_modifier.m_amount,GetId(),UI64LIT(0x0000200000000000)); - } - ((Player*)target)->AddSpellMod(m_spellmod, apply); - return; - } - break; - } case SPELLFAMILY_DRUID: { switch(GetId()) { - case 34246: // Idol of the Emerald Queen - case 60779: // Idol of Lush Moss - { - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - if (apply) - // dummy not have proper effectclassmask - m_spellmod = new SpellModifier(SPELLMOD_DOT,SPELLMOD_FLAT,m_modifier.m_amount/7,GetId(),UI64LIT(0x001000000000)); - - ((Player*)target)->AddSpellMod(m_spellmod, apply); - return; - } case 52610: // Savage Roar { if (apply) diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index 51c553a2f..e7bc4cab3 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -32,7 +32,6 @@ struct Modifier class Unit; struct SpellEntry; -struct SpellModifier; struct ProcTriggerSpell; // forward decl @@ -123,12 +122,14 @@ class MANGOS_DLL_SPEC SpellAuraHolder uint8 GetAuraLevel() const { return m_auraLevel; } void SetAuraLevel(uint8 level) { m_auraLevel = level; } uint32 GetAuraCharges() const { return m_procCharges; } - void SetAuraCharges(uint32 charges) + void SetAuraCharges(uint32 charges, bool update = true) { if (m_procCharges == charges) return; m_procCharges = charges; - SendAuraUpdate(false); + + if (update) + SendAuraUpdate(false); } bool DropAuraCharge() // return true if last charge dropped { @@ -444,7 +445,7 @@ class MANGOS_DLL_SPEC Aura ClassFamilyMask const& GetAuraSpellClassMask() const { return m_spellAuraHolder->GetSpellProto()->GetEffectSpellClassMask(m_effIndex); } bool isAffectedOnSpell(SpellEntry const *spell) const; - bool CanProcFrom(SpellEntry const *spell, uint32 EventProcEx, uint32 procEx, bool active, bool useClassMask) const; + bool CanProcFrom(SpellEntry const *spell, uint32 procFlag, uint32 EventProcEx, uint32 procEx, bool active, bool useClassMask) const; //SpellAuraHolder const* GetHolder() const { return m_spellHolder; } SpellAuraHolder* GetHolder() { return m_spellAuraHolder; } @@ -467,7 +468,6 @@ class MANGOS_DLL_SPEC Aura void ReapplyAffectedPassiveAuras(); Modifier m_modifier; - SpellModifier *m_spellmod; time_t m_applyTime; diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 5f34df16e..f4832d908 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -397,12 +397,6 @@ void Spell::EffectSchoolDMG(SpellEffectIndex effect_idx) } break; } - case SPELLFAMILY_MAGE: - // remove Arcane Blast buffs at any non-Arcane Blast arcane damage spell. - // NOTE: it removed at hit instead cast because currently spell done-damage calculated at hit instead cast - if ((m_spellInfo->SchoolMask & SPELL_SCHOOL_MASK_ARCANE) && !(m_spellInfo->SpellFamilyFlags & UI64LIT(0x20000000))) - m_caster->RemoveAurasDueToSpell(36032); // Arcane Blast buff - break; case SPELLFAMILY_WARRIOR: { // Bloodthirst diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index bf893070d..f1c477414 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -37,7 +37,6 @@ class Player; class Spell; class Unit; struct CreatureInfo; -struct SpellModifier; // only used in code enum SpellCategories @@ -596,6 +595,13 @@ enum ProcFlags PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT | \ PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT) +#define SPELL_CAST_TRIGGER_MASK (PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT | \ + PROC_FLAG_SUCCESSFUL_RANGED_HIT | \ + PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT | \ + PROC_FLAG_SUCCESSFUL_POSITIVE_AOE_HIT | \ + PROC_FLAG_SUCCESSFUL_AOE_SPELL_HIT | \ + PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL | \ + PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT) enum ProcFlagsEx { PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 5b27d0825..b0ab4de44 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -4441,7 +4441,7 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGuid, U int32 basePoints = aur->GetBasePoints(); // construct the new aura for the attacker - will never return NULL, it's just a wrapper for // some different constructors - Aura * new_aur = CreateAura(aur->GetSpellProto(), aur->GetEffIndex(), &basePoints, new_holder, stealer, this); + Aura * new_aur = CreateAura(spellProto, aur->GetEffIndex(), &basePoints, new_holder, stealer, this); // set periodic to do at least one tick (for case when original aura has been at last tick preparing) int32 periodic = aur->GetModifier()->periodictime; @@ -6530,6 +6530,13 @@ uint32 Unit::SpellDamageBonusTaken(Unit *pCaster, SpellEntry const *spellProto, case 25899: // Greater Blessing of Sanctuary TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; break; + case 47580: // Pain and Suffering (Rank 1) TODO: can be pct modifier aura + case 47581: // Pain and Suffering (Rank 2) + case 47582: // Pain and Suffering (Rank 3) + // Shadow Word: Death + if (spellProto->IsFitToFamilyMask(UI64LIT(0x0000000200000000))) + TakenTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; + break; } } @@ -6956,22 +6963,40 @@ uint32 Unit::SpellHealingBonusDone(Unit *pVictim, SpellEntry const *spellProto, } } - // Nourish 20% of heal increase if target is affected by Druids HOTs - if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && (spellProto->SpellFamilyFlags & UI64LIT(0x0200000000000000))) + if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID) { - int ownHotCount = 0; // counted HoT types amount, not stacks - Unit::AuraList const& RejorRegr = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); - for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) - if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID && - (*i)->GetCasterGuid() == GetObjectGuid()) - ++ownHotCount; - - if (ownHotCount) + // Nourish 20% of heal increase if target is affected by Druids HOTs + if (spellProto->SpellFamilyFlags & UI64LIT(0x0200000000000000)) { - DoneTotalMod *= 1.2f; // base bonus at HoTs + int ownHotCount = 0; // counted HoT types amount, not stacks + Unit::AuraList const& RejorRegr = pVictim->GetAurasByType(SPELL_AURA_PERIODIC_HEAL); + for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i) + if ((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID && + (*i)->GetCasterGuid() == GetObjectGuid()) + ++ownHotCount; - if (Aura* glyph = GetAura(62971, EFFECT_INDEX_0))// Glyph of Nourish - DoneTotalMod *= (glyph->GetModifier()->m_amount * ownHotCount + 100.0f) / 100.0f; + if (ownHotCount) + { + DoneTotalMod *= 1.2f; // base bonus at HoTs + + if (Aura* glyph = GetAura(62971, EFFECT_INDEX_0))// Glyph of Nourish + DoneTotalMod *= (glyph->GetModifier()->m_amount * ownHotCount + 100.0f) / 100.0f; + } + } + // Lifebloom + else if (spellProto->IsFitToFamilyMask(0x0000001000000000)) + { + AuraList const& dummyList = owner->GetAurasByType(SPELL_AURA_DUMMY); + for(AuraList::const_iterator i = dummyList.begin(); i != dummyList.end(); ++i) + { + switch((*i)->GetId()) + { + case 34246: // Idol of the Emerald Queen TODO: can be flat modifier aura + case 60779: // Idol of Lush Moss + DoneTotal += (*i)->GetModifier()->m_amount / 7; + break; + } + } } } @@ -9724,12 +9749,17 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag { if (!procSpell->IsFitToFamilyMask(spellProcEvent->spellFamilyMask[i])) continue; + + // modifier aura procs by default are not active and only allowed with non zero charges + // procEx == PROC_EX_NORMAL_HIT only for real "on cast" cases + if (!useCharges && damage == 0 && procExtra == PROC_EX_NORMAL_HIT && (procFlag & SPELL_CAST_TRIGGER_MASK)) + continue; } // don't check dbc FamilyFlags if schoolMask exists - else if (!triggeredByAura->CanProcFrom(procSpell, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask)) + else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, spellProcEvent->procEx, procExtra, damage != 0, !spellProcEvent->schoolMask)) continue; } - else if (!triggeredByAura->CanProcFrom(procSpell, PROC_EX_NONE, procExtra, damage != 0, true)) + else if (!triggeredByAura->CanProcFrom(procSpell, procFlag, PROC_EX_NONE, procExtra, damage != 0, true)) continue; } diff --git a/src/game/UnitAuraProcHandler.cpp b/src/game/UnitAuraProcHandler.cpp index 2dc726696..c1ff8a7f2 100644 --- a/src/game/UnitAuraProcHandler.cpp +++ b/src/game/UnitAuraProcHandler.cpp @@ -3788,9 +3788,6 @@ SpellAuraProcResult Unit::HandleMendingAuraProc( Unit* /*pVictim*/, uint32 /*dam // jumps int32 jumps = triggeredByAura->GetHolder()->GetAuraCharges()-1; - // current aura expire - triggeredByAura->GetHolder()->SetAuraCharges(1); // will removed at next charges decrease - // next target selection if (jumps > 0 && GetTypeId()==TYPEID_PLAYER && caster_guid.IsPlayer()) { @@ -3802,27 +3799,36 @@ SpellAuraProcResult Unit::HandleMendingAuraProc( Unit* /*pVictim*/, uint32 /*dam if(Player* caster = ((Player*)triggeredByAura->GetCaster())) { - caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius,NULL); + caster->ApplySpellMod(spellProto->Id, SPELLMOD_RADIUS, radius, NULL); if(Player* target = ((Player*)this)->GetNextRandomRaidMember(radius)) { - // aura will applied from caster, but spell casted from current aura holder - SpellModifier *mod = new SpellModifier(SPELLMOD_CHARGES,SPELLMOD_FLAT,jumps-5,spellProto->Id,spellProto->SpellFamilyFlags); + SpellAuraHolder *holder = GetSpellAuraHolder(spellProto->Id, caster->GetObjectGuid()); + SpellAuraHolder *new_holder = CreateSpellAuraHolder(spellProto, target, caster); - // remove before apply next (locked against deleted) + for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i) + { + Aura *aur = holder->GetAuraByEffectIndex(SpellEffectIndex(i)); + if (!aur) + continue; + + int32 basePoints = aur->GetBasePoints(); + Aura * new_aur = CreateAura(spellProto, aur->GetEffIndex(), &basePoints, new_holder, target, caster); + new_holder->AddAura(new_aur, new_aur->GetEffIndex()); + } + new_holder->SetAuraCharges(jumps, false); + + // lock aura holder (currently SPELL_AURA_PRAYER_OF_MENDING is single target spell, so will attempt removing from old target + // when applied to new one) triggeredByAura->SetInUse(true); - RemoveAurasByCasterSpell(spellProto->Id,caster->GetObjectGuid()); - - caster->AddSpellMod(mod, true); - CastCustomSpell(target, spellProto->Id, &heal, NULL, NULL, true, NULL, triggeredByAura, caster->GetObjectGuid()); - caster->AddSpellMod(mod, false); + target->AddSpellAuraHolder(new_holder); triggeredByAura->SetInUse(false); } } } // heal - CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid); + CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid, spellProto); return SPELL_AURA_PROC_OK; } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index b3fafbaed..924eaea5a 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11747" + #define REVISION_NR "11748" #endif // __REVISION_NR_H__