From aebb75b816538d3e0f15aa5f15ecfc56b5476472 Mon Sep 17 00:00:00 2001 From: QAston Date: Sun, 19 Jun 2011 13:13:41 +0200 Subject: Core/Auras: Move periodic aura effect handlers to separate functions, do a little cleanup in these, also allow periodic dummy/periodic trigger spell auras to tick when caster is not available. --- src/server/game/Spells/Auras/SpellAuraEffects.cpp | 8336 ++++++++++----------- src/server/game/Spells/Auras/SpellAuraEffects.h | 21 +- 2 files changed, 4125 insertions(+), 4232 deletions(-) (limited to 'src') diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 8a6e8f5b8df..e63d0dfda03 100755 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -42,7 +42,7 @@ class Aura; // // in aura handler there should be check for modes: // AURA_EFFECT_HANDLE_REAL set -// AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK set +// AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK set // AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK set - aura is recalculated or is just applied/removed - need to redo all things related to m_amount // AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK - logical or of above conditions // AURA_EFFECT_HANDLE_STAT - set when stats are reapplied @@ -850,7 +850,7 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool create, bool load) // reset periodic timer on aura create or on reapply when aura isn't dot // possibly we should not reset periodic timers only when aura is triggered by proc // or maybe there's a spell attribute somewhere - bool resetPeriodicTimer = create + bool resetPeriodicTimer = create || ((GetAuraType() != SPELL_AURA_PERIODIC_DAMAGE) && (GetAuraType() != SPELL_AURA_PERIODIC_DAMAGE_PERCENT)); if (resetPeriodicTimer) @@ -1279,3653 +1279,3271 @@ void AuraEffect::PeriodicTick(AuraApplication * aurApp, Unit* caster) const switch(GetAuraType()) { + case SPELL_AURA_PERIODIC_DUMMY: + HandlePeriodicDummyAuraTick(target, caster); + break; + case SPELL_AURA_PERIODIC_TRIGGER_SPELL: + HandlePeriodicTriggerSpellAuraTick(target, caster); + break; + case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: + HandlePeriodicTriggerSpellWithValueAuraTick(target, caster); + break; case SPELL_AURA_PERIODIC_DAMAGE: case SPELL_AURA_PERIODIC_DAMAGE_PERCENT: + HandlePeriodicDamageAurasTick(target, caster); + break; + case SPELL_AURA_PERIODIC_LEECH: + HandlePeriodicHealthLeechAuraTick(target, caster); + break; + case SPELL_AURA_PERIODIC_HEALTH_FUNNEL: + HandlePeriodicHealthFunnelAuraTick(target, caster); + break; + case SPELL_AURA_PERIODIC_HEAL: + case SPELL_AURA_OBS_MOD_HEALTH: + HandlePeriodicHealAurasTick(target, caster); + break; + case SPELL_AURA_PERIODIC_MANA_LEECH: + HandlePeriodicManaLeechAuraTick(target, caster); + break; + case SPELL_AURA_OBS_MOD_POWER: + HandleObsModPowerAuraTick(target, caster); + break; + case SPELL_AURA_PERIODIC_ENERGIZE: + HandlePeriodicEnergizeAuraTick(target, caster); + break; + case SPELL_AURA_POWER_BURN_MANA: + HandlePeriodicPowerBurnManaAuraTick(target, caster); + break; + case SPELL_AURA_DUMMY: + // Haunting Spirits + if (GetId() == 7057) + target->CastSpell((Unit*)NULL , GetAmount(), true); + break; + default: + break; + } +} + +bool AuraEffect::IsAffectedOnSpell(SpellEntry const *spell) const +{ + if (!spell) + return false; + // Check family name + if (spell->SpellFamilyName != m_spellProto->SpellFamilyName) + return false; + + // Check EffectClassMask + if (m_spellProto->EffectSpellClassMask[m_effIndex] & spell->SpellFamilyFlags) + return true; + return false; +} + +void AuraEffect::CleanupTriggeredSpells(Unit* target) +{ + uint32 tSpellId = m_spellProto->EffectTriggerSpell[GetEffIndex()]; + if (!tSpellId) + return; + + SpellEntry const* tProto = sSpellStore.LookupEntry(tSpellId); + if (!tProto) + return; + + if (GetSpellDuration(tProto) != -1) + return; + + // needed for spell 43680, maybe others + // TODO: is there a spell flag, which can solve this in a more sophisticated way? + if (m_spellProto->EffectApplyAuraName[GetEffIndex()] == SPELL_AURA_PERIODIC_TRIGGER_SPELL && + uint32(GetSpellDuration(m_spellProto)) == m_spellProto->EffectAmplitude[GetEffIndex()]) + return; + + target->RemoveAurasDueToSpell(tSpellId, GetCasterGUID()); +} + +void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const +{ + uint32 spellId = 0; + uint32 spellId2 = 0; + //uint32 spellId3 = 0; + uint32 HotWSpellId = 0; + + switch(GetMiscValue()) + { + case FORM_CAT: + spellId = 3025; + HotWSpellId = 24900; + break; + case FORM_TREE: + spellId = 34123; + break; + case FORM_TRAVEL: + spellId = 5419; + break; + case FORM_AQUA: + spellId = 5421; + break; + case FORM_BEAR: + spellId = 1178; + spellId2 = 21178; + HotWSpellId = 24899; + break; + case FORM_DIREBEAR: + spellId = 9635; + spellId2 = 21178; + HotWSpellId = 24899; + break; + case FORM_BATTLESTANCE: + spellId = 21156; + break; + case FORM_DEFENSIVESTANCE: + spellId = 7376; + break; + case FORM_BERSERKERSTANCE: + spellId = 7381; + break; + case FORM_MOONKIN: + spellId = 24905; + spellId2 = 69366; + break; + case FORM_FLIGHT: + spellId = 33948; + spellId2 = 34764; + break; + case FORM_FLIGHT_EPIC: + spellId = 40122; + spellId2 = 40121; + break; + case FORM_METAMORPHOSIS: + spellId = 54817; + spellId2 = 54879; + break; + case FORM_SPIRITOFREDEMPTION: + spellId = 27792; + spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation. + break; + case FORM_SHADOW: + spellId = 49868; + spellId2 = 71167; + break; + case FORM_GHOSTWOLF: + spellId = 67116; + break; + case FORM_GHOUL: + case FORM_AMBIENT: + case FORM_STEALTH: + case FORM_CREATURECAT: + case FORM_CREATUREBEAR: + break; + default: + break; + } + + if (apply) + { + // Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell + if (spellId) { - if (!caster) - break; + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->RemoveSpellCooldown(spellId); + target->CastSpell(target, spellId, true, NULL, this); + } - if (!target->isAlive()) - return; + if (spellId2) + { + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->RemoveSpellCooldown(spellId2); + target->CastSpell(target, spellId2, true, NULL, this); + } - if (target->HasUnitState(UNIT_STAT_ISOLATED)) + if (target->GetTypeId() == TYPEID_PLAYER) + { + const PlayerSpellMap& sp_list = target->ToPlayer()->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) { - SendTickImmune(target, caster); - return; + if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) continue; + if (itr->first == spellId || itr->first == spellId2) continue; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE))) continue; + if (spellInfo->Stances & (1<<(GetMiscValue()-1))) + target->CastSpell(target, itr->first, true, NULL, this); } - - // Consecrate ticks can miss and will not show up in the combat log - if (GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA && - caster->SpellHitResult(target, GetSpellProto(), false) != SPELL_MISS_NONE) - break; - - // Check for immune (not use charges) - if (target->IsImmunedToDamage(GetSpellProto())) + // Leader of the Pack + if (target->ToPlayer()->HasSpell(17007)) { - SendTickImmune(target, caster); - break; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(24932); + if (spellInfo && spellInfo->Stances & (1<<(GetMiscValue()-1))) + target->CastSpell(target, 24932, true, NULL, this); } - - // some auras remove at specific health level or more - if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) + // Improved Barkskin - apply/remove armor bonus due to shapeshift + if (target->ToPlayer()->HasSpell(63410) || target->ToPlayer()->HasSpell(63411)) { - switch (GetId()) + target->RemoveAurasDueToSpell(66530); + if (GetMiscValue() == FORM_TRAVEL || GetMiscValue() == FORM_NONE) // "while in Travel Form or while not shapeshifted" + target->CastSpell(target, 66530, true); + } + // Heart of the Wild + if (HotWSpellId) + { // hacky, but the only way as spell family is not SPELLFAMILY_DRUID + Unit::AuraEffectList const& mModTotalStatPct = target->GetAuraEffectsByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE); + for (Unit::AuraEffectList::const_iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i) { - case 43093: case 31956: case 38801: // Grievous Wound - case 35321: case 38363: case 39215: // Gushing Wound - if (target->IsFullHealth()) - { - target->RemoveAurasDueToSpell(GetId()); - return; - } - break; - case 38772: // Grievous Wound + // Heart of the Wild + if ((*i)->GetSpellProto()->SpellIconID == 240 && (*i)->GetMiscValue() == 3) { - uint32 percent = - GetEffIndex() < 2 && GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_DUMMY ? - caster->CalculateSpellDamage(target, GetSpellProto(), GetEffIndex()+1) : - 100; - if (!target->HealthBelowPct(percent)) - { - target->RemoveAurasDueToSpell(GetId()); - return; - } + int32 HotWMod = (*i)->GetAmount(); + + target->CastCustomSpell(target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this); break; } } } - - uint32 absorb=0; - uint32 resist=0; - CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - - // ignore non positive values (can be result apply spellmods to aura damage - uint32 damage = GetAmount() > 0 ? GetAmount() : 0; - - if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) + switch(GetMiscValue()) { - damage = caster->SpellDamageBonus(target, GetSpellProto(), damage, DOT, GetBase()->GetStackAmount()); - - // Calculate armor mitigation - if (Unit::IsDamageReducedByArmor(GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), m_effIndex)) - { - uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellProto()); - cleanDamage.mitigated_damage += damage - damageReductedArmor; - damage = damageReductedArmor; - } - - // Curse of Agony damage-per-tick calculation - if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags[0] & 0x400) && GetSpellProto()->SpellIconID == 544) - { - uint32 totalTick = GetTotalTicks(); - // 1..4 ticks, 1/2 from normal tick damage - if (m_tickNumber <= totalTick / 3) - damage = damage/2; - // 9..12 ticks, 3/2 from normal tick damage - else if (m_tickNumber > totalTick * 2 / 3) - damage += (damage+1)/2; // +1 prevent 0.5 damage possible lost at 1..4 ticks - // 5..8 ticks have normal tick damage - } - // There is a Chance to make a Soul Shard when Drain soul does damage - if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags[0] & 0x00004000)) - { - if (caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target)) + case FORM_CAT: + // Savage Roar + if (target->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_DRUID, 0 , 0x10000000, 0)) + target->CastSpell(target, 62071, true); + // Nurturing Instinct + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT, SPELLFAMILY_DRUID, 2254, 0)) { - if (roll_chance_i(20)) + uint32 spellId = 0; + switch (aurEff->GetId()) { - caster->CastSpell(caster, 43836, true, 0, this); - // Glyph of Drain Soul - chance to create an additional Soul Shard - if (AuraEffect *aur = caster->GetAuraEffect(58070, 0)) - if (roll_chance_i(aur->GetMiscValue())) - caster->CastSpell(caster, 58068, true, 0, aur); + case 33872: + spellId = 47179; + break; + case 33873: + spellId = 47180; + break; } + target->CastSpell(target, spellId, true, NULL, this); } - } - if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_GENERIC) - { - switch (GetId()) + // Master Shapeshifter - Cat + if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) { - case 70911: // Unbound Plague - case 72854: // Unbound Plague - case 72855: // Unbound Plague - case 72856: // Unbound Plague - damage *= uint32(pow(1.25f, int32(m_tickNumber))); - break; - default: - break; + int32 bp = aurEff->GetAmount(); + target->CastCustomSpell(target, 48420, &bp, NULL, NULL, true); } - } - } - else - damage = uint32(target->CountPctFromMaxHealth(damage)); - - bool crit = IsPeriodicTickCrit(target, caster); - if (crit) - damage = caster->SpellCriticalDamageBonus(m_spellProto, damage, target); - - int32 dmg = damage; - caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL); - damage = dmg; - - caster->CalcAbsorbResist(target, GetSpellSchoolMask(GetSpellProto()), DOT, damage, &absorb, &resist, m_spellProto); - - sLog->outDetail("PeriodicTick: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u", - GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), damage, GetId(), absorb); - - caster->DealDamageMods(target, damage, &absorb); - - // Set trigger flag - uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; - uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT; - damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist); - if (damage) - procVictim|=PROC_FLAG_TAKEN_DAMAGE; - - int32 overkill = damage - target->GetHealth(); - if (overkill < 0) - overkill = 0; - - SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit); - target->SendPeriodicAuraLog(&pInfo); - - caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellProto()); - - caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); - break; - } - case SPELL_AURA_PERIODIC_LEECH: - { - if (!caster) - return; - - if (!caster->isAlive()) - return; - - if (!target->isAlive()) - return; - - if (target->HasUnitState(UNIT_STAT_ISOLATED)) - { - SendTickImmune(target, caster); - return; + break; + case FORM_DIREBEAR: + case FORM_BEAR: + // Master Shapeshifter - Bear + if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) + { + int32 bp = aurEff->GetAmount(); + target->CastCustomSpell(target, 48418, &bp, NULL, NULL, true); + } + // Survival of the Fittest + if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DRUID, 961, 0)) + { + int32 bp = 100 + SpellMgr::CalculateSpellEffectAmount(aurEff->GetSpellProto(), 2); + target->CastCustomSpell(target, 62069, &bp, NULL, NULL, true, 0, this); + } + break; + case FORM_MOONKIN: + // Master Shapeshifter - Moonkin + if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) + { + int32 bp = aurEff->GetAmount(); + target->CastCustomSpell(target, 48421, &bp, NULL, NULL, true); + } + break; + // Master Shapeshifter - Tree of Life + case FORM_TREE: + if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) + { + int32 bp = aurEff->GetAmount(); + target->CastCustomSpell(target, 48422, &bp, NULL, NULL, true); + } + break; } + } + } + else + { + if (spellId) + target->RemoveAurasDueToSpell(spellId); + if (spellId2) + target->RemoveAurasDueToSpell(spellId2); - if (GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA && - caster->SpellHitResult(target, GetSpellProto(), false) != SPELL_MISS_NONE) - return; - - // Check for immune - if (target->IsImmunedToDamage(GetSpellProto())) + // Improved Barkskin - apply/remove armor bonus due to shapeshift + if (Player *pl=target->ToPlayer()) + { + if (pl->HasSpell(63410) || pl->HasSpell(63411)) { - SendTickImmune(target, caster); - return; + target->RemoveAurasDueToSpell(66530); + target->CastSpell(target, 66530, true); } + } - uint32 absorb=0; - uint32 resist=0; - CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - - //uint32 damage = GetModifierValuePerStack() > 0 ? GetModifierValuePerStack() : 0; - uint32 damage = GetAmount() > 0 ? GetAmount() : 0; - damage = caster->SpellDamageBonus(target, GetSpellProto(), damage, DOT, GetBase()->GetStackAmount()); - - bool crit = IsPeriodicTickCrit(target, caster); - if (crit) - damage = caster->SpellCriticalDamageBonus(m_spellProto, damage, target); + Unit::AuraApplicationMap& tAuras = target->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();) + { + if (itr->second->GetBase()->IsRemovedOnShapeLost(target)) + target->RemoveAura(itr); + else + ++itr; + } + } +} - // Calculate armor mitigation - if (Unit::IsDamageReducedByArmor(GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), m_effIndex)) - { - uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellProto()); - cleanDamage.mitigated_damage += damage - damageReductedArmor; - damage = damageReductedArmor; - } +/*********************************************************/ +/*** AURA EFFECT HANDLERS ***/ +/*********************************************************/ - int32 dmg = damage; - caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL); - damage = dmg; +/**************************************/ +/*** VISIBILITY & PHASES ***/ +/**************************************/ - caster->CalcAbsorbResist(target, GetSpellSchoolMask(GetSpellProto()), DOT, damage, &absorb, &resist, m_spellProto); +void AuraEffect::HandleModInvisibilityDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + return; - if (target->GetHealth() < damage) - damage = uint32(target->GetHealth()); + Unit* target = aurApp->GetTarget(); + InvisibilityType type = InvisibilityType(GetMiscValue()); - sLog->outDetail("PeriodicTick: %u (TypeId: %u) health leech of %u (TypeId: %u) for %u dmg inflicted by %u abs is %u", - GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), damage, GetId(), absorb); + if (apply) + { + target->m_invisibilityDetect.AddFlag(type); + target->m_invisibilityDetect.AddValue(type, GetAmount()); + } + else + { + if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY_DETECT)) + target->m_invisibilityDetect.DelFlag(type); - caster->SendSpellNonMeleeDamageLog(target, GetId(), damage, GetSpellSchoolMask(GetSpellProto()), absorb, resist, false, 0, crit); + target->m_invisibilityDetect.AddValue(type, -GetAmount()); + } - // Set trigger flag - uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; - uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT; - damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist); - if (damage) - procVictim|=PROC_FLAG_TAKEN_DAMAGE; - caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellProto()); - int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), false); + // call functions which may have additional effects after chainging state of unit + target->UpdateObjectVisibility(); +} - if (!target->isAlive() && caster->IsNonMeleeSpellCasted(false)) - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) - if (Spell* spell = caster->GetCurrentSpell(CurrentSpellTypes(i))) - if (spell->m_spellInfo->Id == GetId()) - spell->cancel(); +void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) + return; - float gainMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(GetSpellProto(), GetEffIndex(), caster); + Unit* target = aurApp->GetTarget(); + InvisibilityType type = InvisibilityType(GetMiscValue()); - uint32 heal = uint32(caster->SpellHealingBonus(caster, GetSpellProto(), uint32(new_damage * gainMultiplier), DOT, GetBase()->GetStackAmount())); + if (apply) + { + // apply glow vision + if (target->GetTypeId() == TYPEID_PLAYER) + target->SetByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); - int32 gain = caster->HealBySpell(caster, GetSpellProto(), heal); - caster->getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellProto()); - break; - } - case SPELL_AURA_PERIODIC_HEALTH_FUNNEL: // only three spells + target->m_invisibility.AddFlag(type); + target->m_invisibility.AddValue(type, GetAmount()); + } + else + { + if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) { - if (!caster || !caster->GetHealth()) - break; - - if (!target->isAlive()) - return; - - if (target->HasUnitState(UNIT_STAT_ISOLATED)) - { - SendTickImmune(target, caster); - return; - } - - uint32 damage = GetAmount(); - // do not kill health donator - if (caster->GetHealth() < damage) - damage = caster->GetHealth() - 1; - if (!damage) - break; - - //donator->SendSpellNonMeleeDamageLog(donator, GetId(), damage, GetSpellSchoolMask(spellProto), 0, 0, false, 0); - caster->ModifyHealth(-(int32)damage); - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "PeriodicTick: donator %u target %u damage %u.", target->GetEntry(), target->GetEntry(), damage); - - float gainMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(GetSpellProto(), GetEffIndex(), caster); - - damage = int32(damage * gainMultiplier); + // if not have different invisibility auras. + // remove glow vision + if (target->GetTypeId() == TYPEID_PLAYER) + target->RemoveByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); - caster->HealBySpell(target, GetSpellProto(), damage); - break; + target->m_invisibility.DelFlag(type); } - case SPELL_AURA_PERIODIC_HEAL: - case SPELL_AURA_OBS_MOD_HEALTH: + else { - if (!caster) - break; - - if (!target->isAlive()) - return; - - if (target->HasUnitState(UNIT_STAT_ISOLATED)) + bool found = false; + Unit::AuraEffectList const& invisAuras = target->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY); + for (Unit::AuraEffectList::const_iterator i = invisAuras.begin(); i != invisAuras.end(); ++i) { - SendTickImmune(target, caster); - return; + if (GetMiscValue() == (*i)->GetMiscValue()) + { + found = true; + break; + } } + if (!found) + target->m_invisibility.DelFlag(type); + } - // heal for caster damage (must be alive) - if (target != caster && GetSpellProto()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL && !caster->isAlive()) - break; + target->m_invisibility.AddValue(type, -GetAmount()); + } - if (GetBase()->GetDuration() == -1 && target->IsFullHealth()) - break; + // call functions which may have additional effects after chainging state of unit + if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) + { + // drop flag at invisibiliy in bg + target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + } + target->UpdateObjectVisibility(); +} - // ignore non positive values (can be result apply spellmods to aura damage - int32 damage = m_amount > 0 ? m_amount : 0; +void AuraEffect::HandleModStealthDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + return; - if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH) - { - // Taken mods - float TakenTotalMod = 1.0f; + Unit* target = aurApp->GetTarget(); + StealthType type = StealthType(GetMiscValue()); - // Tenacity increase healing % taken - if (AuraEffect const* Tenacity = target->GetAuraEffect(58549, 0)) - AddPctN(TakenTotalMod, Tenacity->GetAmount()); + if (apply) + { + target->m_stealthDetect.AddFlag(type); + target->m_stealthDetect.AddValue(type, GetAmount()); + } + else + { + if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH_DETECT)) + target->m_stealthDetect.DelFlag(type); - // Healing taken percent - float minval = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT); - if (minval) - AddPctF(TakenTotalMod, minval); + target->m_stealthDetect.AddValue(type, -GetAmount()); + } - float maxval = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT); - if (maxval) - AddPctF(TakenTotalMod, maxval); + // call functions which may have additional effects after chainging state of unit + target->UpdateObjectVisibility(); +} - // Healing over time taken percent - float minval_hot = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT); - if (minval_hot) - AddPctF(TakenTotalMod, minval_hot); +void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) + return; - float maxval_hot = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT); - if (maxval_hot) - AddPctF(TakenTotalMod, maxval_hot); + Unit* target = aurApp->GetTarget(); + StealthType type = StealthType(GetMiscValue()); - TakenTotalMod = std::max(TakenTotalMod, 0.0f); + if (apply) + { + target->m_stealth.AddFlag(type); + target->m_stealth.AddValue(type, GetAmount()); - damage = uint32(target->CountPctFromMaxHealth(damage)); - damage = uint32(damage * TakenTotalMod); - } - else - { - // Wild Growth = amount + (6 - 2*doneTicks) * ticks* amount / 100 - if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellIconID == 2864) - { - int32 addition = int32(float(damage * GetTotalTicks()) * ((6-float(2*(GetTickNumber()-1)))/100)); + target->SetStandFlags(UNIT_STAND_FLAGS_CREEP); + if (target->GetTypeId() == TYPEID_PLAYER) + target->SetByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_STEALTH); + } + else + { + target->m_stealth.AddValue(type, -GetAmount()); - // Item - Druid T10 Restoration 2P Bonus - if (AuraEffect* aurEff = caster->GetAuraEffect(70658, 0)) - // divided by 50 instead of 100 because calculated as for every 2 tick - addition += abs(int32((addition * aurEff->GetAmount()) / 50)); + if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) // if last SPELL_AURA_MOD_STEALTH + { + target->m_stealth.DelFlag(type); - damage += addition; - } + target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP); + if (target->GetTypeId() == TYPEID_PLAYER) + target->RemoveByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_STEALTH); + } + } - damage = caster->SpellHealingBonus(target, GetSpellProto(), damage, DOT, GetBase()->GetStackAmount()); - } + // call functions which may have additional effects after chainging state of unit + if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) + { + // drop flag at stealth in bg + target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + } + target->UpdateObjectVisibility(); +} - bool crit = IsPeriodicTickCrit(target, caster); - if (crit) - damage = caster->SpellCriticalHealingBonus(m_spellProto, damage, target); +void AuraEffect::HandleModStealthLevel(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + return; - sLog->outDetail("PeriodicTick: %u (TypeId: %u) heal of %u (TypeId: %u) for %u health inflicted by %u", - GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), damage, GetId()); + Unit* target = aurApp->GetTarget(); + StealthType type = StealthType(GetMiscValue()); - uint32 absorb = 0; - uint32 heal = uint32(damage); - caster->CalcHealAbsorb(target, GetSpellProto(), heal, absorb); - int32 gain = caster->DealHeal(target, heal); + if (apply) + target->m_stealth.AddValue(type, GetAmount()); + else + target->m_stealth.AddValue(type, -GetAmount()); - SpellPeriodicAuraLogInfo pInfo(this, damage, damage - gain, absorb, 0, 0.0f, crit); - target->SendPeriodicAuraLog(&pInfo); + // call functions which may have additional effects after chainging state of unit + target->UpdateObjectVisibility(); +} - target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellProto()); +void AuraEffect::HandleSpiritOfRedemption(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - bool haveCastItem = GetBase()->GetCastItemGUID() != 0; + Unit* target = aurApp->GetTarget(); - // Health Funnel - // damage caster for heal amount - if (target != caster && GetSpellProto()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL) - { - uint32 damage = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), 0); // damage is not affected by spell power - if ((int32)damage > gain) - damage = gain; - uint32 absorb = 0; - caster->DealDamageMods(caster, damage, &absorb); - caster->SendSpellNonMeleeDamageLog(caster, GetId(), damage, GetSpellSchoolMask(GetSpellProto()), absorb, 0, false, 0, false); - - CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - caster->DealDamage(caster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); - } + if (target->GetTypeId() != TYPEID_PLAYER) + return; - uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; - uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT; - // ignore item heals - if (!haveCastItem) - caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellProto()); - break; - } - case SPELL_AURA_PERIODIC_MANA_LEECH: + // prepare spirit state + if (apply) + { + if (target->GetTypeId() == TYPEID_PLAYER) { - if (GetMiscValue() < 0 || GetMiscValue() >= int8(MAX_POWERS)) - break; - - if (!target->isAlive()) - return; - - if (target->HasUnitState(UNIT_STAT_ISOLATED)) - { - SendTickImmune(target, caster); - return; - } - - Powers power = Powers(GetMiscValue()); - - // power type might have changed between aura applying and tick (druid's shapeshift) - if (target->getPowerType() != power) - break; - - if (!caster || !caster->isAlive()) - break; - - if (GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA && - caster->SpellHitResult(target, GetSpellProto(), false) != SPELL_MISS_NONE) - break; - - // Check for immune (not use charges) - if (target->IsImmunedToDamage(GetSpellProto())) - { - SendTickImmune(target, caster); - break; - } - - // ignore non positive values (can be result apply spellmods to aura damage - uint32 damage = m_amount > 0 ? m_amount : 0; + // disable breath/etc timers + target->ToPlayer()->StopMirrorTimers(); - // Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana) - // It's mana percent cost spells, m_amount is percent drain from target - if (m_spellProto->ManaCostPercentage) - { - // max value - uint32 maxmana = CalculatePctF(caster->GetMaxPower(power), damage * 2.0f); - ApplyPctU(damage, target->GetMaxPower(power)); - if (damage > maxmana) - damage = maxmana; - } + // set stand state (expected in this form) + if (!target->IsStandState()) + target->SetStandState(UNIT_STAND_STATE_STAND); + } - sLog->outDetail("PeriodicTick: %u (TypeId: %u) power leech of %u (TypeId: %u) for %u dmg inflicted by %u", - GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), damage, GetId()); + target->SetHealth(1); + } + // die at aura end + else if (target->isAlive()) + // call functions which may have additional effects after chainging state of unit + target->setDeathState(JUST_DIED); +} - int32 drain_amount = std::min(target->GetPower(power), damage); +void AuraEffect::HandleAuraGhost(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - if (power == POWER_MANA) - drain_amount -= target->GetSpellCritDamageReduction(drain_amount); + Unit* target = aurApp->GetTarget(); - target->ModifyPower(power, -drain_amount); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - float gain_multiplier = 0.0f; + if (apply) + { + target->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); + target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + } + else + { + if (target->HasAuraType(SPELL_AURA_GHOST)) + return; - if (caster->GetMaxPower(power) > 0) - gain_multiplier = SpellMgr::CalculateSpellEffectValueMultiplier(GetSpellProto(), GetEffIndex(), caster); + target->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); + target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); + target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); + } +} - SpellPeriodicAuraLogInfo pInfo(this, drain_amount, 0, 0, 0, gain_multiplier, false); - target->SendPeriodicAuraLog(&pInfo); +void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - int32 gain_amount = int32(drain_amount * gain_multiplier); + Unit* target = aurApp->GetTarget(); - if (gain_amount) - { - int32 gain = caster->ModifyPower(power, gain_amount); - target->AddThreat(caster, float(gain) * 0.5f, GetSpellSchoolMask(GetSpellProto()), GetSpellProto()); - } + // no-phase is also phase state so same code for apply and remove + uint32 newPhase = 0; + Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE); + if (!phases.empty()) + for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) + newPhase |= (*itr)->GetMiscValue(); - switch(GetId()) - { - case 31447: // Mark of Kaz'rogal - if (target->GetPower(power) == 0) - { - target->CastSpell(target, 31463, true, 0, this); - // Remove aura - GetBase()->SetDuration(0); - } - break; + if (Player* player = target->ToPlayer()) + { + if (!newPhase) + newPhase = PHASEMASK_NORMAL; - case 32960: // Mark of Kazzak - int32 modifier = int32(target->GetPower(power) * 0.05f); - target->ModifyPower(power, -modifier); + // GM-mode have mask 0xFFFFFFFF + if (player->isGameMaster()) + newPhase = 0xFFFFFFFF; - if (target->GetPower(power) == 0) - { - target->CastSpell(target, 32961, true, 0, this); - // Remove aura - GetBase()->SetDuration(0); - } - } - // Drain Mana - if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK - && m_spellProto->SpellFamilyFlags[0] & 0x00000010) - { - int32 manaFeedVal = 0; - if (AuraEffect const* aurEff = GetBase()->GetEffect(1)) - manaFeedVal = aurEff->GetAmount(); - // Mana Feed - Drain Mana - if (manaFeedVal > 0) - { - ApplyPctN(manaFeedVal, gain_amount); - caster->CastCustomSpell(caster, 32554, &manaFeedVal, NULL, NULL, true, NULL, this); - } - } - break; - } - case SPELL_AURA_OBS_MOD_POWER: + player->SetPhaseMask(newPhase, false); + player->GetSession()->SendSetPhaseShift(newPhase); + } + else + { + if (!newPhase) { - if (GetMiscValue() < 0) - return; - - if (!target->isAlive()) - return; + newPhase = PHASEMASK_NORMAL; + if (Creature* creature = target->ToCreature()) + if (CreatureData const* data = sObjectMgr->GetCreatureData(creature->GetDBTableGUIDLow())) + newPhase = data->phaseMask; + } - if (target->HasUnitState(UNIT_STAT_ISOLATED)) - { - SendTickImmune(target, caster); - return; - } + target->SetPhaseMask(newPhase, false); + } - Powers power; - if (GetMiscValue() == POWER_ALL) - power = target->getPowerType(); - else - power = Powers(GetMiscValue()); + // call functions which may have additional effects after chainging state of unit + // phase auras normally not expected at BG but anyway better check + if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) + { + // drop flag at invisibiliy in bg + target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + } - if (target->GetMaxPower(power) == 0) - return; + // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) + if (target->IsVisible()) + target->UpdateObjectVisibility(); +} - if (GetBase()->GetDuration() == -1 && target->GetPower(power) == target->GetMaxPower(power)) - return; +/**********************/ +/*** UNIT MODEL ***/ +/**********************/ - uint32 amount = m_amount * target->GetMaxPower(power) /100; - sLog->outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u", - GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), amount, GetId()); +void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false); - target->SendPeriodicAuraLog(&pInfo); + Unit* target = aurApp->GetTarget(); - int32 gain = target->ModifyPower(power, amount); + uint32 modelid = 0; + Powers PowerType = POWER_MANA; + ShapeshiftForm form = ShapeshiftForm(GetMiscValue()); - if (caster) - target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellProto()); + switch (form) + { + case FORM_CAT: // 0x01 + case FORM_GHOUL: // 0x07 + PowerType = POWER_ENERGY; break; - } - case SPELL_AURA_PERIODIC_ENERGIZE: - { - // ignore non positive values (can be result apply spellmods to aura damage - if (m_amount < 0 || GetMiscValue() >= int8(MAX_POWERS)) - return; - - if (!target->isAlive()) - return; - - if (target->HasUnitState(UNIT_STAT_ISOLATED)) - { - SendTickImmune(target, caster); - return; - } - - Powers power = Powers(GetMiscValue()); - - if (target->GetMaxPower(power) == 0) - return; - if (GetBase()->GetDuration() == -1 && target->GetPower(power) == target->GetMaxPower(power)) - return; - - uint32 amount = m_amount; + case FORM_BEAR: // 0x05 + case FORM_DIREBEAR: // 0x08 - SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false); - target->SendPeriodicAuraLog(&pInfo); + case FORM_BATTLESTANCE: // 0x11 + case FORM_DEFENSIVESTANCE: // 0x12 + case FORM_BERSERKERSTANCE: // 0x13 + PowerType = POWER_RAGE; + break; - sLog->outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u", - GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), amount, GetId()); + case FORM_TREE: // 0x02 + case FORM_TRAVEL: // 0x03 + case FORM_AQUA: // 0x04 + case FORM_AMBIENT: // 0x06 - int32 gain = target->ModifyPower(power, amount); + case FORM_STEVES_GHOUL: // 0x09 + case FORM_THARONJA_SKELETON: // 0x0A + case FORM_TEST_OF_STRENGTH: // 0x0B + case FORM_BLB_PLAYER: // 0x0C + case FORM_SHADOW_DANCE: // 0x0D + case FORM_CREATUREBEAR: // 0x0E + case FORM_CREATURECAT: // 0x0F + case FORM_GHOSTWOLF: // 0x10 - if (caster) - target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellProto()); + case FORM_TEST: // 0x14 + case FORM_ZOMBIE: // 0x15 + case FORM_METAMORPHOSIS: // 0x16 + case FORM_UNDEAD: // 0x19 + case FORM_MASTER_ANGLER: // 0x1A + case FORM_FLIGHT_EPIC: // 0x1B + case FORM_SHADOW: // 0x1C + case FORM_FLIGHT: // 0x1D + case FORM_STEALTH: // 0x1E + case FORM_MOONKIN: // 0x1F + case FORM_SPIRITOFREDEMPTION: // 0x20 break; - } - case SPELL_AURA_POWER_BURN_MANA: - { - if (!caster) - return; + default: + sLog->outError("Auras: Unknown Shapeshift Type: %u", GetMiscValue()); + } - if (!target->isAlive()) - return; + modelid = target->GetModelForForm(form); - if (target->HasUnitState(UNIT_STAT_ISOLATED)) + if (apply) + { + // remove polymorph before changing display id to keep new display id + switch (form) + { + case FORM_CAT: + case FORM_TREE: + case FORM_TRAVEL: + case FORM_AQUA: + case FORM_BEAR: + case FORM_DIREBEAR: + case FORM_FLIGHT_EPIC: + case FORM_FLIGHT: + case FORM_MOONKIN: { - SendTickImmune(target, caster); - return; - } + // remove movement affects + target->RemoveMovementImpairingAuras(); - // Check for immune (not use charges) - if (target->IsImmunedToDamage(GetSpellProto())) - { - SendTickImmune(target, caster); - return; + // and polymorphic affects + if (target->IsPolymorphed()) + target->RemoveAurasDueToSpell(target->getTransForm()); + break; } + default: + break; + } - int32 damage = m_amount > 0 ? m_amount : 0; - - Powers powerType = Powers(GetMiscValue()); - - if (!target->isAlive() || target->getPowerType() != powerType) - return; + // remove other shapeshift before applying a new one + target->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT, 0, GetBase()); - // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) - if (powerType == POWER_MANA) - damage -= target->GetSpellCritDamageReduction(damage); + // stop handling the effect if it was removed by linked event + if (aurApp->GetRemoveMode()) + return; - uint32 gain = uint32(-target->ModifyPower(powerType, -damage)); + if (modelid > 0) + target->SetDisplayId(modelid); - float dmgMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(GetSpellProto(), GetEffIndex(), caster); + if (PowerType != POWER_MANA) + { + uint32 oldPower = target->GetPower(PowerType); + // reset power to default values only at power change + if (target->getPowerType() != PowerType) + target->setPowerType(PowerType); - SpellEntry const* spellProto = GetSpellProto(); - //maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG - SpellNonMeleeDamage damageInfo(caster, target, spellProto->Id, spellProto->SchoolMask); - //no SpellDamageBonus for burn mana - caster->CalculateSpellDamageTaken(&damageInfo, int32(gain * dmgMultiplier), spellProto); + switch (form) + { + case FORM_CAT: + case FORM_BEAR: + case FORM_DIREBEAR: + { + // get furor proc chance + uint32 FurorChance = 0; + if (AuraEffect const *dummy = target->GetDummyAuraEffect(SPELLFAMILY_DRUID, 238, 0)) + FurorChance = std::max(dummy->GetAmount(), 0); - caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - - caster->SendSpellNonMeleeDamageLog(&damageInfo); - - // Set trigger flag - uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; - uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; - uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT; - if (damageInfo.damage) - procVictim|=PROC_FLAG_TAKEN_DAMAGE; - - caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto); - - caster->DealSpellDamage(&damageInfo, true); - break; + switch (GetMiscValue()) + { + case FORM_CAT: + { + int32 basePoints = int32(std::min(oldPower, FurorChance)); + target->SetPower(POWER_ENERGY, 0); + target->CastCustomSpell(target, 17099, &basePoints, NULL, NULL, true, NULL, this); + } + break; + case FORM_BEAR: + case FORM_DIREBEAR: + if (urand(0, 99) < FurorChance) + target->CastSpell(target, 17057, true); + default: + { + uint32 newEnergy = std::min(target->GetPower(POWER_ENERGY), FurorChance); + target->SetPower(POWER_ENERGY, newEnergy); + } + break; + } + break; + } + default: + break; + } } - case SPELL_AURA_DUMMY: - // Haunting Spirits - if (GetId() == 7057) - target->CastSpell((Unit*)NULL , GetAmount(), true); - break; - case SPELL_AURA_PERIODIC_DUMMY: - PeriodicDummyTick(target, caster); - break; - case SPELL_AURA_PERIODIC_TRIGGER_SPELL: - TriggerSpell(target, caster); - break; - case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE: - TriggerSpellWithValue(target, caster); - break; - default: - break; - } -} + // stop handling the effect if it was removed by linked event + if (aurApp->GetRemoveMode()) + return; -void AuraEffect::PeriodicDummyTick(Unit* target, Unit* caster) const -{ - switch (GetSpellProto()->SpellFamilyName) + target->SetShapeshiftForm(form); + } + else { - case SPELLFAMILY_GENERIC: - switch (GetId()) + // reset model id if no other auras present + // may happen when aura is applied on linked event on aura removal + if (!target->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) { - // Forsaken Skills - case 7054: + target->SetShapeshiftForm(FORM_NONE); + if (target->getClass() == CLASS_DRUID) { - // Possibly need cast one of them (but - // 7038 Forsaken Skill: Swords - // 7039 Forsaken Skill: Axes - // 7040 Forsaken Skill: Daggers - // 7041 Forsaken Skill: Maces - // 7042 Forsaken Skill: Staves - // 7043 Forsaken Skill: Bows - // 7044 Forsaken Skill: Guns - // 7045 Forsaken Skill: 2H Axes - // 7046 Forsaken Skill: 2H Maces - // 7047 Forsaken Skill: 2H Swords - // 7048 Forsaken Skill: Defense - // 7049 Forsaken Skill: Fire - // 7050 Forsaken Skill: Frost - // 7051 Forsaken Skill: Holy - // 7053 Forsaken Skill: Shadow - return; + target->setPowerType(POWER_MANA); + // Remove movement impairing effects also when shifting out + target->RemoveMovementImpairingAuras(); } - case 54798: // FLAMING Arrow Triggered Effect - { - if (!target || !target->ToCreature() || !caster->IsVehicle()) - return; - - Unit *rider = caster->GetVehicleKit()->GetPassenger(0); - if (!rider) - return; - - // set ablaze - if (target->HasAuraEffect(54683, EFFECT_0)) - return; - else - target->CastSpell(target, 54683, true); + } - // Credit Frostworgs - if (target->GetEntry() == 29358) - rider->CastSpell(rider, 54896, true); - // Credit Frost Giants - else if (target->GetEntry() == 29351) - rider->CastSpell(rider, 54893, true); + if (modelid > 0) + target->RestoreDisplayId(); + switch (form) + { + // Nordrassil Harness - bonus + case FORM_BEAR: + case FORM_DIREBEAR: + case FORM_CAT: + if (AuraEffect* dummy = target->GetAuraEffect(37315, 0)) + target->CastSpell(target, 37316, true, NULL, dummy); break; - } - case 62292: // Blaze (Pool of Tar) - // should we use custom damage? - target->CastSpell((Unit*)NULL, m_spellProto->EffectTriggerSpell[m_effIndex], true); + // Nordrassil Regalia - bonus + case FORM_MOONKIN: + if (AuraEffect* dummy = target->GetAuraEffect(37324, 0)) + target->CastSpell(target, 37325, true, NULL, dummy); break; - case 62399: // Overload Circuit - if (target->GetMap()->IsDungeon() && int(target->GetAppliedAuras().count(62399)) >= (target->GetMap()->IsHeroic() ? 4 : 2)) + case FORM_BATTLESTANCE: + case FORM_DEFENSIVESTANCE: + case FORM_BERSERKERSTANCE: + { + uint32 Rage_val = 0; + // Defensive Tactics + if (form == FORM_DEFENSIVESTANCE) { - target->CastSpell(target, 62475, true); // System Shutdown - if (Unit *veh = target->GetVehicleBase()) - veh->CastSpell(target, 62475, true); + if (AuraEffect const* aurEff = target->IsScriptOverriden(m_spellProto, 831)) + Rage_val += aurEff->GetAmount() * 10; } - break; - case 64821: // Fuse Armor (Razorscale) - if (GetBase()->GetStackAmount() == GetSpellProto()->StackAmount) + // Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch) + if (target->GetTypeId() == TYPEID_PLAYER) { - target->CastSpell(target, 64774, true, NULL, NULL, GetCasterGUID()); - target->RemoveAura(64821); - } - break; - } - break; - case SPELLFAMILY_MAGE: - { - // Mirror Image - if (GetId() == 55342) - // Set name of summons to name of caster - target->CastSpell((Unit *)NULL, m_spellProto->EffectTriggerSpell[m_effIndex], true); - break; - } - case SPELLFAMILY_WARLOCK: - { - switch (GetSpellProto()->Id) - { - // Demonic Circle - case 48018: - if (GameObject* obj = target->GetGameObject(GetSpellProto()->Id)) + PlayerSpellMap const& sp_list = target->ToPlayer()->GetSpellMap(); + for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) { - if (target->IsWithinDist(obj, GetSpellMaxRange(48020, true))) - { - if (!target->HasAura(62388)) - target->CastSpell(target, 62388, true); - } - else - target->RemoveAura(62388); + if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) continue; + SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); + if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellIconID == 139) + Rage_val += target->CalculateSpellDamage(target, spellInfo, 0) * 10; } - break; + } + if (target->GetPower(POWER_RAGE) > Rage_val) + target->SetPower(POWER_RAGE, Rage_val); + break; } - break; + default: + break; } - case SPELLFAMILY_DRUID: + } + + // adding/removing linked auras + // add/remove the shapeshift aura's boosts + HandleShapeshiftBoosts(target, apply); + + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->InitDataForForm(); + + if (target->getClass() == CLASS_DRUID) + { + // Dash + if (AuraEffect * aurEff =target->GetAuraEffect(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8)) + aurEff->RecalculateAmount(); + + // Disarm handling + // If druid shifts while being disarmed we need to deal with that since forms aren't affected by disarm + // and also HandleAuraModDisarm is not triggered + if (!target->CanUseAttackType(BASE_ATTACK)) { - switch (GetSpellProto()->Id) + if (Item *pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)) { - // Frenzied Regeneration - case 22842: - { - // Converts up to 10 rage per second into health for $d. Each point of rage is converted into ${$m2/10}.1% of max health. - // Should be manauser - if (target->getPowerType() != POWER_RAGE) - break; - uint32 rage = target->GetPower(POWER_RAGE); - // Nothing todo - if (rage == 0) - break; - int32 mod = (rage < 100) ? rage : 100; - int32 points = target->CalculateSpellDamage(target, GetSpellProto(), 1); - int32 regen = target->GetMaxHealth() * (mod * points / 10) / 1000; - target->CastCustomSpell(target, 22845, ®en, 0, 0, true, 0, this); - target->SetPower(POWER_RAGE, rage-mod); - break; - } - // Force of Nature - case 33831: - break; + target->ToPlayer()->_ApplyWeaponDamage(EQUIPMENT_SLOT_MAINHAND, pItem->GetTemplate(), NULL, apply); } - break; } - case SPELLFAMILY_ROGUE: - { - switch (GetSpellProto()->Id) - { - // Master of Subtlety - case 31666: - if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) - target->RemoveAurasDueToSpell(31665); - break; - // Killing Spree - case 51690: - { - // TODO: this should use effect[1] of 51690 - UnitList targets; - { - // eff_radius == 0 - float radius = GetSpellMaxRange(GetSpellProto(), false); - - CellPair p(Trinity::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - - Trinity::AnyUnfriendlyVisibleUnitInObjectRangeCheck u_check(caster, caster, radius); - Trinity::UnitListSearcher checker(caster, targets, u_check); + } - TypeContainerVisitor, GridTypeMapContainer > grid_object_checker(checker); - TypeContainerVisitor, WorldTypeMapContainer > world_object_checker(checker); + // stop handling the effect if it was removed by linked event + if (apply && aurApp->GetRemoveMode()) + return; - cell.Visit(p, grid_object_checker, *GetBase()->GetOwner()->GetMap(), *caster, radius); - cell.Visit(p, world_object_checker, *GetBase()->GetOwner()->GetMap(), *caster, radius); - } + if (target->GetTypeId() == TYPEID_PLAYER) + { + SpellShapeshiftEntry const *shapeInfo = sSpellShapeshiftStore.LookupEntry(form); + // Learn spells for shapeshift form - no need to send action bars or add spells to spellbook + for (uint8 i = 0; istanceSpell[i]) + continue; + if (apply) + target->ToPlayer()->AddTemporarySpell(shapeInfo->stanceSpell[i]); + else + target->ToPlayer()->RemoveTemporarySpell(shapeInfo->stanceSpell[i]); + } + } +} - if (targets.empty()) - return; +void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; - UnitList::const_iterator itr = targets.begin(); - std::advance(itr, rand()%targets.size()); - Unit* spellTarget = *itr; + Unit* target = aurApp->GetTarget(); - target->CastSpell(spellTarget, 57840, true); - target->CastSpell(spellTarget, 57841, true); - break; - } - // Overkill - case 58428: - if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) - target->RemoveAurasDueToSpell(58427); - break; - } - break; - } - case SPELLFAMILY_HUNTER: + if (apply) + { + // update active transform spell only when transform or shapeshift not set or not overwriting negative by positive case + if (!target->GetModelForForm(target->GetShapeshiftForm()) || !IsPositiveSpell(GetId())) { - // Explosive Shot - if (GetSpellProto()->SpellFamilyFlags[1] & 0x80000000) + // special case (spell specific functionality) + if (GetMiscValue() == 0) { - if (caster) - caster->CastCustomSpell(53352, SPELLVALUE_BASE_POINT0, m_amount, target, true, NULL, this); - break; + switch (GetId()) + { + // Orb of Deception + case 16739: + { + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + switch (target->getRace()) + { + // Blood Elf + case RACE_BLOODELF: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 17829 : 17830); + break; + // Orc + case RACE_ORC: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 10139 : 10140); + break; + // Troll + case RACE_TROLL: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 10135 : 10134); + break; + // Tauren + case RACE_TAUREN: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 10136 : 10147); + break; + // Undead + case RACE_UNDEAD_PLAYER: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 10146 : 10145); + break; + // Draenei + case RACE_DRAENEI: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 17827 : 17828); + break; + // Dwarf + case RACE_DWARF: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 10141 : 10142); + break; + // Gnome + case RACE_GNOME: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 10148 : 10149); + break; + // Human + case RACE_HUMAN: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 10137 : 10138); + break; + // Night Elf + case RACE_NIGHTELF: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 10143 : 10144); + break; + default: + break; + } + break; + } + // Murloc costume + case 42365: + target->SetDisplayId(21723); + break; + // Dread Corsair + case 50517: + // Corsair Costume + case 51926: + { + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + switch (target->getRace()) + { + // Blood Elf + case RACE_BLOODELF: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25032 : 25043); + break; + // Orc + case RACE_ORC: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25039 : 25050); + break; + // Troll + case RACE_TROLL: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25041 : 25052); + break; + // Tauren + case RACE_TAUREN: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25040 : 25051); + break; + // Undead + case RACE_UNDEAD_PLAYER: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25042 : 25053); + break; + // Draenei + case RACE_DRAENEI: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25033 : 25044); + break; + // Dwarf + case RACE_DWARF: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25034 : 25045); + break; + // Gnome + case RACE_GNOME: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25035 : 25046); + break; + // Human + case RACE_HUMAN: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25037 : 25048); + break; + // Night Elf + case RACE_NIGHTELF: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 25038 : 25049); + break; + default: + break; + } + break; + } + // Pygmy Oil + case 53806: + target->SetDisplayId(22512); + break; + // Honor the Dead + case 65386: + case 65495: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 29203 : 29204); + break; + // Darkspear Pride + case 75532: + target->SetDisplayId(target->getGender() == GENDER_MALE ? 31737 : 31738); + break; + default: + break; + } } - switch (GetSpellProto()->Id) + else { - // Feeding Frenzy Rank 1 - case 53511: - if (target->getVictim() && target->getVictim()->HealthBelowPct(35)) - target->CastSpell(target, 60096, true, 0, this); - return; - // Feeding Frenzy Rank 2 - case 53512: - if (target->getVictim() && target->getVictim()->HealthBelowPct(35)) - target->CastSpell(target, 60097, true, 0, this); - return; - default: - break; + CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(GetMiscValue()); + if (!ci) + { + target->SetDisplayId(16358); // pig pink ^_^ + sLog->outError("Auras: unknown creature id = %d (only need its modelid) From Spell Aura Transform in Spell ID = %d", GetMiscValue(), GetId()); + } + else + { + uint32 model_id = 0; + + if (uint32 modelid = ci->GetRandomValidModelId()) + model_id = modelid; // Will use the default model here + + // Polymorph (sheep) + if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && GetSpellProto()->SpellIconID == 82 && GetSpellProto()->SpellVisual[0] == 12978) + if (Unit* caster = GetCaster()) + if (caster->HasAura(52648)) // Glyph of the Penguin + model_id = 26452; + + target->SetDisplayId(model_id); + + // Dragonmaw Illusion (set mount model also) + if (GetId() == 42016 && target->GetMountID() && !target->GetAuraEffectsByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED).empty()) + target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 16314); + } } - break; } - case SPELLFAMILY_SHAMAN: - if (GetId() == 52179) // Astral Shift - { - // Periodic need for remove visual on stun/fear/silence lost - if (!(target->GetUInt32Value(UNIT_FIELD_FLAGS)&(UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED))) - target->RemoveAurasDueToSpell(52179); - break; - } - break; - case SPELLFAMILY_DEATHKNIGHT: - switch (GetId()) - { - case 49016: // Hysteria - uint32 damage = uint32(target->CountPctFromMaxHealth(1)); - target->DealDamage(target, damage, NULL, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); - break; - } - // Death and Decay - if (GetSpellProto()->SpellFamilyFlags[0] & 0x20) - { - if (caster) - caster->CastCustomSpell(target, 52212, &m_amount, NULL, NULL, true, 0, this); - break; - } - // Blood of the North - // Reaping - // Death Rune Mastery - if (GetSpellProto()->SpellIconID == 3041 || GetSpellProto()->SpellIconID == 22 || GetSpellProto()->SpellIconID == 2622) + + // update active transform spell only when transform or shapeshift not set or not overwriting negative by positive case + if (!target->getTransForm() || !IsPositiveSpell(GetId()) || IsPositiveSpell(target->getTransForm())) + target->setTransForm(GetId()); + + // polymorph case + if ((mode & AURA_EFFECT_HANDLE_REAL) && target->GetTypeId() == TYPEID_PLAYER && target->IsPolymorphed()) + { + // for players, start regeneration after 1s (in polymorph fast regeneration case) + // only if caster is Player (after patch 2.4.2) + if (IS_PLAYER_GUID(GetCasterGUID())) + target->ToPlayer()->setRegenTimerCount(1*IN_MILLISECONDS); + + //dismount polymorphed target (after patch 2.4.2) + if (target->IsMounted()) + target->RemoveAurasByType(SPELL_AURA_MOUNTED); + } + } + else + { + // HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true) will reapply it if need + if (target->getTransForm() == GetId()) + target->setTransForm(0); + + target->RestoreDisplayId(); + + // Dragonmaw Illusion (restore mount model) + if (GetId() == 42016 && target->GetMountID() == 16314) + { + if (!target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).empty()) { - if (target->GetTypeId() != TYPEID_PLAYER) - return; - if (target->ToPlayer()->getClass() != CLASS_DEATH_KNIGHT) - return; + uint32 cr_id = target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetMiscValue(); + if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(cr_id)) + { + uint32 team = 0; + if (target->GetTypeId() == TYPEID_PLAYER) + team = target->ToPlayer()->GetTeam(); - // timer expired - remove death runes - target->ToPlayer()->RemoveRunesByAuraEffect(this); + uint32 displayID = sObjectMgr->ChooseDisplayId(team, ci); + sObjectMgr->GetCreatureModelRandomGender(&displayID); + + target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, displayID); + } } - break; - default: - break; + } } } -void AuraEffect::TriggerSpell(Unit* target, Unit* caster) const +void AuraEffect::HandleAuraModScale(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!caster || !target) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) return; - Unit* triggerTarget = target; + Unit* target = aurApp->GetTarget(); - // generic casting code with custom spells and target/caster customs - uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[GetEffIndex()]; + target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X, (float)GetAmount(), apply); +} - SpellEntry const *triggeredSpellInfo = sSpellStore.LookupEntry(triggerSpellId); - SpellEntry const *auraSpellInfo = GetSpellProto(); - uint32 auraId = auraSpellInfo->Id; +void AuraEffect::HandleAuraCloneCaster(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; - // specific code for cases with no trigger spell provided in field - if (triggeredSpellInfo == NULL) + Unit* target = aurApp->GetTarget(); + + if (apply) { - switch (auraSpellInfo->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - { - switch (auraId) - { - // Thaumaturgy Channel - case 9712: - triggerSpellId = 21029; - break; - // Brood Affliction: Bronze - case 23170: - triggerSpellId = 23171; - return; - // Restoration - case 24379: - case 23493: - { - int32 heal = caster->CountPctFromMaxHealth(10); - caster->HealBySpell(target, auraSpellInfo, heal); + Unit* caster = GetCaster(); + if (!caster || caster == target) + return; + // What must be cloned? at least display and scale + target->SetDisplayId(caster->GetDisplayId()); + target->SetCreatorGUID(caster->GetGUID()); + //target->SetFloatValue(OBJECT_FIELD_SCALE_X, caster->GetFloatValue(OBJECT_FIELD_SCALE_X)); // we need retail info about how scaling is handled (aura maybe?) + target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE); + } + else + { + target->SetCreatorGUID(0); + target->SetDisplayId(target->GetNativeDisplayId()); + target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE); + } +} - int32 mana = caster->GetMaxPower(POWER_MANA); - if (mana) - { - mana /= 10; - caster->EnergizeBySpell(caster, 23493, mana, POWER_MANA); - } - return; - } - // Nitrous Boost - case 27746: - if (target->GetPower(POWER_MANA) >= 10) - { - target->ModifyPower(POWER_MANA, -10); - target->SendEnergizeSpellLog(caster, 27746, 10, POWER_MANA); - } - else - target->RemoveAurasDueToSpell(27746); - return; - // Frost Blast - case 27808: - caster->CastCustomSpell(29879, SPELLVALUE_BASE_POINT0, int32(target->CountPctFromMaxHealth(21)), target, true, NULL, this); - return; - // Detonate Mana - case 27819: - if (int32 mana = (int32)(target->GetMaxPower(POWER_MANA) / 10)) - { - mana = target->ModifyPower(POWER_MANA, -mana); - target->CastCustomSpell(27820, SPELLVALUE_BASE_POINT0, -mana*10, target, true, NULL, this); - } - return; - // Inoculate Nestlewood Owlkin - case 29528: - if (triggerTarget->GetTypeId() != TYPEID_UNIT)// prevent error reports in case ignored player target - return; - break; - // Feed Captured Animal - case 29917: - triggerSpellId = 29916; - break; - // Extract Gas - case 30427: - { - // move loot to player inventory and despawn target - if (caster->GetTypeId() == TYPEID_PLAYER && - triggerTarget->GetTypeId() == TYPEID_UNIT && - triggerTarget->ToCreature()->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD) - { - Player* player = (Player*)caster; - Creature* creature = triggerTarget->ToCreature(); - // missing lootid has been reported on startup - just return - if (!creature->GetCreatureInfo()->SkinLootId) - return; +/************************/ +/*** FIGHT ***/ +/************************/ - player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, true); +void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - creature->DespawnOrUnsummon(); - } - return; - } - // Quake - case 30576: triggerSpellId = 30571; break; - // Doom - // TODO: effect trigger spell may be independant on spell targets, and executed in spell finish phase - // so instakill will be naturally done before trigger spell - case 31347: - { - target->CastSpell(target, 31350, true, NULL, this); - target->Kill(target); - return; - } - // Spellcloth - case 31373: - { - // Summon Elemental after create item - target->SummonCreature(17870, 0, 0, 0, target->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); - return; - } - // Flame Quills - case 34229: - { - // cast 24 spells 34269-34289, 34314-34316 - for (uint32 spell_id = 34269; spell_id != 34290; ++spell_id) - caster->CastSpell(target, spell_id, true, NULL, this); - for (uint32 spell_id = 34314; spell_id != 34317; ++spell_id) - caster->CastSpell(target, spell_id, true, NULL, this); - return; - } - // Remote Toy - case 37027: triggerSpellId = 37029; break; - // Eye of Grillok - case 38495: - { - target->CastSpell(target, 38530, true, NULL, this); - return; - } - // Absorb Eye of Grillok (Zezzak's Shard) - case 38554: - { - if (target->GetTypeId() != TYPEID_UNIT) - return; + Unit* target = aurApp->GetTarget(); - caster->CastSpell(caster, 38495, true, NULL, this); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - Creature* creatureTarget = target->ToCreature(); + if (apply) + { + /* + WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); + data<GetGUID(); + data<SendMessageToSet(&data, true); + */ - creatureTarget->DespawnOrUnsummon(); - return; - } - // Tear of Azzinoth Summon Channel - it's not really supposed to do anything, and this only prevents the console spam - case 39857: - triggerSpellId = 39856; - break; - // Personalized Weather - case 46736: - triggerSpellId = 46737; - break; - // Shield Level 1 - case 63130: - // Shield Level 2 - case 63131: - // Shield Level 3 - case 63132: - // Ball of Flames Visual - case 71706: - return; - } - break; - } - case SPELLFAMILY_MAGE: - { - switch(auraId) - { - // Invisibility - case 66: - // Here need periodic triger reducing threat spell (or do it manually) - return; - } - break; - } - case SPELLFAMILY_DRUID: - { - switch(auraId) - { - // Cat Form - // triggerSpellId not set and unknown effect triggered in this case, ignoring for while - case 768: - return; - } - break; - } - case SPELLFAMILY_SHAMAN: + UnitList targets; + Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetMap()->GetVisibilityRange()); + Trinity::UnitListSearcher searcher(target, targets, u_check); + target->VisitNearbyObject(target->GetMap()->GetVisibilityRange(), searcher); + for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter) + { + if (!(*iter)->HasUnitState(UNIT_STAT_CASTING)) + continue; + + for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) { - switch(auraId) + if ((*iter)->GetCurrentSpell(i) + && (*iter)->GetCurrentSpell(i)->m_targets.getUnitTargetGUID() == target->GetGUID()) { - // Lightning Shield (The Earthshatterer set trigger after cast Lighting Shield) - case 28820: - { - // Need remove self if Lightning Shield not active - if (!target->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400)) - target->RemoveAurasDueToSpell(28820); - return; - } - // Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus) - case 38443: - { - bool all = true; - for (int i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) - { - if (!target->m_SummonSlot[i]) - { - all = false; - break; - } - } - - if (all) - caster->CastSpell(target, 38437, true, NULL, this); - else - target->RemoveAurasDueToSpell(38437); - return; - } + (*iter)->InterruptSpell(CurrentSpellTypes(i), false); } - break; } - default: - break; } + target->CombatStop(); + target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + + // prevent interrupt message + if (GetCasterGUID() == target->GetGUID() && target->GetCurrentSpell(CURRENT_GENERIC_SPELL)) + target->FinishSpell(CURRENT_GENERIC_SPELL, false); + target->InterruptNonMeleeSpells(true); + target->getHostileRefManager().deleteReferences(); + + // stop handling the effect if it was removed by linked event + if (aurApp->GetRemoveMode()) + return; + // blizz like 2.0.x + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); + // blizz like 2.0.x + target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH); + // blizz like 2.0.x + target->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); + + target->AddUnitState(UNIT_STAT_DIED); } else { - // Spell exist but require custom code - switch (auraId) - { - // Pursuing Spikes (Anub'arak) - case 65920: - case 65922: - case 65923: - { - Unit *permafrostCaster = NULL; - if (caster->HasAura(66193)) permafrostCaster = caster->GetAura(66193)->GetCaster(); - if (caster->HasAura(67855)) permafrostCaster = caster->GetAura(67855)->GetCaster(); - if (caster->HasAura(67856)) permafrostCaster = caster->GetAura(67856)->GetCaster(); - if (caster->HasAura(67857)) permafrostCaster = caster->GetAura(67857)->GetCaster(); - - if (permafrostCaster) - { - if (Creature *permafrostCasterAsCreature = permafrostCaster->ToCreature()) - permafrostCasterAsCreature->DespawnOrUnsummon(3000); - - caster->CastSpell(caster, 66181, false); - caster->RemoveAllAuras(); - if (Creature *casterAsCreature = caster->ToCreature()) - casterAsCreature->DisappearAndDie(); - } - } - break; - // Mana Tide - case 16191: - target->CastCustomSpell(triggerTarget, triggerSpellId, &m_amount, NULL, NULL, true, NULL, this); - return; - // Negative Energy Periodic - case 46284: - caster->CastCustomSpell(triggerSpellId, SPELLVALUE_MAX_TARGETS, m_tickNumber / 10 + 1, NULL, true, NULL, this); - return; - // Poison (Grobbulus) - case 28158: - case 54362: - // Slime Pool (Dreadscale & Acidmaw) - case 66882: - target->CastCustomSpell(triggerSpellId, SPELLVALUE_RADIUS_MOD, (int32)((((float)m_tickNumber / 60) * 0.9f + 0.1f) * 10000 * 2 / 3), NULL, true, NULL, this); - return; - // Beacon of Light - case 53563: - { - Unit* triggerCaster = (Unit *)(GetBase()->GetOwner()); - triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, 0, this, triggerCaster->GetGUID()); - return; - } - // Slime Spray - temporary here until preventing default effect works again - // added on 9.10.2010 - case 69508: - { - caster->CastSpell(triggerTarget, triggerSpellId, true, NULL, NULL, caster->GetGUID()); - return; - } + /* + WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); + data<GetGUID(); + data<SendMessageToSet(&data, true); + */ + // blizz like 2.0.x + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); + // blizz like 2.0.x + target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH); + // blizz like 2.0.x + target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); + + target->ClearUnitState(UNIT_STAT_DIED); + } +} + +void AuraEffect::HandleModUnattackable(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; + + Unit* target = aurApp->GetTarget(); + + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (!apply && target->HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) + return; + + target->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, apply); + + // call functions which may have additional effects after chainging state of unit + if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) + { + target->CombatStop(); + target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + } +} + +void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); + + AuraType type = GetAuraType(); + + //Prevent handling aura twice + if ((apply) ? target->GetAuraEffectsByType(type).size() > 1 : target->HasAuraType(type)) + return; + + uint32 field, flag, slot; + WeaponAttackType attType; + switch (type) + { + case SPELL_AURA_MOD_DISARM: + field=UNIT_FIELD_FLAGS; + flag=UNIT_FLAG_DISARMED; + slot=EQUIPMENT_SLOT_MAINHAND; + attType=BASE_ATTACK; + break; + case SPELL_AURA_MOD_DISARM_OFFHAND: + field=UNIT_FIELD_FLAGS_2; + flag=UNIT_FLAG2_DISARM_OFFHAND; + slot=EQUIPMENT_SLOT_OFFHAND; + attType=OFF_ATTACK; + break; + case SPELL_AURA_MOD_DISARM_RANGED: + field=UNIT_FIELD_FLAGS_2; + flag=UNIT_FLAG2_DISARM_RANGED; + slot=EQUIPMENT_SLOT_RANGED; + attType=RANGED_ATTACK; + break; + default: + return; + } + + if (!apply) + target->RemoveFlag(field, flag); + + if (apply) + target->SetFlag(field, flag); + + // Handle damage modifcation, shapeshifted druids are not affected + if (target->GetTypeId() == TYPEID_PLAYER && !target->IsInFeralForm()) + { + if (Item *pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + { + uint8 attacktype = Player::GetAttackBySlot(slot); + + if (attacktype < MAX_ATTACK) + target->ToPlayer()->_ApplyWeaponDamage(slot, pItem->GetTemplate(), NULL, !apply); } } - // Reget trigger spell proto - triggeredSpellInfo = sSpellStore.LookupEntry(triggerSpellId); + if (target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->GetCurrentEquipmentId()) + target->UpdateDamagePhysical(attType); +} + +void AuraEffect::HandleAuraModSilence(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); - if (triggeredSpellInfo) + if (apply) { - Unit* triggerCaster = GetTriggeredSpellCaster(triggeredSpellInfo, caster, triggerTarget); - triggerCaster->CastSpell(triggerTarget, triggeredSpellInfo, true, NULL, this); - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::TriggerSpell: Spell %u Trigger %u", GetId(), triggeredSpellInfo->Id); + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED); + + // call functions which may have additional effects after chainging state of unit + // Stop cast only spells vs PreventionType == SPELL_PREVENTION_TYPE_SILENCE + for (uint32 i = CURRENT_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) + if (Spell* spell = target->GetCurrentSpell(CurrentSpellTypes(i))) + if (spell->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) + // Stop spells on prepare or casting state + target->InterruptSpell(CurrentSpellTypes(i), false); } else { - Creature* c = triggerTarget->ToCreature(); - if (!c || (c && !sScriptMgr->OnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex()), triggerTarget->ToCreature())) || - (c && !c->AI()->sOnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex())))) - sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::TriggerSpell: Spell %u has non-existent spell %u in EffectTriggered[%d] and is therefor not triggered.", GetId(), triggerSpellId, GetEffIndex()); + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(SPELL_AURA_MOD_SILENCE) || target->HasAuraType(SPELL_AURA_MOD_PACIFY_SILENCE)) + return; + + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED); } } -void AuraEffect::TriggerSpellWithValue(Unit* target, Unit* caster) const +void AuraEffect::HandleAuraModPacify(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!caster || !target) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; - Unit* triggerTarget = target; + Unit* target = aurApp->GetTarget(); - uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[m_effIndex]; - SpellEntry const *triggeredSpellInfo = sSpellStore.LookupEntry(triggerSpellId); - if (triggeredSpellInfo) + if (apply) + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); + else { - Unit* triggerCaster = GetTriggeredSpellCaster(triggeredSpellInfo, caster, triggerTarget); + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(SPELL_AURA_MOD_PACIFY) || target->HasAuraType(SPELL_AURA_MOD_PACIFY_SILENCE)) + return; + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); + } +} + +void AuraEffect::HandleAuraModPacifyAndSilence(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; + + Unit* target = aurApp->GetTarget(); - // generic casting code with custom spells and target/caster customs - int32 basepoints0 = GetAmount(); - triggerCaster->CastCustomSpell(triggerTarget, triggerSpellId, &basepoints0, 0, 0, true, 0, this); + // Vengeance of the Blue Flight (TODO: REMOVE THIS!) + if (m_spellProto->Id == 45839) + { + if (apply) + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + else + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); } - else - sLog->outError("AuraEffect::TriggerSpellWithValue: Spell %u has value 0 in EffectTriggered[%d] and is therefor not handled. Define as custom case?", GetId(), GetEffIndex()); + if (!(apply)) + { + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(SPELL_AURA_MOD_PACIFY_SILENCE)) + return; + } + HandleAuraModPacify(aurApp, mode, apply); + HandleAuraModSilence(aurApp, mode, apply); } -bool AuraEffect::IsAffectedOnSpell(SpellEntry const *spell) const +void AuraEffect::HandleAuraAllowOnlyAbility(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!spell) - return false; - // Check family name - if (spell->SpellFamilyName != m_spellProto->SpellFamilyName) - return false; + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; - // Check EffectClassMask - if (m_spellProto->EffectSpellClassMask[m_effIndex] & spell->SpellFamilyFlags) - return true; - return false; + Unit* target = aurApp->GetTarget(); + + if (target->GetTypeId() == TYPEID_PLAYER) + { + if (apply) + target->SetFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY); + else + { + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(SPELL_AURA_ALLOW_ONLY_ABILITY)) + return; + target->RemoveFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY); + } + } } -void AuraEffect::CleanupTriggeredSpells(Unit* target) +/****************************/ +/*** TRACKING ***/ +/****************************/ + +void AuraEffect::HandleAuraTrackCreatures(AuraApplication const* aurApp, uint8 mode, bool apply) const { - uint32 tSpellId = m_spellProto->EffectTriggerSpell[GetEffIndex()]; - if (!tSpellId) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; - SpellEntry const* tProto = sSpellStore.LookupEntry(tSpellId); - if (!tProto) + Unit* target = aurApp->GetTarget(); + + if (target->GetTypeId() != TYPEID_PLAYER) return; - if (GetSpellDuration(tProto) != -1) + target->SetUInt32Value(PLAYER_TRACK_CREATURES, (apply) ? ((uint32)1)<<(GetMiscValue()-1) : 0); +} + +void AuraEffect::HandleAuraTrackResources(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; - // needed for spell 43680, maybe others - // TODO: is there a spell flag, which can solve this in a more sophisticated way? - if (m_spellProto->EffectApplyAuraName[GetEffIndex()] == SPELL_AURA_PERIODIC_TRIGGER_SPELL && - uint32(GetSpellDuration(m_spellProto)) == m_spellProto->EffectAmplitude[GetEffIndex()]) + Unit* target = aurApp->GetTarget(); + + if (target->GetTypeId() != TYPEID_PLAYER) return; - target->RemoveAurasDueToSpell(tSpellId, GetCasterGUID()); + target->SetUInt32Value(PLAYER_TRACK_RESOURCES, (apply) ? ((uint32)1)<<(GetMiscValue()-1): 0); } -void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const +void AuraEffect::HandleAuraTrackStealthed(AuraApplication const* aurApp, uint8 mode, bool apply) const { - uint32 spellId = 0; - uint32 spellId2 = 0; - //uint32 spellId3 = 0; - uint32 HotWSpellId = 0; + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; - switch(GetMiscValue()) + Unit* target = aurApp->GetTarget(); + + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + if (!(apply)) { - case FORM_CAT: - spellId = 3025; - HotWSpellId = 24900; - break; - case FORM_TREE: - spellId = 34123; - break; - case FORM_TRAVEL: - spellId = 5419; - break; - case FORM_AQUA: - spellId = 5421; - break; - case FORM_BEAR: - spellId = 1178; - spellId2 = 21178; - HotWSpellId = 24899; - break; - case FORM_DIREBEAR: - spellId = 9635; - spellId2 = 21178; - HotWSpellId = 24899; - break; - case FORM_BATTLESTANCE: - spellId = 21156; - break; - case FORM_DEFENSIVESTANCE: - spellId = 7376; - break; - case FORM_BERSERKERSTANCE: - spellId = 7381; - break; - case FORM_MOONKIN: - spellId = 24905; - spellId2 = 69366; - break; - case FORM_FLIGHT: - spellId = 33948; - spellId2 = 34764; - break; - case FORM_FLIGHT_EPIC: - spellId = 40122; - spellId2 = 40121; - break; - case FORM_METAMORPHOSIS: - spellId = 54817; - spellId2 = 54879; - break; - case FORM_SPIRITOFREDEMPTION: - spellId = 27792; - spellId2 = 27795; // must be second, this important at aura remove to prevent to early iterator invalidation. - break; - case FORM_SHADOW: - spellId = 49868; - spellId2 = 71167; - break; - case FORM_GHOSTWOLF: - spellId = 67116; - break; - case FORM_GHOUL: - case FORM_AMBIENT: - case FORM_STEALTH: - case FORM_CREATURECAT: - case FORM_CREATUREBEAR: - break; - default: - break; - } - - if (apply) - { - // Remove cooldown of spells triggered on stance change - they may share cooldown with stance spell - if (spellId) - { - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->RemoveSpellCooldown(spellId); - target->CastSpell(target, spellId, true, NULL, this); - } - - if (spellId2) - { - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->RemoveSpellCooldown(spellId2); - target->CastSpell(target, spellId2, true, NULL, this); - } - - if (target->GetTypeId() == TYPEID_PLAYER) - { - const PlayerSpellMap& sp_list = target->ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) continue; - if (itr->first == spellId || itr->first == spellId2) continue; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (!spellInfo || !(spellInfo->Attributes & (SPELL_ATTR0_PASSIVE | SPELL_ATTR0_HIDDEN_CLIENTSIDE))) continue; - if (spellInfo->Stances & (1<<(GetMiscValue()-1))) - target->CastSpell(target, itr->first, true, NULL, this); - } - // Leader of the Pack - if (target->ToPlayer()->HasSpell(17007)) - { - SpellEntry const *spellInfo = sSpellStore.LookupEntry(24932); - if (spellInfo && spellInfo->Stances & (1<<(GetMiscValue()-1))) - target->CastSpell(target, 24932, true, NULL, this); - } - // Improved Barkskin - apply/remove armor bonus due to shapeshift - if (target->ToPlayer()->HasSpell(63410) || target->ToPlayer()->HasSpell(63411)) - { - target->RemoveAurasDueToSpell(66530); - if (GetMiscValue() == FORM_TRAVEL || GetMiscValue() == FORM_NONE) // "while in Travel Form or while not shapeshifted" - target->CastSpell(target, 66530, true); - } - // Heart of the Wild - if (HotWSpellId) - { // hacky, but the only way as spell family is not SPELLFAMILY_DRUID - Unit::AuraEffectList const& mModTotalStatPct = target->GetAuraEffectsByType(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE); - for (Unit::AuraEffectList::const_iterator i = mModTotalStatPct.begin(); i != mModTotalStatPct.end(); ++i) - { - // Heart of the Wild - if ((*i)->GetSpellProto()->SpellIconID == 240 && (*i)->GetMiscValue() == 3) - { - int32 HotWMod = (*i)->GetAmount(); - - target->CastCustomSpell(target, HotWSpellId, &HotWMod, NULL, NULL, true, NULL, this); - break; - } - } - } - switch(GetMiscValue()) - { - case FORM_CAT: - // Savage Roar - if (target->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_DRUID, 0 , 0x10000000, 0)) - target->CastSpell(target, 62071, true); - // Nurturing Instinct - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT, SPELLFAMILY_DRUID, 2254, 0)) - { - uint32 spellId = 0; - switch (aurEff->GetId()) - { - case 33872: - spellId = 47179; - break; - case 33873: - spellId = 47180; - break; - } - target->CastSpell(target, spellId, true, NULL, this); - } - // Master Shapeshifter - Cat - if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) - { - int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48420, &bp, NULL, NULL, true); - } - break; - case FORM_DIREBEAR: - case FORM_BEAR: - // Master Shapeshifter - Bear - if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) - { - int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48418, &bp, NULL, NULL, true); - } - // Survival of the Fittest - if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, SPELLFAMILY_DRUID, 961, 0)) - { - int32 bp = 100 + SpellMgr::CalculateSpellEffectAmount(aurEff->GetSpellProto(), 2); - target->CastCustomSpell(target, 62069, &bp, NULL, NULL, true, 0, this); - } - break; - case FORM_MOONKIN: - // Master Shapeshifter - Moonkin - if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) - { - int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48421, &bp, NULL, NULL, true); - } - break; - // Master Shapeshifter - Tree of Life - case FORM_TREE: - if (AuraEffect const* aurEff = target->GetDummyAuraEffect(SPELLFAMILY_GENERIC, 2851, 0)) - { - int32 bp = aurEff->GetAmount(); - target->CastCustomSpell(target, 48422, &bp, NULL, NULL, true); - } - break; - } - } - } - else - { - if (spellId) - target->RemoveAurasDueToSpell(spellId); - if (spellId2) - target->RemoveAurasDueToSpell(spellId2); - - // Improved Barkskin - apply/remove armor bonus due to shapeshift - if (Player *pl=target->ToPlayer()) - { - if (pl->HasSpell(63410) || pl->HasSpell(63411)) - { - target->RemoveAurasDueToSpell(66530); - target->CastSpell(target, 66530, true); - } - } - - Unit::AuraApplicationMap& tAuras = target->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();) - { - if (itr->second->GetBase()->IsRemovedOnShapeLost(target)) - target->RemoveAura(itr); - else - ++itr; - } + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType())) + return; } + target->ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_TRACK_STEALTHED, apply); } -/*********************************************************/ -/*** AURA EFFECT HANDLERS ***/ -/*********************************************************/ - -/**************************************/ -/*** VISIBILITY & PHASES ***/ -/**************************************/ - -void AuraEffect::HandleModInvisibilityDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModStalked(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); - InvisibilityType type = InvisibilityType(GetMiscValue()); + // used by spells: Hunter's Mark, Mind Vision, Syndicate Tracker (MURP) DND if (apply) - { - target->m_invisibilityDetect.AddFlag(type); - target->m_invisibilityDetect.AddValue(type, GetAmount()); - } + target->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT); else { - if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY_DETECT)) - target->m_invisibilityDetect.DelFlag(type); - - target->m_invisibilityDetect.AddValue(type, -GetAmount()); + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (!target->HasAuraType(GetAuraType())) + target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT); } // call functions which may have additional effects after chainging state of unit target->UpdateObjectVisibility(); } -void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraUntrackable(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); - InvisibilityType type = InvisibilityType(GetMiscValue()); if (apply) - { - // apply glow vision - if (target->GetTypeId() == TYPEID_PLAYER) - target->SetByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); - - target->m_invisibility.AddFlag(type); - target->m_invisibility.AddValue(type, GetAmount()); - } + target->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE); else { - if (!target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) - { - // if not have different invisibility auras. - // remove glow vision - if (target->GetTypeId() == TYPEID_PLAYER) - target->RemoveByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_INVISIBILITY_GLOW); - - target->m_invisibility.DelFlag(type); - } - else - { - bool found = false; - Unit::AuraEffectList const& invisAuras = target->GetAuraEffectsByType(SPELL_AURA_MOD_INVISIBILITY); - for (Unit::AuraEffectList::const_iterator i = invisAuras.begin(); i != invisAuras.end(); ++i) - { - if (GetMiscValue() == (*i)->GetMiscValue()) - { - found = true; - break; - } - } - if (!found) - target->m_invisibility.DelFlag(type); - } - - target->m_invisibility.AddValue(type, -GetAmount()); - } - - // call functions which may have additional effects after chainging state of unit - if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) - { - // drop flag at invisibiliy in bg - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType())) + return; + target->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE); } - target->UpdateObjectVisibility(); } -void AuraEffect::HandleModStealthDetect(AuraApplication const* aurApp, uint8 mode, bool apply) const +/****************************/ +/*** SKILLS & TALENTS ***/ +/****************************/ + +void AuraEffect::HandleAuraModPetTalentsPoints(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); - StealthType type = StealthType(GetMiscValue()); - if (apply) - { - target->m_stealthDetect.AddFlag(type); - target->m_stealthDetect.AddValue(type, GetAmount()); - } - else - { - if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH_DETECT)) - target->m_stealthDetect.DelFlag(type); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - target->m_stealthDetect.AddValue(type, -GetAmount()); - } + // Recalculate pet talent points + if (Pet *pet = target->ToPlayer()->GetPet()) + pet->InitTalentForLevel(); +} - // call functions which may have additional effects after chainging state of unit - target->UpdateObjectVisibility(); +void AuraEffect::HandleAuraModSkill(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_SKILL))) + return; + Unit* target = aurApp->GetTarget(); + + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + uint32 prot = GetMiscValue(); + int32 points = GetAmount(); + + target->ToPlayer()->ModifySkillBonus(prot, ((apply) ? points: -points), GetAuraType() == SPELL_AURA_MOD_SKILL_TALENT); + if (prot == SKILL_DEFENSE) + target->ToPlayer()->UpdateDefenseBonusesMod(); } -void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, bool apply) const +/****************************/ +/*** MOVEMENT ***/ +/****************************/ + +void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); - StealthType type = StealthType(GetMiscValue()); if (apply) { - target->m_stealth.AddFlag(type); - target->m_stealth.AddValue(type, GetAmount()); - - target->SetStandFlags(UNIT_STAND_FLAGS_CREEP); - if (target->GetTypeId() == TYPEID_PLAYER) - target->SetByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_STEALTH); - } - else - { - target->m_stealth.AddValue(type, -GetAmount()); + uint32 creatureEntry = GetMiscValue(); - if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) // if last SPELL_AURA_MOD_STEALTH + // Festive Holiday Mount + if (target->HasAura(62061)) { - target->m_stealth.DelFlag(type); + if (GetBase()->HasEffectType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) + creatureEntry = 24906; + else + creatureEntry = 15665; + } - target->RemoveStandFlags(UNIT_STAND_FLAGS_CREEP); - if (target->GetTypeId() == TYPEID_PLAYER) - target->RemoveByteFlag(PLAYER_FIELD_BYTES2, 3, PLAYER_FIELD_BYTE2_STEALTH); + CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(creatureEntry); + if (!ci) + { + sLog->outErrorDb("AuraMounted: `creature_template`='%u' not found in database (only need its modelid)", GetMiscValue()); + return; } - } - // call functions which may have additional effects after chainging state of unit - if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) + uint32 team = 0; + if (target->GetTypeId() == TYPEID_PLAYER) + team = target->ToPlayer()->GetTeam(); + + uint32 displayID = sObjectMgr->ChooseDisplayId(team, ci); + sObjectMgr->GetCreatureModelRandomGender(&displayID); + + //some spell has one aura of mount and one of vehicle + for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) + if (GetSpellProto()->Effect[i] == SPELL_EFFECT_SUMMON + && GetSpellProto()->EffectMiscValue[i] == GetMiscValue()) + displayID = 0; + + target->Mount(displayID, ci->VehicleId, GetMiscValue()); + } + else { - // drop flag at stealth in bg - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + target->Unmount(); + //some mounts like Headless Horseman's Mount or broom stick are skill based spell + // need to remove ALL arura related to mounts, this will stop client crash with broom stick + // and never endless flying after using Headless Horseman's Mount + if (mode & AURA_EFFECT_HANDLE_REAL) + target->RemoveAurasByType(SPELL_AURA_MOUNTED); } - target->UpdateObjectVisibility(); } -void AuraEffect::HandleModStealthLevel(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraAllowFlight(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); - StealthType type = StealthType(GetMiscValue()); - if (apply) - target->m_stealth.AddValue(type, GetAmount()); - else - target->m_stealth.AddValue(type, -GetAmount()); + if (!apply) + { + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType()) || target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) + return; + } - // call functions which may have additional effects after chainging state of unit - target->UpdateObjectVisibility(); + if (target->GetTypeId() == TYPEID_UNIT) + target->SetFlying(apply); + + if (Player *plr = target->m_movedPlayer) + { + // allow flying + WorldPacket data; + if (apply) + data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12); + else + data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12); + data.append(target->GetPackGUID()); + data << uint32(0); // unk + plr->SendDirectMessage(&data); + } } -void AuraEffect::HandleSpiritOfRedemption(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraWaterWalk(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - // prepare spirit state - if (apply) + if (!apply) { - if (target->GetTypeId() == TYPEID_PLAYER) - { - // disable breath/etc timers - target->ToPlayer()->StopMirrorTimers(); - - // set stand state (expected in this form) - if (!target->IsStandState()) - target->SetStandState(UNIT_STAND_STATE_STAND); - } - - target->SetHealth(1); + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType())) + return; } - // die at aura end - else if (target->isAlive()) - // call functions which may have additional effects after chainging state of unit - target->setDeathState(JUST_DIED); + + WorldPacket data; + if (apply) + data.Initialize(SMSG_MOVE_WATER_WALK, 8+4); + else + data.Initialize(SMSG_MOVE_LAND_WALK, 8+4); + data.append(target->GetPackGUID()); + data << uint32(0); + target->SendMessageToSet(&data, true); } -void AuraEffect::HandleAuraGhost(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraFeatherFall(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - if (apply) + if (!apply) { - target->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); - target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); - target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_GHOST); + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType())) + return; } + + WorldPacket data; + if (apply) + data.Initialize(SMSG_MOVE_FEATHER_FALL, 8+4); else - { - if (target->HasAuraType(SPELL_AURA_GHOST)) - return; + data.Initialize(SMSG_MOVE_NORMAL_FALL, 8+4); + data.append(target->GetPackGUID()); + data << uint32(0); + target->SendMessageToSet(&data, true); - target->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST); - target->m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); - target->m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); - } + // start fall from current height + if (!apply && target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->SetFallInformation(0, target->GetPositionZ()); } -void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraHover(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); - // no-phase is also phase state so same code for apply and remove - uint32 newPhase = 0; - Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE); - if (!phases.empty()) - for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - newPhase |= (*itr)->GetMiscValue(); - - if (Player* player = target->ToPlayer()) + if (!apply) { - if (!newPhase) - newPhase = PHASEMASK_NORMAL; - - // GM-mode have mask 0xFFFFFFFF - if (player->isGameMaster()) - newPhase = 0xFFFFFFFF; - - player->SetPhaseMask(newPhase, false); - player->GetSession()->SendSetPhaseShift(newPhase); + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType())) + return; } + + WorldPacket data; + if (apply) + data.Initialize(SMSG_MOVE_SET_HOVER, 8+4); else - { - if (!newPhase) - { - newPhase = PHASEMASK_NORMAL; - if (Creature* creature = target->ToCreature()) - if (CreatureData const* data = sObjectMgr->GetCreatureData(creature->GetDBTableGUIDLow())) - newPhase = data->phaseMask; - } + data.Initialize(SMSG_MOVE_UNSET_HOVER, 8+4); + data.append(target->GetPackGUID()); + data << uint32(0); + target->SendMessageToSet(&data, true); +} - target->SetPhaseMask(newPhase, false); - } +void AuraEffect::HandleWaterBreathing(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +{ + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; - // call functions which may have additional effects after chainging state of unit - // phase auras normally not expected at BG but anyway better check - if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) + Unit* target = aurApp->GetTarget(); + + // update timers in client + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->UpdateMirrorTimers(); +} + +void AuraEffect::HandleForceMoveForward(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + return; + + Unit* target = aurApp->GetTarget(); + + if (apply) + target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE); + else { - // drop flag at invisibiliy in bg - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType())) + return; + target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE); } - - // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) - if (target->IsVisible()) - target->UpdateObjectVisibility(); } -/**********************/ -/*** UNIT MODEL ***/ -/**********************/ +/****************************/ +/*** THREAT ***/ +/****************************/ -void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); + for (int32 i = 0; i < MAX_SPELL_SCHOOL; ++i) + if (GetMiscValue() & (1 << i)) + ApplyPercentModFloatVar(target->m_threatModifier[i], float(GetAmount()), apply); +} - uint32 modelid = 0; - Powers PowerType = POWER_MANA; - ShapeshiftForm form = ShapeshiftForm(GetMiscValue()); +void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + return; - switch (form) - { - case FORM_CAT: // 0x01 - case FORM_GHOUL: // 0x07 - PowerType = POWER_ENERGY; - break; + Unit* target = aurApp->GetTarget(); - case FORM_BEAR: // 0x05 - case FORM_DIREBEAR: // 0x08 + if (!target->isAlive() || target->GetTypeId() != TYPEID_PLAYER) + return; - case FORM_BATTLESTANCE: // 0x11 - case FORM_DEFENSIVESTANCE: // 0x12 - case FORM_BERSERKERSTANCE: // 0x13 - PowerType = POWER_RAGE; - break; + Unit* caster = GetCaster(); + if (!caster || !caster->isAlive()) + return; - case FORM_TREE: // 0x02 - case FORM_TRAVEL: // 0x03 - case FORM_AQUA: // 0x04 - case FORM_AMBIENT: // 0x06 + target->getHostileRefManager().addTempThreat((float)GetAmount(), apply); +} - case FORM_STEVES_GHOUL: // 0x09 - case FORM_THARONJA_SKELETON: // 0x0A - case FORM_TEST_OF_STRENGTH: // 0x0B - case FORM_BLB_PLAYER: // 0x0C - case FORM_SHADOW_DANCE: // 0x0D - case FORM_CREATUREBEAR: // 0x0E - case FORM_CREATURECAT: // 0x0F - case FORM_GHOSTWOLF: // 0x10 +void AuraEffect::HandleModTaunt(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - case FORM_TEST: // 0x14 - case FORM_ZOMBIE: // 0x15 - case FORM_METAMORPHOSIS: // 0x16 - case FORM_UNDEAD: // 0x19 - case FORM_MASTER_ANGLER: // 0x1A - case FORM_FLIGHT_EPIC: // 0x1B - case FORM_SHADOW: // 0x1C - case FORM_FLIGHT: // 0x1D - case FORM_STEALTH: // 0x1E - case FORM_MOONKIN: // 0x1F - case FORM_SPIRITOFREDEMPTION: // 0x20 - break; - default: - sLog->outError("Auras: Unknown Shapeshift Type: %u", GetMiscValue()); - } + Unit* target = aurApp->GetTarget(); - modelid = target->GetModelForForm(form); + if (!target->isAlive() || !target->CanHaveThreatList()) + return; + + Unit* caster = GetCaster(); + if (!caster || !caster->isAlive()) + return; if (apply) + target->TauntApply(caster); + else { - // remove polymorph before changing display id to keep new display id - switch (form) - { - case FORM_CAT: - case FORM_TREE: - case FORM_TRAVEL: - case FORM_AQUA: - case FORM_BEAR: - case FORM_DIREBEAR: - case FORM_FLIGHT_EPIC: - case FORM_FLIGHT: - case FORM_MOONKIN: - { - // remove movement affects - target->RemoveMovementImpairingAuras(); + // When taunt aura fades out, mob will switch to previous target if current has less than 1.1 * secondthreat + target->TauntFadeOut(caster); + } +} - // and polymorphic affects - if (target->IsPolymorphed()) - target->RemoveAurasDueToSpell(target->getTransForm()); - break; - } - default: - break; - } +/*****************************/ +/*** CONTROL ***/ +/*****************************/ - // remove other shapeshift before applying a new one - target->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT, 0, GetBase()); +void AuraEffect::HandleModConfuse(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - // stop handling the effect if it was removed by linked event - if (aurApp->GetRemoveMode()) - return; + Unit* target = aurApp->GetTarget(); - if (modelid > 0) - target->SetDisplayId(modelid); + target->SetControlled(apply, UNIT_STAT_CONFUSED); +} - if (PowerType != POWER_MANA) - { - uint32 oldPower = target->GetPower(PowerType); - // reset power to default values only at power change - if (target->getPowerType() != PowerType) - target->setPowerType(PowerType); +void AuraEffect::HandleModFear(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - switch (form) - { - case FORM_CAT: - case FORM_BEAR: - case FORM_DIREBEAR: - { - // get furor proc chance - uint32 FurorChance = 0; - if (AuraEffect const *dummy = target->GetDummyAuraEffect(SPELLFAMILY_DRUID, 238, 0)) - FurorChance = std::max(dummy->GetAmount(), 0); + Unit* target = aurApp->GetTarget(); - switch (GetMiscValue()) - { - case FORM_CAT: - { - int32 basePoints = int32(std::min(oldPower, FurorChance)); - target->SetPower(POWER_ENERGY, 0); - target->CastCustomSpell(target, 17099, &basePoints, NULL, NULL, true, NULL, this); - } - break; - case FORM_BEAR: - case FORM_DIREBEAR: - if (urand(0, 99) < FurorChance) - target->CastSpell(target, 17057, true); - default: - { - uint32 newEnergy = std::min(target->GetPower(POWER_ENERGY), FurorChance); - target->SetPower(POWER_ENERGY, newEnergy); - } - break; - } - break; - } - default: - break; - } - } - // stop handling the effect if it was removed by linked event - if (aurApp->GetRemoveMode()) - return; + target->SetControlled(apply, UNIT_STAT_FLEEING); +} - target->SetShapeshiftForm(form); - } - else - { - // reset model id if no other auras present - // may happen when aura is applied on linked event on aura removal - if (!target->HasAuraType(SPELL_AURA_MOD_SHAPESHIFT)) - { - target->SetShapeshiftForm(FORM_NONE); - if (target->getClass() == CLASS_DRUID) - { - target->setPowerType(POWER_MANA); - // Remove movement impairing effects also when shifting out - target->RemoveMovementImpairingAuras(); - } - } +void AuraEffect::HandleAuraModStun(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - if (modelid > 0) - target->RestoreDisplayId(); + Unit* target = aurApp->GetTarget(); - switch (form) - { - // Nordrassil Harness - bonus - case FORM_BEAR: - case FORM_DIREBEAR: - case FORM_CAT: - if (AuraEffect* dummy = target->GetAuraEffect(37315, 0)) - target->CastSpell(target, 37316, true, NULL, dummy); - break; - // Nordrassil Regalia - bonus - case FORM_MOONKIN: - if (AuraEffect* dummy = target->GetAuraEffect(37324, 0)) - target->CastSpell(target, 37325, true, NULL, dummy); - break; - case FORM_BATTLESTANCE: - case FORM_DEFENSIVESTANCE: - case FORM_BERSERKERSTANCE: - { - uint32 Rage_val = 0; - // Defensive Tactics - if (form == FORM_DEFENSIVESTANCE) - { - if (AuraEffect const* aurEff = target->IsScriptOverriden(m_spellProto, 831)) - Rage_val += aurEff->GetAmount() * 10; - } - // Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch) - if (target->GetTypeId() == TYPEID_PLAYER) - { - PlayerSpellMap const& sp_list = target->ToPlayer()->GetSpellMap(); - for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr) - { - if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->disabled) continue; - SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first); - if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellIconID == 139) - Rage_val += target->CalculateSpellDamage(target, spellInfo, 0) * 10; - } - } - if (target->GetPower(POWER_RAGE) > Rage_val) - target->SetPower(POWER_RAGE, Rage_val); - break; - } - default: - break; - } + target->SetControlled(apply, UNIT_STAT_STUNNED); +} + +void AuraEffect::HandleAuraModRoot(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); + + target->SetControlled(apply, UNIT_STAT_ROOT); +} + +void AuraEffect::HandlePreventFleeing(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); + + if (target->HasAuraType(SPELL_AURA_MOD_FEAR)) + target->SetControlled(!(apply), UNIT_STAT_FLEEING); +} + +/***************************/ +/*** CHARM ***/ +/***************************/ + +void AuraEffect::HandleModPossess(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); + + Unit* caster = GetCaster(); + + // no support for posession AI yet + if (caster && caster->GetTypeId() == TYPEID_UNIT) + { + HandleModCharm(aurApp, mode, apply); + return; } - // adding/removing linked auras - // add/remove the shapeshift aura's boosts - HandleShapeshiftBoosts(target, apply); + if (apply) + target->SetCharmedBy(caster, CHARM_TYPE_POSSESS, aurApp); + else + target->RemoveCharmedBy(caster); +} - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->InitDataForForm(); +// only one spell has this aura +void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - if (target->getClass() == CLASS_DRUID) + Unit* caster = GetCaster(); + if (!caster || caster->GetTypeId() != TYPEID_PLAYER) + return; + + //seems it may happen that when removing it is no longer owner's pet + //if (caster->ToPlayer()->GetPet() != target) + // return; + + Unit* target = aurApp->GetTarget(); + if (target->GetTypeId() != TYPEID_UNIT || !target->ToCreature()->isPet()) + return; + + Pet* pet = target->ToPet(); + + if (apply) { - // Dash - if (AuraEffect * aurEff =target->GetAuraEffect(SPELL_AURA_MOD_INCREASE_SPEED, SPELLFAMILY_DRUID, 0, 0, 0x8)) - aurEff->RecalculateAmount(); + if (caster->ToPlayer()->GetPet() != pet) + return; - // Disarm handling - // If druid shifts while being disarmed we need to deal with that since forms aren't affected by disarm - // and also HandleAuraModDisarm is not triggered - if (!target->CanUseAttackType(BASE_ATTACK)) + pet->SetCharmedBy(caster, CHARM_TYPE_POSSESS, aurApp); + } + else + { + pet->RemoveCharmedBy(caster); + + if (!pet->IsWithinDistInMap(caster, pet->GetMap()->GetVisibilityRange())) + pet->Remove(PET_SAVE_NOT_IN_SLOT, true); + else { - if (Item *pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND)) + // Reinitialize the pet bar and make the pet come back to the owner + caster->ToPlayer()->PetSpellInitialize(); + if (!pet->getVictim()) { - target->ToPlayer()->_ApplyWeaponDamage(EQUIPMENT_SLOT_MAINHAND, pItem->GetTemplate(), NULL, apply); + pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, pet->GetFollowAngle()); + //if (target->GetCharmInfo()) + // target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW); } } } +} - // stop handling the effect if it was removed by linked event - if (apply && aurApp->GetRemoveMode()) +void AuraEffect::HandleModCharm(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; - if (target->GetTypeId() == TYPEID_PLAYER) + Unit* target = aurApp->GetTarget(); + + Unit* caster = GetCaster(); + + if (apply) + target->SetCharmedBy(caster, CHARM_TYPE_CHARM, aurApp); + else + target->RemoveCharmedBy(caster); +} + +void AuraEffect::HandleCharmConvert(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); + + Unit* caster = GetCaster(); + + if (apply) + target->SetCharmedBy(caster, CHARM_TYPE_CONVERT, aurApp); + else + target->RemoveCharmedBy(caster); +} + +/** + * Such auras are applied from a caster(=player) to a vehicle. + * This has been verified using spell #49256 + */ +void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Unit* target = aurApp->GetTarget(); + + if (!target->IsVehicle()) + return; + + Unit* caster = GetCaster(); + + if (!caster || caster == target) + return; + + if (apply) { - SpellShapeshiftEntry const *shapeInfo = sSpellShapeshiftStore.LookupEntry(form); - // Learn spells for shapeshift form - no need to send action bars or add spells to spellbook - for (uint8 i = 0; i_EnterVehicle(target->GetVehicleKit(), m_amount - 1, aurApp); + } + else + { + if (GetId() == 53111) // Devour Humanoid { - if (!shapeInfo->stanceSpell[i]) - continue; - if (apply) - target->ToPlayer()->AddTemporarySpell(shapeInfo->stanceSpell[i]); - else - target->ToPlayer()->RemoveTemporarySpell(shapeInfo->stanceSpell[i]); + target->Kill(caster); + if (caster->GetTypeId() == TYPEID_UNIT) + caster->ToCreature()->RemoveCorpse(); } + caster->_ExitVehicle(); + // some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them + caster->RemoveAurasDueToSpell(GetId()); } } -void AuraEffect::HandleAuraTransform(AuraApplication const* aurApp, uint8 mode, bool apply) const +/*********************************************************/ +/*** MODIFY SPEED ***/ +/*********************************************************/ +void AuraEffect::HandleAuraModIncreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); - if (apply) + target->UpdateSpeed(MOVE_RUN, true); +} + +void AuraEffect::HandleAuraModIncreaseMountedSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + HandleAuraModIncreaseSpeed(aurApp, mode, apply); +} + +void AuraEffect::HandleAuraModIncreaseFlightSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) + return; + + Unit* target = aurApp->GetTarget(); + + // Enable Fly mode for flying mounts + if (GetAuraType() == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) { - // update active transform spell only when transform or shapeshift not set or not overwriting negative by positive case - if (!target->GetModelForForm(target->GetShapeshiftForm()) || !IsPositiveSpell(GetId())) + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK && (apply || (!target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !target->HasAuraType(SPELL_AURA_FLY)))) { - // special case (spell specific functionality) - if (GetMiscValue() == 0) - { - switch (GetId()) - { - // Orb of Deception - case 16739: - { - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - switch (target->getRace()) - { - // Blood Elf - case RACE_BLOODELF: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 17829 : 17830); - break; - // Orc - case RACE_ORC: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 10139 : 10140); - break; - // Troll - case RACE_TROLL: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 10135 : 10134); - break; - // Tauren - case RACE_TAUREN: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 10136 : 10147); - break; - // Undead - case RACE_UNDEAD_PLAYER: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 10146 : 10145); - break; - // Draenei - case RACE_DRAENEI: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 17827 : 17828); - break; - // Dwarf - case RACE_DWARF: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 10141 : 10142); - break; - // Gnome - case RACE_GNOME: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 10148 : 10149); - break; - // Human - case RACE_HUMAN: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 10137 : 10138); - break; - // Night Elf - case RACE_NIGHTELF: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 10143 : 10144); - break; - default: - break; - } - break; - } - // Murloc costume - case 42365: - target->SetDisplayId(21723); - break; - // Dread Corsair - case 50517: - // Corsair Costume - case 51926: - { - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - switch (target->getRace()) - { - // Blood Elf - case RACE_BLOODELF: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25032 : 25043); - break; - // Orc - case RACE_ORC: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25039 : 25050); - break; - // Troll - case RACE_TROLL: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25041 : 25052); - break; - // Tauren - case RACE_TAUREN: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25040 : 25051); - break; - // Undead - case RACE_UNDEAD_PLAYER: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25042 : 25053); - break; - // Draenei - case RACE_DRAENEI: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25033 : 25044); - break; - // Dwarf - case RACE_DWARF: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25034 : 25045); - break; - // Gnome - case RACE_GNOME: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25035 : 25046); - break; - // Human - case RACE_HUMAN: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25037 : 25048); - break; - // Night Elf - case RACE_NIGHTELF: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 25038 : 25049); - break; - default: - break; - } - break; - } - // Pygmy Oil - case 53806: - target->SetDisplayId(22512); - break; - // Honor the Dead - case 65386: - case 65495: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 29203 : 29204); - break; - // Darkspear Pride - case 75532: - target->SetDisplayId(target->getGender() == GENDER_MALE ? 31737 : 31738); - break; - default: - break; - } - } - else + if (Player *plr = target->m_movedPlayer) { - CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(GetMiscValue()); - if (!ci) - { - target->SetDisplayId(16358); // pig pink ^_^ - sLog->outError("Auras: unknown creature id = %d (only need its modelid) From Spell Aura Transform in Spell ID = %d", GetMiscValue(), GetId()); - } + WorldPacket data; + if (apply) + data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12); else - { - uint32 model_id = 0; - - if (uint32 modelid = ci->GetRandomValidModelId()) - model_id = modelid; // Will use the default model here - - // Polymorph (sheep) - if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_MAGE && GetSpellProto()->SpellIconID == 82 && GetSpellProto()->SpellVisual[0] == 12978) - if (Unit* caster = GetCaster()) - if (caster->HasAura(52648)) // Glyph of the Penguin - model_id = 26452; - - target->SetDisplayId(model_id); - - // Dragonmaw Illusion (set mount model also) - if (GetId() == 42016 && target->GetMountID() && !target->GetAuraEffectsByType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED).empty()) - target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 16314); - } + data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12); + data.append(plr->GetPackGUID()); + data << uint32(0); // unknown + plr->SendDirectMessage(&data); } } - // update active transform spell only when transform or shapeshift not set or not overwriting negative by positive case - if (!target->getTransForm() || !IsPositiveSpell(GetId()) || IsPositiveSpell(target->getTransForm())) - target->setTransForm(GetId()); - - // polymorph case - if ((mode & AURA_EFFECT_HANDLE_REAL) && target->GetTypeId() == TYPEID_PLAYER && target->IsPolymorphed()) + if (mode & AURA_EFFECT_HANDLE_REAL) { - // for players, start regeneration after 1s (in polymorph fast regeneration case) - // only if caster is Player (after patch 2.4.2) - if (IS_PLAYER_GUID(GetCasterGUID())) - target->ToPlayer()->setRegenTimerCount(1*IN_MILLISECONDS); + //Players on flying mounts must be immune to polymorph + if (target->GetTypeId() == TYPEID_PLAYER) + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - //dismount polymorphed target (after patch 2.4.2) - if (target->IsMounted()) - target->RemoveAurasByType(SPELL_AURA_MOUNTED); + // Dragonmaw Illusion (overwrite mount model, mounted aura already applied) + if (apply && target->HasAuraEffect(42016, 0) && target->GetMountID()) + target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 16314); } } - else - { - // HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true) will reapply it if need - if (target->getTransForm() == GetId()) - target->setTransForm(0); - - target->RestoreDisplayId(); - - // Dragonmaw Illusion (restore mount model) - if (GetId() == 42016 && target->GetMountID() == 16314) - { - if (!target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).empty()) - { - uint32 cr_id = target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetMiscValue(); - if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(cr_id)) - { - uint32 team = 0; - if (target->GetTypeId() == TYPEID_PLAYER) - team = target->ToPlayer()->GetTeam(); - - uint32 displayID = sObjectMgr->ChooseDisplayId(team, ci); - sObjectMgr->GetCreatureModelRandomGender(&displayID); - target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, displayID); - } - } - } - } + if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) + target->UpdateSpeed(MOVE_FLIGHT, true); } -void AuraEffect::HandleAuraModScale(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModIncreaseSwimSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); - target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X, (float)GetAmount(), apply); + target->UpdateSpeed(MOVE_SWIM, true); } -void AuraEffect::HandleAuraCloneCaster(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModDecreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); - if (apply) - { - Unit* caster = GetCaster(); - if (!caster || caster == target) - return; - // What must be cloned? at least display and scale - target->SetDisplayId(caster->GetDisplayId()); - target->SetCreatorGUID(caster->GetGUID()); - //target->SetFloatValue(OBJECT_FIELD_SCALE_X, caster->GetFloatValue(OBJECT_FIELD_SCALE_X)); // we need retail info about how scaling is handled (aura maybe?) - target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE); - } - else - { - target->SetCreatorGUID(0); - target->SetDisplayId(target->GetNativeDisplayId()); - target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_MIRROR_IMAGE); - } + target->UpdateSpeed(MOVE_RUN, true); + target->UpdateSpeed(MOVE_SWIM, true); + target->UpdateSpeed(MOVE_FLIGHT, true); + target->UpdateSpeed(MOVE_RUN_BACK, true); + target->UpdateSpeed(MOVE_SWIM_BACK, true); + target->UpdateSpeed(MOVE_FLIGHT_BACK, true); } -/************************/ -/*** FIGHT ***/ -/************************/ - -void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) - return; + target->UpdateSpeed(MOVE_RUN, true); + target->UpdateSpeed(MOVE_SWIM, true); + target->UpdateSpeed(MOVE_FLIGHT, true); +} - if (apply) - { - /* - WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); - data<GetGUID(); - data<SendMessageToSet(&data, true); - */ +/*********************************************************/ +/*** IMMUNITY ***/ +/*********************************************************/ - UnitList targets; - Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(target, target, target->GetMap()->GetVisibilityRange()); - Trinity::UnitListSearcher searcher(target, targets, u_check); - target->VisitNearbyObject(target->GetMap()->GetVisibilityRange(), searcher); - for (UnitList::iterator iter = targets.begin(); iter != targets.end(); ++iter) - { - if (!(*iter)->HasUnitState(UNIT_STAT_CASTING)) - continue; +void AuraEffect::HandleModStateImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++) - { - if ((*iter)->GetCurrentSpell(i) - && (*iter)->GetCurrentSpell(i)->m_targets.getUnitTargetGUID() == target->GetGUID()) - { - (*iter)->InterruptSpell(CurrentSpellTypes(i), false); - } - } - } - target->CombatStop(); - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + Unit* target = aurApp->GetTarget(); - // prevent interrupt message - if (GetCasterGUID() == target->GetGUID() && target->GetCurrentSpell(CURRENT_GENERIC_SPELL)) - target->FinishSpell(CURRENT_GENERIC_SPELL, false); - target->InterruptNonMeleeSpells(true); - target->getHostileRefManager().deleteReferences(); + std::list immunity_list; + if (GetMiscValue() & (1<<10)) + immunity_list.push_back(SPELL_AURA_MOD_STUN); + if (GetMiscValue() & (1<<1)) + immunity_list.push_back(SPELL_AURA_TRANSFORM); - // stop handling the effect if it was removed by linked event - if (aurApp->GetRemoveMode()) - return; - // blizz like 2.0.x - target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); - // blizz like 2.0.x - target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH); - // blizz like 2.0.x - target->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); + // These flag can be recognized wrong: + if (GetMiscValue() & (1<<6)) + immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); + if (GetMiscValue() & (1<<0)) + immunity_list.push_back(SPELL_AURA_MOD_ROOT); + if (GetMiscValue() & (1<<2)) + immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); + if (GetMiscValue() & (1<<9)) + immunity_list.push_back(SPELL_AURA_MOD_FEAR); - target->AddUnitState(UNIT_STAT_DIED); - } - else - { - /* - WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9); - data<GetGUID(); - data<SendMessageToSet(&data, true); - */ - // blizz like 2.0.x - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_29); - // blizz like 2.0.x - target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH); - // blizz like 2.0.x - target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD); + // an exception for Bladestorm + if ((GetMiscValue() & (1<<7)) && (GetId() != 46924)) + immunity_list.push_back(SPELL_AURA_MOD_DISARM); - target->ClearUnitState(UNIT_STAT_DIED); + // apply immunities + for (std::list ::iterator iter = immunity_list.begin(); iter != immunity_list.end(); ++iter) + target->ApplySpellImmune(GetId(), IMMUNITY_STATE, *iter, apply); + + // Patch 3.0.3 Bladestorm now breaks all snares and roots on the warrior when activated. + if (apply && GetId() == 46924) + { + target->RemoveAurasByType(SPELL_AURA_MOD_ROOT); + target->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); } + + if (apply && GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) + for (std::list ::iterator iter = immunity_list.begin(); iter != immunity_list.end(); ++iter) + target->RemoveAurasByType(*iter); } -void AuraEffect::HandleModUnattackable(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); + uint32 mechanic; - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (!apply && target->HasAuraType(SPELL_AURA_MOD_UNATTACKABLE)) - return; - - target->ApplyModFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE, apply); - - // call functions which may have additional effects after chainging state of unit - if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) + switch (GetId()) { - target->CombatStop(); - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + case 42292: // PvP trinket + case 59752: // Every Man for Himself + mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; + // Actually we should apply immunities here, too, but the aura has only 100 ms duration, so there is practically no point + break; + case 54508: // Demonic Empowerment + mechanic = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); + break; + case 34471: // The Beast Within + case 19574: // Bestial Wrath + mechanic = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN) | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM) | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR) | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED) | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply); + break; + default: + if (GetMiscValue() < 1) + return; + mechanic = 1 << GetMiscValue(); + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply); + break; } + + if (apply && GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) + target->RemoveAurasWithMechanic(mechanic, AURA_REMOVE_BY_DEFAULT, GetId()); } -void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - AuraType type = GetAuraType(); - - //Prevent handling aura twice - if ((apply) ? target->GetAuraEffectsByType(type).size() > 1 : target->HasAuraType(type)) - return; - - uint32 field, flag, slot; - WeaponAttackType attType; - switch (type) - { - case SPELL_AURA_MOD_DISARM: - field=UNIT_FIELD_FLAGS; - flag=UNIT_FLAG_DISARMED; - slot=EQUIPMENT_SLOT_MAINHAND; - attType=BASE_ATTACK; - break; - case SPELL_AURA_MOD_DISARM_OFFHAND: - field=UNIT_FIELD_FLAGS_2; - flag=UNIT_FLAG2_DISARM_OFFHAND; - slot=EQUIPMENT_SLOT_OFFHAND; - attType=OFF_ATTACK; - break; - case SPELL_AURA_MOD_DISARM_RANGED: - field=UNIT_FIELD_FLAGS_2; - flag=UNIT_FLAG2_DISARM_RANGED; - slot=EQUIPMENT_SLOT_RANGED; - attType=RANGED_ATTACK; - break; - default: - return; - } - - if (!apply) - target->RemoveFlag(field, flag); - - if (apply) - target->SetFlag(field, flag); + target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply); - // Handle damage modifcation, shapeshifted druids are not affected - if (target->GetTypeId() == TYPEID_PLAYER && !target->IsInFeralForm()) + // when removing flag aura, handle flag drop + if (!apply && target->GetTypeId() == TYPEID_PLAYER + && (GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION)) { - if (Item *pItem = target->ToPlayer()->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + if (target->GetTypeId() == TYPEID_PLAYER) { - uint8 attacktype = Player::GetAttackBySlot(slot); - - if (attacktype < MAX_ATTACK) - target->ToPlayer()->_ApplyWeaponDamage(slot, pItem->GetTemplate(), NULL, !apply); + if (target->ToPlayer()->InBattleground()) + { + if (Battleground *bg = target->ToPlayer()->GetBattleground()) + bg->EventPlayerDroppedFlag(target->ToPlayer()); + } + else + sOutdoorPvPMgr->HandleDropFlag((Player*)target, GetSpellProto()->Id); } } - - if (target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->GetCurrentEquipmentId()) - target->UpdateDamagePhysical(attType); } -void AuraEffect::HandleAuraModSilence(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - if (apply) - { - target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED); - - // call functions which may have additional effects after chainging state of unit - // Stop cast only spells vs PreventionType == SPELL_PREVENTION_TYPE_SILENCE - for (uint32 i = CURRENT_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) - if (Spell* spell = target->GetCurrentSpell(CurrentSpellTypes(i))) - if (spell->m_spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE) - // Stop spells on prepare or casting state - target->InterruptSpell(CurrentSpellTypes(i), false); - } - else - { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(SPELL_AURA_MOD_SILENCE) || target->HasAuraType(SPELL_AURA_MOD_PACIFY_SILENCE)) - return; + target->ApplySpellImmune(GetId(), IMMUNITY_STATE, GetMiscValue(), apply); - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED); - } + if (apply && GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) + target->RemoveAurasByType(AuraType(GetMiscValue()), 0 , GetBase()); } -void AuraEffect::HandleAuraModPacify(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - if (apply) - target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); - else - { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(SPELL_AURA_MOD_PACIFY) || target->HasAuraType(SPELL_AURA_MOD_PACIFY_SILENCE)) - return; - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED); - } -} + target->ApplySpellImmune(GetId(), IMMUNITY_SCHOOL, GetMiscValue(), (apply)); -void AuraEffect::HandleAuraModPacifyAndSilence(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) - return; - - Unit* target = aurApp->GetTarget(); - - // Vengeance of the Blue Flight (TODO: REMOVE THIS!) - if (m_spellProto->Id == 45839) + if (GetSpellProto()->Mechanic == MECHANIC_BANISH) { if (apply) - target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + target->AddUnitState(UNIT_STAT_ISOLATED); else - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - } - if (!(apply)) - { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(SPELL_AURA_MOD_PACIFY_SILENCE)) - return; + { + bool banishFound = false; + Unit::AuraEffectList const& banishAuras = target->GetAuraEffectsByType(GetAuraType()); + for (Unit::AuraEffectList::const_iterator i = banishAuras.begin(); i != banishAuras.end(); ++i) + if ((*i)->GetSpellProto()->Mechanic == MECHANIC_BANISH) + { + banishFound = true; + break; + } + if (!banishFound) + target->ClearUnitState(UNIT_STAT_ISOLATED); + } } - HandleAuraModPacify(aurApp, mode, apply); - HandleAuraModSilence(aurApp, mode, apply); -} -void AuraEffect::HandleAuraAllowOnlyAbility(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) - return; + if (apply && GetMiscValue() == SPELL_SCHOOL_MASK_NORMAL) + target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); - Unit* target = aurApp->GetTarget(); + // remove all flag auras (they are positive, but they must be removed when you are immune) + if (GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY + && GetSpellProto()->AttributesEx2 & SPELL_ATTR2_DAMAGE_REDUCED_SHIELD) + target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); - if (target->GetTypeId() == TYPEID_PLAYER) + // TODO: optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else + if ((apply) + && GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY + && IsPositiveSpell(GetId())) //Only positive immunity removes auras { - if (apply) - target->SetFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY); - else + uint32 school_mask = GetMiscValue(); + Unit::AuraApplicationMap& Auras = target->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator iter = Auras.begin(); iter != Auras.end();) { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(SPELL_AURA_ALLOW_ONLY_ABILITY)) - return; - target->RemoveFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY); + SpellEntry const *spell = iter->second->GetBase()->GetSpellProto(); + if ((GetSpellSchoolMask(spell) & school_mask)//Check for school mask + && CanSpellDispelAura(GetSpellProto(), spell) + && !iter->second->IsPositive() //Don't remove positive spells + && spell->Id != GetId()) //Don't remove self + { + target->RemoveAura(iter); + } + else + ++iter; } } } -/****************************/ -/*** TRACKING ***/ -/****************************/ - -void AuraEffect::HandleAuraTrackCreatures(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->SetUInt32Value(PLAYER_TRACK_CREATURES, (apply) ? ((uint32)1)<<(GetMiscValue()-1) : 0); + target->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, GetMiscValue(), apply); } -void AuraEffect::HandleAuraTrackResources(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->SetUInt32Value(PLAYER_TRACK_RESOURCES, (apply) ? ((uint32)1)<<(GetMiscValue()-1): 0); + target->ApplySpellDispelImmunity(m_spellProto, DispelType(GetMiscValue()), (apply)); } -void AuraEffect::HandleAuraTrackStealthed(AuraApplication const* aurApp, uint8 mode, bool apply) const +/*********************************************************/ +/*** MODIFY STATS ***/ +/*********************************************************/ + +/********************************/ +/*** RESISTANCE ***/ +/********************************/ + +void AuraEffect::HandleAuraModResistanceExclusive(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) + for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) + { + if (GetMiscValue() & int32(1<GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE, 1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, float(GetAmount() - amount), apply); + if (target->GetTypeId() == TYPEID_PLAYER) + target->ApplyResistanceBuffModsMod(SpellSchools(x), aurApp->IsPositive(), float(GetAmount() - amount), apply); + } + } + } +} + +void AuraEffect::HandleAuraModResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - if (!(apply)) + Unit* target = aurApp->GetTarget(); + + for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType())) - return; + if (GetMiscValue() & int32(1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->isPet()) + target->ApplyResistanceBuffModsMod(SpellSchools(x), GetAmount() > 0, (float)GetAmount(), apply); + } } - target->ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_TRACK_STEALTHED, apply); } -void AuraEffect::HandleAuraModStalked(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - // used by spells: Hunter's Mark, Mind Vision, Syndicate Tracker (MURP) DND - if (apply) - target->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT); + // only players have base stats + if (target->GetTypeId() != TYPEID_PLAYER) + { + //pets only have base armor + if (target->ToCreature()->isPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) + target->HandleStatModifier(UNIT_MOD_ARMOR, BASE_PCT, float(GetAmount()), apply); + } else { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (!target->HasAuraType(GetAuraType())) - target->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TRACK_UNIT); + for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) + { + if (GetMiscValue() & int32(1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount()), apply); + } } - - // call functions which may have additional effects after chainging state of unit - target->UpdateObjectVisibility(); } -void AuraEffect::HandleAuraUntrackable(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (apply) - target->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE); - else + for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType())) - return; - target->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_UNTRACKABLE); + if (GetMiscValue() & int32(1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->isPet()) + { + target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)GetAmount(), apply); + target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)GetAmount(), apply); + } + } } } -/****************************/ -/*** SKILLS & TALENTS ***/ -/****************************/ - -void AuraEffect::HandleAuraModPetTalentsPoints(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleModBaseResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); + // only players have base stats if (target->GetTypeId() != TYPEID_PLAYER) - return; - - // Recalculate pet talent points - if (Pet *pet = target->ToPlayer()->GetPet()) - pet->InitTalentForLevel(); + { + //only pets have base stats + if (target->ToCreature()->isPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) + target->HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(GetAmount()), apply); + } + else + { + for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + if (GetMiscValue() & (1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply); + } } -void AuraEffect::HandleAuraModSkill(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModTargetResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_SKILL))) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; + Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) - return; + // applied to damage as HandleNoImmediateEffect in Unit::CalcAbsorbResist and Unit::CalcArmorReducedDamage - uint32 prot = GetMiscValue(); - int32 points = GetAmount(); + // show armor penetration + if (target->GetTypeId() == TYPEID_PLAYER && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) + target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE, GetAmount(), apply); - target->ToPlayer()->ModifySkillBonus(prot, ((apply) ? points: -points), GetAuraType() == SPELL_AURA_MOD_SKILL_TALENT); - if (prot == SKILL_DEFENSE) - target->ToPlayer()->UpdateDefenseBonusesMod(); + // show as spell penetration only full spell penetration bonuses (all resistances except armor and holy + if (target->GetTypeId() == TYPEID_PLAYER && (GetMiscValue() & SPELL_SCHOOL_MASK_SPELL) == SPELL_SCHOOL_MASK_SPELL) + target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, GetAmount(), apply); } -/****************************/ -/*** MOVEMENT ***/ -/****************************/ +/********************************/ +/*** STAT ***/ +/********************************/ -void AuraEffect::HandleAuraMounted(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (apply) + if (GetMiscValue() < -2 || GetMiscValue() > 4) { - uint32 creatureEntry = GetMiscValue(); + sLog->outError("WARNING: Spell %u effect %u has an unsupported misc value (%i) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue()); + return; + } - // Festive Holiday Mount - if (target->HasAura(62061)) + for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + { + // -1 or -2 is all stats (misc < -2 checked in function beginning) + if (GetMiscValue() < 0 || GetMiscValue() == i) { - if (GetBase()->HasEffectType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) - creatureEntry = 24906; - else - creatureEntry = 15665; + //target->ApplyStatMod(Stats(i), m_amount, apply); + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->isPet()) + target->ApplyStatBuffMod(Stats(i), (float)GetAmount(), apply); } + } +} - CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(creatureEntry); - if (!ci) - { - sLog->outErrorDb("AuraMounted: `creature_template`='%u' not found in database (only need its modelid)", GetMiscValue()); - return; - } +void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; - uint32 team = 0; - if (target->GetTypeId() == TYPEID_PLAYER) - team = target->ToPlayer()->GetTeam(); + Unit* target = aurApp->GetTarget(); - uint32 displayID = sObjectMgr->ChooseDisplayId(team, ci); - sObjectMgr->GetCreatureModelRandomGender(&displayID); + if (GetMiscValue() < -1 || GetMiscValue() > 4) + { + sLog->outError("WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); + return; + } - //some spell has one aura of mount and one of vehicle - for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) - if (GetSpellProto()->Effect[i] == SPELL_EFFECT_SUMMON - && GetSpellProto()->EffectMiscValue[i] == GetMiscValue()) - displayID = 0; + // only players have base stats + if (target->GetTypeId() != TYPEID_PLAYER) + return; - target->Mount(displayID, ci->VehicleId, GetMiscValue()); - } - else + for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) { - target->Unmount(); - //some mounts like Headless Horseman's Mount or broom stick are skill based spell - // need to remove ALL arura related to mounts, this will stop client crash with broom stick - // and never endless flying after using Headless Horseman's Mount - if (mode & AURA_EFFECT_HANDLE_REAL) - target->RemoveAurasByType(SPELL_AURA_MOUNTED); + if (GetMiscValue() == i || GetMiscValue() == -1) + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount), apply); } } -void AuraEffect::HandleAuraAllowFlight(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModSpellDamagePercentFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (!apply) - { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType()) || target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) - return; - } - - if (target->GetTypeId() == TYPEID_UNIT) - target->SetFlying(apply); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - if (Player *plr = target->m_movedPlayer) - { - // allow flying - WorldPacket data; - if (apply) - data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12); - else - data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12); - data.append(target->GetPackGUID()); - data << uint32(0); // unk - plr->SendDirectMessage(&data); - } + // Magic damage modifiers implemented in Unit::SpellDamageBonus + // This information for client side use only + // Recalculate bonus + target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } -void AuraEffect::HandleAuraWaterWalk(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModSpellHealingPercentFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (!apply) - { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType())) - return; - } + if (target->GetTypeId() != TYPEID_PLAYER) + return; - WorldPacket data; - if (apply) - data.Initialize(SMSG_MOVE_WATER_WALK, 8+4); - else - data.Initialize(SMSG_MOVE_LAND_WALK, 8+4); - data.append(target->GetPackGUID()); - data << uint32(0); - target->SendMessageToSet(&data, true); + // Recalculate bonus + target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } -void AuraEffect::HandleAuraFeatherFall(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModSpellDamagePercentFromAttackPower(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (!apply) - { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType())) - return; - } - - WorldPacket data; - if (apply) - data.Initialize(SMSG_MOVE_FEATHER_FALL, 8+4); - else - data.Initialize(SMSG_MOVE_NORMAL_FALL, 8+4); - data.append(target->GetPackGUID()); - data << uint32(0); - target->SendMessageToSet(&data, true); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - // start fall from current height - if (!apply && target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->SetFallInformation(0, target->GetPositionZ()); + // Magic damage modifiers implemented in Unit::SpellDamageBonus + // This information for client side use only + // Recalculate bonus + target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } -void AuraEffect::HandleAuraHover(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModSpellHealingPercentFromAttackPower(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (!apply) - { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType())) - return; - } + if (target->GetTypeId() != TYPEID_PLAYER) + return; - WorldPacket data; - if (apply) - data.Initialize(SMSG_MOVE_SET_HOVER, 8+4); - else - data.Initialize(SMSG_MOVE_UNSET_HOVER, 8+4); - data.append(target->GetPackGUID()); - data << uint32(0); - target->SendMessageToSet(&data, true); + // Recalculate bonus + target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } -void AuraEffect::HandleWaterBreathing(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleModHealingDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - // update timers in client - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->UpdateMirrorTimers(); + if (target->GetTypeId() != TYPEID_PLAYER) + return; + // implemented in Unit::SpellHealingBonus + // this information is for client side only + target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); } -void AuraEffect::HandleForceMoveForward(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (apply) - target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE); - else + if (GetMiscValue() < -1 || GetMiscValue() > 4) { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType())) - return; - target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FORCE_MOVE); + sLog->outError("WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); + return; } -} -/****************************/ -/*** THREAT ***/ -/****************************/ + // save current health state + float healthPct = target->GetHealthPct(); + bool alive = target->isAlive(); -void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) - return; + for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + { + if (GetMiscValue() == i || GetMiscValue() == -1) + { + target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetAmount()), apply); + if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->isPet()) + target->ApplyStatPercentBuffMod(Stats(i), float(GetAmount()), apply); + } + } - Unit* target = aurApp->GetTarget(); - for (int32 i = 0; i < MAX_SPELL_SCHOOL; ++i) - if (GetMiscValue() & (1 << i)) - ApplyPercentModFloatVar(target->m_threatModifier[i], float(GetAmount()), apply); + //recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_UNK4 0x00000010 flag) + if (GetMiscValue() == STAT_STAMINA && (m_spellProto->Attributes & SPELL_ATTR0_UNK4)) + target->SetHealth(std::max(uint32(healthPct * target->GetMaxHealth() * 0.01f), (alive ? 1 : 0))); } -void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModResistenceOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (!target->isAlive() || target->GetTypeId() != TYPEID_PLAYER) + if (target->GetTypeId() != TYPEID_PLAYER) return; - Unit* caster = GetCaster(); - if (!caster || !caster->isAlive()) + if (GetMiscValue() != SPELL_SCHOOL_MASK_NORMAL) + { + // support required adding replace UpdateArmor by loop by UpdateResistence at intellect update + // and include in UpdateResistence same code as in UpdateArmor for aura mod apply. + sLog->outError("Aura SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT(182) does not work for non-armor type resistances!"); return; + } - target->getHostileRefManager().addTempThreat((float)GetAmount(), apply); + // Recalculate Armor + target->UpdateArmor(); } -void AuraEffect::HandleModTaunt(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModExpertise(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (!target->isAlive() || !target->CanHaveThreatList()) - return; - - Unit* caster = GetCaster(); - if (!caster || !caster->isAlive()) + if (target->GetTypeId() != TYPEID_PLAYER) return; - if (apply) - target->TauntApply(caster); - else - { - // When taunt aura fades out, mob will switch to previous target if current has less than 1.1 * secondthreat - target->TauntFadeOut(caster); - } + target->ToPlayer()->UpdateExpertise(BASE_ATTACK); + target->ToPlayer()->UpdateExpertise(OFF_ATTACK); } -/*****************************/ -/*** CONTROL ***/ -/*****************************/ - -void AuraEffect::HandleModConfuse(AuraApplication const* aurApp, uint8 mode, bool apply) const +/********************************/ +/*** HEAL & ENERGIZE ***/ +/********************************/ +void AuraEffect::HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->SetControlled(apply, UNIT_STAT_CONFUSED); -} - -void AuraEffect::HandleModFear(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (target->GetTypeId() != TYPEID_PLAYER) return; - Unit* target = aurApp->GetTarget(); + // Update manaregen value + if (GetMiscValue() == POWER_MANA) + target->ToPlayer()->UpdateManaRegen(); + // other powers are not immediate effects - implemented in Player::Regenerate, Creature::Regenerate +} - target->SetControlled(apply, UNIT_STAT_FLEEING); +void AuraEffect::HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + HandleModPowerRegen(aurApp, mode, apply); } -void AuraEffect::HandleAuraModStun(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModManaRegen(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->SetControlled(apply, UNIT_STAT_STUNNED); + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + //Note: an increase in regen does NOT cause threat. + target->ToPlayer()->UpdateManaRegen(); } -void AuraEffect::HandleAuraModRoot(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->SetControlled(apply, UNIT_STAT_ROOT); + if (apply) + { + target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); + target->ModifyHealth(GetAmount()); + } + else + { + if (int32(target->GetHealth()) > GetAmount()) + target->ModifyHealth(-GetAmount()); + else + target->SetHealth(1); + target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); + } } -void AuraEffect::HandlePreventFleeing(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (target->HasAuraType(SPELL_AURA_MOD_FEAR)) - target->SetControlled(!(apply), UNIT_STAT_FLEEING); -} + uint32 oldhealth = target->GetHealth(); + double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth(); -/***************************/ -/*** CHARM ***/ -/***************************/ + target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); -void AuraEffect::HandleModPossess(AuraApplication const* aurApp, uint8 mode, bool apply) const + // refresh percentage + if (oldhealth > 0) + { + uint32 newhealth = uint32(ceil((double)target->GetMaxHealth() * healthPercentage)); + if (newhealth == 0) + newhealth = 1; + + target->SetHealth(newhealth); + } +} + +void AuraEffect::HandleAuraModIncreaseEnergy(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - Unit* caster = GetCaster(); + Powers powerType = Powers(GetMiscValue()); + // do not check power type, we can always modify the maximum + // as the client will not see any difference + // also, placing conditions that may change during the aura duration + // inside effect handlers is not a good idea + //if (int32(powerType) != GetMiscValue()) + // return; - // no support for posession AI yet - if (caster && caster->GetTypeId() == TYPEID_UNIT) + UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType); + + // Special case with temporary increase max/current power (percent) + if (GetId() == 64904) // Hymn of Hope { - HandleModCharm(aurApp, mode, apply); - return; + if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) + { + int32 change = target->GetPower(powerType) + (apply ? GetAmount() : -GetAmount()); + if (change < 0) + change = 0; + target->SetPower(powerType, change); + } } - if (apply) - target->SetCharmedBy(caster, CHARM_TYPE_POSSESS, aurApp); - else - target->RemoveCharmedBy(caster); + // generic flat case + target->HandleStatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); } -// only one spell has this aura -void AuraEffect::HandleModPossessPet(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* caster = GetCaster(); - if (!caster || caster->GetTypeId() != TYPEID_PLAYER) - return; + Unit* target = aurApp->GetTarget(); - //seems it may happen that when removing it is no longer owner's pet - //if (caster->ToPlayer()->GetPet() != target) + Powers powerType = Powers(GetMiscValue()); + // do not check power type, we can always modify the maximum + // as the client will not see any difference + // also, placing conditions that may change during the aura duration + // inside effect handlers is not a good idea + //if (int32(powerType) != GetMiscValue()) // return; - Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_UNIT || !target->ToCreature()->isPet()) + UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType); + + target->HandleStatModifier(unitMod, TOTAL_PCT, float(GetAmount()), apply); +} + +void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Pet* pet = target->ToPet(); + Unit* target = aurApp->GetTarget(); - if (apply) - { - if (caster->ToPlayer()->GetPet() != pet) - return; + // Unit will keep hp% after MaxHealth being modified if unit is alive. + float percent = target->GetHealthPct(); + target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply); + if (target->isAlive()) + target->SetHealth(target->CountPctFromMaxHealth(int32(percent))); +} - pet->SetCharmedBy(caster, CHARM_TYPE_POSSESS, aurApp); - } - else - { - pet->RemoveCharmedBy(caster); +void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; - if (!pet->IsWithinDistInMap(caster, pet->GetMap()->GetVisibilityRange())) - pet->Remove(PET_SAVE_NOT_IN_SLOT, true); - else - { - // Reinitialize the pet bar and make the pet come back to the owner - caster->ToPlayer()->PetSpellInitialize(); - if (!pet->getVictim()) - { - pet->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, pet->GetFollowAngle()); - //if (target->GetCharmInfo()) - // target->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW); - } - } - } + Unit* target = aurApp->GetTarget(); + + target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()), apply); } -void AuraEffect::HandleModCharm(AuraApplication const* aurApp, uint8 mode, bool apply) const +/********************************/ +/*** FIGHT ***/ +/********************************/ + +void AuraEffect::HandleAuraModParryPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - Unit* caster = GetCaster(); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - if (apply) - target->SetCharmedBy(caster, CHARM_TYPE_CHARM, aurApp); - else - target->RemoveCharmedBy(caster); + target->ToPlayer()->UpdateParryPercentage(); } -void AuraEffect::HandleCharmConvert(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModDodgePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - Unit* caster = GetCaster(); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - if (apply) - target->SetCharmedBy(caster, CHARM_TYPE_CONVERT, aurApp); - else - target->RemoveCharmedBy(caster); + target->ToPlayer()->UpdateDodgePercentage(); } -/** - * Such auras are applied from a caster(=player) to a vehicle. - * This has been verified using spell #49256 - */ -void AuraEffect::HandleAuraControlVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModBlockPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (!target->IsVehicle()) + if (target->GetTypeId() != TYPEID_PLAYER) return; - Unit* caster = GetCaster(); + target->ToPlayer()->UpdateBlockPercentage(); +} - if (!caster || caster == target) +void AuraEffect::HandleAuraModRegenInterrupt(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + HandleModManaRegen(aurApp, mode, apply); +} + +void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - if (apply) + Unit* target = aurApp->GetTarget(); + + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + for (int i = 0; i < MAX_ATTACK; ++i) + if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true)) + target->ToPlayer()->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply); + + // mods must be applied base at equipped weapon class and subclass comparison + // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask + // GetMiscValue() comparison with item generated damage types + + if (GetSpellProto()->EquippedItemClass == -1) { - caster->_EnterVehicle(target->GetVehicleKit(), m_amount - 1, aurApp); + target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); + target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); + target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); } else { - if (GetId() == 53111) // Devour Humanoid - { - target->Kill(caster); - if (caster->GetTypeId() == TYPEID_UNIT) - caster->ToCreature()->RemoveCorpse(); - } - caster->_ExitVehicle(); - // some SPELL_AURA_CONTROL_VEHICLE auras have a dummy effect on the player - remove them - caster->RemoveAurasDueToSpell(GetId()); + // done in Player::_ApplyWeaponDependentAuraMods } } -/*********************************************************/ -/*** MODIFY SPEED ***/ -/*********************************************************/ -void AuraEffect::HandleAuraModIncreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->UpdateSpeed(MOVE_RUN, true); + if (target->GetTypeId() == TYPEID_PLAYER) + { + target->ToPlayer()->UpdateMeleeHitChances(); + target->ToPlayer()->UpdateRangedHitChances(); + } + else + { + target->m_modMeleeHitChance += (apply) ? GetAmount() : (-GetAmount()); + target->m_modRangedHitChance += (apply) ? GetAmount() : (-GetAmount()); + } } -void AuraEffect::HandleAuraModIncreaseMountedSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModSpellHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const { - HandleAuraModIncreaseSpeed(aurApp, mode, apply); -} - -void AuraEffect::HandleAuraModIncreaseFlightSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_SEND_FOR_CLIENT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - // Enable Fly mode for flying mounts - if (GetAuraType() == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) - { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK && (apply || (!target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !target->HasAuraType(SPELL_AURA_FLY)))) - { - if (Player *plr = target->m_movedPlayer) - { - WorldPacket data; - if (apply) - data.Initialize(SMSG_MOVE_SET_CAN_FLY, 12); - else - data.Initialize(SMSG_MOVE_UNSET_CAN_FLY, 12); - data.append(plr->GetPackGUID()); - data << uint32(0); // unknown - plr->SendDirectMessage(&data); - } - } + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->UpdateSpellHitChances(); + else + target->m_modSpellHitChance += (apply) ? GetAmount(): (-GetAmount()); +} - if (mode & AURA_EFFECT_HANDLE_REAL) - { - //Players on flying mounts must be immune to polymorph - if (target->GetTypeId() == TYPEID_PLAYER) - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); +void AuraEffect::HandleModSpellCritChance(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; - // Dragonmaw Illusion (overwrite mount model, mounted aura already applied) - if (apply && target->HasAuraEffect(42016, 0) && target->GetMountID()) - target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, 16314); - } - } + Unit* target = aurApp->GetTarget(); - if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) - target->UpdateSpeed(MOVE_FLIGHT, true); + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->UpdateAllSpellCritChances(); + else + target->m_baseSpellCritChance += (apply) ? GetAmount():-GetAmount(); } -void AuraEffect::HandleAuraModIncreaseSwimSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleModSpellCritChanceShool(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->UpdateSpeed(MOVE_SWIM, true); + if (target->GetTypeId() != TYPEID_PLAYER) + return; + + for (int school = SPELL_SCHOOL_NORMAL; school < MAX_SPELL_SCHOOL; ++school) + if (GetMiscValue() & (1<ToPlayer()->UpdateSpellCritChance(school); } -void AuraEffect::HandleAuraModDecreaseSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->UpdateSpeed(MOVE_RUN, true); - target->UpdateSpeed(MOVE_SWIM, true); - target->UpdateSpeed(MOVE_FLIGHT, true); - target->UpdateSpeed(MOVE_RUN_BACK, true); - target->UpdateSpeed(MOVE_SWIM_BACK, true); - target->UpdateSpeed(MOVE_FLIGHT_BACK, true); + if (target->GetTypeId() != TYPEID_PLAYER) + { + target->m_baseSpellCritChance += (apply) ? GetAmount():-GetAmount(); + return; + } + + target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); + target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); + target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); + + // included in Player::UpdateSpellCritChance calculation + target->ToPlayer()->UpdateAllSpellCritChances(); } -void AuraEffect::HandleAuraModUseNormalSpeed(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +/********************************/ +/*** ATTACK SPEED ***/ +/********************************/ + +void AuraEffect::HandleModCastingSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->UpdateSpeed(MOVE_RUN, true); - target->UpdateSpeed(MOVE_SWIM, true); - target->UpdateSpeed(MOVE_FLIGHT, true); + target->ApplyCastTimePercentMod((float)GetAmount(), apply); } -/*********************************************************/ -/*** IMMUNITY ***/ -/*********************************************************/ - -void AuraEffect::HandleModStateImmunityMask(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModMeleeRangedSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - std::list immunity_list; - if (GetMiscValue() & (1<<10)) - immunity_list.push_back(SPELL_AURA_MOD_STUN); - if (GetMiscValue() & (1<<1)) - immunity_list.push_back(SPELL_AURA_TRANSFORM); + target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply); + target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), apply); + target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); +} - // These flag can be recognized wrong: - if (GetMiscValue() & (1<<6)) - immunity_list.push_back(SPELL_AURA_MOD_DECREASE_SPEED); - if (GetMiscValue() & (1<<0)) - immunity_list.push_back(SPELL_AURA_MOD_ROOT); - if (GetMiscValue() & (1<<2)) - immunity_list.push_back(SPELL_AURA_MOD_CONFUSE); - if (GetMiscValue() & (1<<9)) - immunity_list.push_back(SPELL_AURA_MOD_FEAR); +void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; - // an exception for Bladestorm - if ((GetMiscValue() & (1<<7)) && (GetId() != 46924)) - immunity_list.push_back(SPELL_AURA_MOD_DISARM); + Unit* target = aurApp->GetTarget(); - // apply immunities - for (std::list ::iterator iter = immunity_list.begin(); iter != immunity_list.end(); ++iter) - target->ApplySpellImmune(GetId(), IMMUNITY_STATE, *iter, apply); + target->ApplyCastTimePercentMod(float(m_amount), apply); + target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); + target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); + target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(GetAmount()), apply); +} - // Patch 3.0.3 Bladestorm now breaks all snares and roots on the warrior when activated. - if (apply && GetId() == 46924) - { - target->RemoveAurasByType(SPELL_AURA_MOD_ROOT); - target->RemoveAurasByType(SPELL_AURA_MOD_DECREASE_SPEED); - } +void AuraEffect::HandleModAttackSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; - if (apply && GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) - for (std::list ::iterator iter = immunity_list.begin(); iter != immunity_list.end(); ++iter) - target->RemoveAurasByType(*iter); + Unit* target = aurApp->GetTarget(); + + target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply); + target->UpdateDamagePhysical(BASE_ATTACK); } -void AuraEffect::HandleModMechanicImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - uint32 mechanic; - switch (GetId()) - { - case 42292: // PvP trinket - case 59752: // Every Man for Himself - mechanic = IMMUNE_TO_MOVEMENT_IMPAIRMENT_AND_LOSS_CONTROL_MASK; - // Actually we should apply immunities here, too, but the aura has only 100 ms duration, so there is practically no point - break; - case 54508: // Demonic Empowerment - mechanic = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - break; - case 34471: // The Beast Within - case 19574: // Bestial Wrath - mechanic = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT) | (1 << MECHANIC_FEAR) | (1 << MECHANIC_STUN) | (1 << MECHANIC_SLEEP) | (1 << MECHANIC_CHARM) | (1 << MECHANIC_SAPPED) | (1 << MECHANIC_HORROR) | (1 << MECHANIC_POLYMORPH) | (1 << MECHANIC_DISORIENTED) | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_TURN); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SNARE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_ROOT, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FEAR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_STUN, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_CHARM, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_HORROR, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, MECHANIC_TURN, apply); - break; - default: - if (GetMiscValue() < 1) - return; - mechanic = 1 << GetMiscValue(); - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply); - break; - } + target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply); + target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), apply); +} - if (apply && GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) - target->RemoveAurasWithMechanic(mechanic, AURA_REMOVE_BY_DEFAULT, GetId()); +void AuraEffect::HandleAuraModRangedHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; + + Unit* target = aurApp->GetTarget(); + + target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); } -void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleRangedAmmoHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->ApplySpellImmune(GetId(), IMMUNITY_EFFECT, GetMiscValue(), apply); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - // when removing flag aura, handle flag drop - if (!apply && target->GetTypeId() == TYPEID_PLAYER - && (GetSpellProto()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION)) - { - if (target->GetTypeId() == TYPEID_PLAYER) - { - if (target->ToPlayer()->InBattleground()) - { - if (Battleground *bg = target->ToPlayer()->GetBattleground()) - bg->EventPlayerDroppedFlag(target->ToPlayer()); - } - else - sOutdoorPvPMgr->HandleDropFlag((Player*)target, GetSpellProto()->Id); - } - } + target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); } -void AuraEffect::HandleAuraModStateImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const +/********************************/ +/*** COMBAT RATING ***/ +/********************************/ + +void AuraEffect::HandleModRating(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->ApplySpellImmune(GetId(), IMMUNITY_STATE, GetMiscValue(), apply); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - if (apply && GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) - target->RemoveAurasByType(AuraType(GetMiscValue()), 0 , GetBase()); + for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating) + if (GetMiscValue() & (1 << rating)) + target->ToPlayer()->ApplyRatingMod(CombatRating(rating), GetAmount(), apply); } -void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->ApplySpellImmune(GetId(), IMMUNITY_SCHOOL, GetMiscValue(), (apply)); + if (target->GetTypeId() != TYPEID_PLAYER) + return; - if (GetSpellProto()->Mechanic == MECHANIC_BANISH) - { - if (apply) - target->AddUnitState(UNIT_STAT_ISOLATED); - else - { - bool banishFound = false; - Unit::AuraEffectList const& banishAuras = target->GetAuraEffectsByType(GetAuraType()); - for (Unit::AuraEffectList::const_iterator i = banishAuras.begin(); i != banishAuras.end(); ++i) - if ((*i)->GetSpellProto()->Mechanic == MECHANIC_BANISH) - { - banishFound = true; - break; - } - if (!banishFound) - target->ClearUnitState(UNIT_STAT_ISOLATED); - } - } + // Just recalculate ratings + for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating) + if (GetMiscValue() & (1 << rating)) + target->ToPlayer()->ApplyRatingMod(CombatRating(rating), 0, apply); +} - if (apply && GetMiscValue() == SPELL_SCHOOL_MASK_NORMAL) - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); +/********************************/ +/*** ATTACK POWER ***/ +/********************************/ - // remove all flag auras (they are positive, but they must be removed when you are immune) - if (GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY - && GetSpellProto()->AttributesEx2 & SPELL_ATTR2_DAMAGE_REDUCED_SHIELD) - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); +void AuraEffect::HandleAuraModAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; - // TODO: optimalize this cycle - use RemoveAurasWithInterruptFlags call or something else - if ((apply) - && GetSpellProto()->AttributesEx & SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY - && IsPositiveSpell(GetId())) //Only positive immunity removes auras - { - uint32 school_mask = GetMiscValue(); - Unit::AuraApplicationMap& Auras = target->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator iter = Auras.begin(); iter != Auras.end();) - { - SpellEntry const *spell = iter->second->GetBase()->GetSpellProto(); - if ((GetSpellSchoolMask(spell) & school_mask)//Check for school mask - && CanSpellDispelAura(GetSpellProto(), spell) - && !iter->second->IsPositive() //Don't remove positive spells - && spell->Id != GetId()) //Don't remove self - { - target->RemoveAura(iter); - } - else - ++iter; - } - } + Unit* target = aurApp->GetTarget(); + + target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply); } -void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, GetMiscValue(), apply); + if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0) + return; + + target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply); } -void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - target->ApplySpellDispelImmunity(m_spellProto, DispelType(GetMiscValue()), (apply)); + //UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1 + target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount()), apply); } -/*********************************************************/ -/*** MODIFY STATS ***/ -/*********************************************************/ +void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + return; -/********************************/ -/*** RESISTANCE ***/ -/********************************/ + Unit* target = aurApp->GetTarget(); -void AuraEffect::HandleAuraModResistanceExclusive(AuraApplication const* aurApp, uint8 mode, bool apply) const + if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0) + return; + + //UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1 + target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()), apply); +} + +void AuraEffect::HandleAuraModRangedAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) - { - if (GetMiscValue() & int32(1<GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE, 1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, float(GetAmount() - amount), apply); - if (target->GetTypeId() == TYPEID_PLAYER) - target->ApplyResistanceBuffModsMod(SpellSchools(x), aurApp->IsPositive(), float(GetAmount() - amount), apply); - } - } - } + // Recalculate bonus + if (target->GetTypeId() == TYPEID_PLAYER && !(target->getClassMask() & CLASSMASK_WAND_USERS)) + target->ToPlayer()->UpdateAttackPowerAndDamage(true); } -void AuraEffect::HandleAuraModResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + HandleAuraModAttackPowerOfArmor(aurApp, mode, apply); +} + +void AuraEffect::HandleAuraModAttackPowerOfArmor(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) - { - if (GetMiscValue() & int32(1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetAmount()), apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->isPet()) - target->ApplyResistanceBuffModsMod(SpellSchools(x), GetAmount() > 0, (float)GetAmount(), apply); - } - } + // Recalculate bonus + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->UpdateAttackPowerAndDamage(false); } - -void AuraEffect::HandleAuraModBaseResistancePCT(AuraApplication const* aurApp, uint8 mode, bool apply) const +/********************************/ +/*** DAMAGE BONUS ***/ +/********************************/ +void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - // only players have base stats - if (target->GetTypeId() != TYPEID_PLAYER) + // apply item specific bonuses for already equipped weapon + if (target->GetTypeId() == TYPEID_PLAYER) { - //pets only have base armor - if (target->ToCreature()->isPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) - target->HandleStatModifier(UNIT_MOD_ARMOR, BASE_PCT, float(GetAmount()), apply); + for (int i = 0; i < MAX_ATTACK; ++i) + if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true)) + target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply); } - else + + // GetMiscValue() is bitmask of spell schools + // 1 (0-bit) - normal school damage (SPELL_SCHOOL_MASK_NORMAL) + // 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands + // 127 - full bitmask any damages + // + // mods must be applied base at equipped weapon class and subclass comparison + // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask + // GetMiscValue() comparison with item generated damage types + + if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0) { - for (int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL; x++) + // apply generic physical damage bonuses including wand case + if (GetSpellProto()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER) { - if (GetMiscValue() & int32(1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetAmount()), apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply); + + if (target->GetTypeId() == TYPEID_PLAYER) + { + if (GetAmount() > 0) + target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, GetAmount(), apply); + else + target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, GetAmount(), apply); + } + } + else + { + // done in Player::_ApplyWeaponDependentAuraMods } } -} -void AuraEffect::HandleModResistancePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + // Skip non magic case for speedup + if ((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0) return; - Unit* target = aurApp->GetTarget(); + if (GetSpellProto()->EquippedItemClass != -1 || GetSpellProto()->EquippedItemInventoryTypeMask != 0) + { + // wand magic case (skip generic to all item spell bonuses) + // done in Player::_ApplyWeaponDependentAuraMods - for (int8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) + // Skip item specific requirements for not wand magic damage + return; + } + + // Magic damage modifiers implemented in Unit::SpellDamageBonus + // This information for client side use only + if (target->GetTypeId() == TYPEID_PLAYER) { - if (GetMiscValue() & int32(1< 0) { - target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetAmount()), apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->isPet()) + for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) { - target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), true, (float)GetAmount(), apply); - target->ApplyResistanceBuffModsPercentMod(SpellSchools(i), false, (float)GetAmount(), apply); + if ((GetMiscValue() & (1<ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, GetAmount(), apply); + } + } + else + { + for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) + { + if ((GetMiscValue() & (1<ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i, GetAmount(), apply); } } + if (Guardian* pet = target->ToPlayer()->GetGuardianPet()) + pet->UpdateAttackPowerAndDamage(); } } -void AuraEffect::HandleModBaseResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; - Unit* target = aurApp->GetTarget(); + Player* target = aurApp->GetTarget()->ToPlayer(); + if (!target) + return; - // only players have base stats - if (target->GetTypeId() != TYPEID_PLAYER) - { - //only pets have base stats - if (target->ToCreature()->isPet() && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) - target->HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(GetAmount()), apply); - } - else - { - for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) - if (GetMiscValue() & (1<HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetAmount()), apply); - } + if (target->HasItemFitToSpellRequirements(GetSpellProto())) + aurApp->GetTarget()->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, GetAmount()/100.0f, apply); } -void AuraEffect::HandleModTargetResistance(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - // applied to damage as HandleNoImmediateEffect in Unit::CalcAbsorbResist and Unit::CalcArmorReducedDamage - - // show armor penetration - if (target->GetTypeId() == TYPEID_PLAYER && (GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)) - target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE, GetAmount(), apply); - - // show as spell penetration only full spell penetration bonuses (all resistances except armor and holy - if (target->GetTypeId() == TYPEID_PLAYER && (GetMiscValue() & SPELL_SCHOOL_MASK_SPELL) == SPELL_SCHOOL_MASK_SPELL) - target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE, GetAmount(), apply); + target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); } -/********************************/ -/*** STAT ***/ -/********************************/ - -void AuraEffect::HandleAuraModStat(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) return; Unit* target = aurApp->GetTarget(); - if (GetMiscValue() < -2 || GetMiscValue() > 4) - { - sLog->outError("WARNING: Spell %u effect %u has an unsupported misc value (%i) for SPELL_AURA_MOD_STAT ", GetId(), GetEffIndex(), GetMiscValue()); - return; - } + BaseModType modType = FLAT_MOD; + if (GetAuraType() == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT) + modType = PCT_MOD; - for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) - { - // -1 or -2 is all stats (misc < -2 checked in function beginning) - if (GetMiscValue() < 0 || GetMiscValue() == i) - { - //target->ApplyStatMod(Stats(i), m_amount, apply); - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetAmount()), apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->isPet()) - target->ApplyStatBuffMod(Stats(i), (float)GetAmount(), apply); - } - } + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetAmount()), apply); } -void AuraEffect::HandleModPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const +/********************************/ +/*** POWER COST ***/ +/********************************/ + +void AuraEffect::HandleModPowerCostPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); - if (GetMiscValue() < -1 || GetMiscValue() > 4) - { - sLog->outError("WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); - return; - } - - // only players have base stats - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i) - { - if (GetMiscValue() == i || GetMiscValue() == -1) - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_amount), apply); - } + float amount = CalculatePctN(1.0f, GetAmount()); + for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) + if (GetMiscValue() & (1 << i)) + target->ApplyModSignedFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + i, amount, apply); } -void AuraEffect::HandleModSpellDamagePercentFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleModPowerCost(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - // Magic damage modifiers implemented in Unit::SpellDamageBonus - // This information for client side use only - // Recalculate bonus - target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); + for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) + if (GetMiscValue() & (1<ApplyModInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i, GetAmount(), apply); } -void AuraEffect::HandleModSpellHealingPercentFromStat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleArenaPreparation(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - // Recalculate bonus - target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); + if (apply) + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION); + else + { + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType())) + return; + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION); + } } -void AuraEffect::HandleModSpellDamagePercentFromAttackPower(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleNoReagentUseAura(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); @@ -4933,15 +4551,19 @@ void AuraEffect::HandleModSpellDamagePercentFromAttackPower(AuraApplication cons if (target->GetTypeId() != TYPEID_PLAYER) return; - // Magic damage modifiers implemented in Unit::SpellDamageBonus - // This information for client side use only - // Recalculate bonus - target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); + flag96 mask; + Unit::AuraEffectList const& noReagent = target->GetAuraEffectsByType(SPELL_AURA_NO_REAGENT_USE); + for (Unit::AuraEffectList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i) + mask |= (*i)->m_spellProto->EffectSpellClassMask[(*i)->m_effIndex]; + + target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1 , mask[0]); + target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+1, mask[1]); + target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+2, mask[2]); } -void AuraEffect::HandleModSpellHealingPercentFromAttackPower(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleAuraRetainComboPoints(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); @@ -4949,784 +4571,782 @@ void AuraEffect::HandleModSpellHealingPercentFromAttackPower(AuraApplication con if (target->GetTypeId() != TYPEID_PLAYER) return; - // Recalculate bonus - target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); + // combo points was added in SPELL_EFFECT_ADD_COMBO_POINTS handler + // remove only if aura expire by time (in case combo points amount change aura removed without combo points lost) + if (!(apply) && GetBase()->GetDuration() == 0 && target->ToPlayer()->GetComboTarget()) + if (Unit* unit = ObjectAccessor::GetUnit(*target, target->ToPlayer()->GetComboTarget())) + target->ToPlayer()->AddComboPoints(unit, -GetAmount()); } -void AuraEffect::HandleModHealingDone(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - // implemented in Unit::SpellHealingBonus - // this information is for client side only - target->ToPlayer()->UpdateSpellDamageAndHealingBonus(); -} +/*********************************************************/ +/*** OTHERS ***/ +/*********************************************************/ -void AuraEffect::HandleModTotalPercentStat(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_REAPPLY))) return; Unit* target = aurApp->GetTarget(); - if (GetMiscValue() < -1 || GetMiscValue() > 4) - { - sLog->outError("WARNING: Misc Value for SPELL_AURA_MOD_PERCENT_STAT not valid"); - return; - } - - // save current health state - float healthPct = target->GetHealthPct(); - bool alive = target->isAlive(); + Unit* caster = GetCaster(); - for (int32 i = STAT_STRENGTH; i < MAX_STATS; i++) + if (mode & AURA_EFFECT_HANDLE_REAL) { - if (GetMiscValue() == i || GetMiscValue() == -1) + // pet auras + if (PetAura const* petSpell = sSpellMgr->GetPetAura(GetId(), m_effIndex)) { - target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetAmount()), apply); - if (target->GetTypeId() == TYPEID_PLAYER || target->ToCreature()->isPet()) - target->ApplyStatPercentBuffMod(Stats(i), float(GetAmount()), apply); + if (apply) + target->AddPetAura(petSpell); + else + target->RemovePetAura(petSpell); } } - //recalculate current HP/MP after applying aura modifications (only for spells with SPELL_ATTR0_UNK4 0x00000010 flag) - if (GetMiscValue() == STAT_STAMINA && (m_spellProto->Attributes & SPELL_ATTR0_UNK4)) - target->SetHealth(std::max(uint32(healthPct * target->GetMaxHealth() * 0.01f), (alive ? 1 : 0))); -} - -void AuraEffect::HandleAuraModResistenceOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - if (GetMiscValue() != SPELL_SCHOOL_MASK_NORMAL) + if (mode & (AURA_EFFECT_HANDLE_REAL | AURA_EFFECT_HANDLE_REAPPLY)) { - // support required adding replace UpdateArmor by loop by UpdateResistence at intellect update - // and include in UpdateResistence same code as in UpdateArmor for aura mod apply. - sLog->outError("Aura SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT(182) does not work for non-armor type resistances!"); - return; - } - - // Recalculate Armor - target->UpdateArmor(); -} - -void AuraEffect::HandleAuraModExpertise(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->ToPlayer()->UpdateExpertise(BASE_ATTACK); - target->ToPlayer()->UpdateExpertise(OFF_ATTACK); -} - -/********************************/ -/*** HEAL & ENERGIZE ***/ -/********************************/ -void AuraEffect::HandleModPowerRegen(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - // Update manaregen value - if (GetMiscValue() == POWER_MANA) - target->ToPlayer()->UpdateManaRegen(); - // other powers are not immediate effects - implemented in Player::Regenerate, Creature::Regenerate -} - -void AuraEffect::HandleModPowerRegenPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - HandleModPowerRegen(aurApp, mode, apply); -} + // AT APPLY + if (apply) + { + // Overpower + if (caster && m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && + m_spellProto->SpellFamilyFlags[0] & 0x4) + { + // In addition, if you strike a player.. + if (target->GetTypeId() != TYPEID_PLAYER) + return; + // ..while they are casting + if (target->IsNonMeleeSpellCasted(false, false, true, false, false)) + if (AuraEffect * aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARRIOR, 2775, 0)) + switch (aurEff->GetId()) + { + // Unrelenting Assault, rank 1 + case 46859: + target->CastSpell(target, 64849, true, NULL, aurEff); + break; + // Unrelenting Assault, rank 2 + case 46860: + target->CastSpell(target, 64850, true, NULL, aurEff); + break; + } + } + switch(GetId()) + { + case 1515: // Tame beast + // FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness + if (caster && target->CanHaveThreatList()) + target->AddThreat(caster, 10.0f); + break; + case 13139: // net-o-matic + // root to self part of (root_target->charge->root_self sequence + if (caster) + caster->CastSpell(caster, 13138, true, NULL, this); + break; + case 34026: // kill command + { + Unit* pet = target->GetGuardianPet(); + if (!pet) + break; -void AuraEffect::HandleModManaRegen(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; + target->CastSpell(target, 34027, true, NULL, this); - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - //Note: an increase in regen does NOT cause threat. - target->ToPlayer()->UpdateManaRegen(); -} - -void AuraEffect::HandleAuraModIncreaseHealth(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (apply) - { - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); - target->ModifyHealth(GetAmount()); - } - else - { - if (int32(target->GetHealth()) > GetAmount()) - target->ModifyHealth(-GetAmount()); + // set 3 stacks and 3 charges (to make all auras not disappear at once) + Aura * owner_aura = target->GetAura(34027, GetCasterGUID()); + Aura * pet_aura = pet->GetAura(58914, GetCasterGUID()); + if (owner_aura) + { + owner_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount); + } + if (pet_aura) + { + pet_aura->SetCharges(0); + pet_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount); + } + break; + } + case 37096: // Blood Elf Illusion + { + if (caster) + { + switch(caster->getGender()) + { + case GENDER_FEMALE: + caster->CastSpell(target, 37095, true, NULL, this); // Blood Elf Disguise + break; + case GENDER_MALE: + caster->CastSpell(target, 37093, true, NULL, this); + break; + default: + break; + } + } + break; + } + case 55198: // Tidal Force + { + target->CastSpell(target, 55166, true, NULL, this); + // set 3 stacks and 3 charges (to make all auras not disappear at once) + Aura * owner_aura = target->GetAura(55166, GetCasterGUID()); + if (owner_aura) + { + // This aura lasts 2 sec, need this hack to properly proc spells + // TODO: drop aura charges for ApplySpellMod in ProcDamageAndSpell + GetBase()->SetDuration(owner_aura->GetDuration()); + // Make aura be not charged-this prevents removing charge on not crit spells + owner_aura->SetCharges(0); + owner_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount); + } + break; + } + case 39850: // Rocket Blast + if (roll_chance_i(20)) // backfire stun + target->CastSpell(target, 51581, true, NULL, this); + break; + case 43873: // Headless Horseman Laugh + target->PlayDistanceSound(11965); + break; + case 46354: // Blood Elf Illusion + if (caster) + { + switch(caster->getGender()) + { + case GENDER_FEMALE: + caster->CastSpell(target, 46356, true, NULL, this); + break; + case GENDER_MALE: + caster->CastSpell(target, 46355, true, NULL, this); + break; + } + } + break; + case 46361: // Reinforced Net + if (caster) + { + float currentGroundLevel = target->GetBaseMap()->GetHeight(target->GetPositionX(), target->GetPositionY(), MAX_HEIGHT); + if (target->GetPositionZ() > currentGroundLevel) + target->GetMotionMaster()->MoveFall(currentGroundLevel); + } + break; + case 46699: // Requires No Ammo + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use + break; + case 49028: + if (caster) + if (AuraEffect *aurEff = caster->GetAuraEffect(63330, 0)) // glyph of Dancing Rune Weapon + GetBase()->SetDuration(GetBase()->GetDuration() + aurEff->GetAmount()); + break; + case 52916: // Honor Among Thieves + if (target->GetTypeId() == TYPEID_PLAYER) + if (Unit* spellTarget = ObjectAccessor::GetUnit(*target, target->ToPlayer()->GetComboTarget())) + target->CastSpell(spellTarget, 51699, true); + break; + case 28832: // Mark of Korth'azz + case 28833: // Mark of Blaumeux + case 28834: // Mark of Rivendare + case 28835: // Mark of Zeliek + if (caster) // actually we can also use cast(this, originalcasterguid) + { + int32 damage; + switch(GetBase()->GetStackAmount()) + { + case 1: damage = 0; break; + case 2: damage = 500; break; + case 3: damage = 1000; break; + case 4: damage = 1500; break; + case 5: damage = 4000; break; + case 6: damage = 12000; break; + default:damage = 20000 + 1000 * (GetBase()->GetStackAmount() - 7); break; + } + if (damage) + caster->CastCustomSpell(28836, SPELLVALUE_BASE_POINT0, damage, target); + } + break; + case 63322: // Saronite Vapors + { + int32 mana = int32(GetAmount() * pow(2.0f, GetBase()->GetStackAmount())); // mana restore - bp * 2^stackamount + int32 damage = mana * 2; // damage + caster->CastCustomSpell(target, 63337, &mana, NULL, NULL, true); + caster->CastCustomSpell(target, 63338, &damage, NULL, NULL, true); + break; + } + case 71563: + if (Aura* newAura = target->AddAura(71564, target)) + newAura->SetStackAmount(newAura->GetSpellProto()->StackAmount); + } + } + // AT REMOVE else - target->SetHealth(1); - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); - } -} - -void AuraEffect::HandleAuraModIncreaseMaxHealth(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - uint32 oldhealth = target->GetHealth(); - double healthPercentage = (double)oldhealth / (double)target->GetMaxHealth(); - - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetAmount()), apply); - - // refresh percentage - if (oldhealth > 0) - { - uint32 newhealth = uint32(ceil((double)target->GetMaxHealth() * healthPercentage)); - if (newhealth == 0) - newhealth = 1; - - target->SetHealth(newhealth); - } -} - -void AuraEffect::HandleAuraModIncreaseEnergy(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - Powers powerType = Powers(GetMiscValue()); - // do not check power type, we can always modify the maximum - // as the client will not see any difference - // also, placing conditions that may change during the aura duration - // inside effect handlers is not a good idea - //if (int32(powerType) != GetMiscValue()) - // return; - - UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType); - - // Special case with temporary increase max/current power (percent) - if (GetId() == 64904) // Hymn of Hope - { - if (mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK) { - int32 change = target->GetPower(powerType) + (apply ? GetAmount() : -GetAmount()); - if (change < 0) - change = 0; - target->SetPower(powerType, change); - } - } - - // generic flat case - target->HandleStatModifier(unitMod, TOTAL_VALUE, float(GetAmount()), apply); -} - -void AuraEffect::HandleAuraModIncreaseEnergyPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - Powers powerType = Powers(GetMiscValue()); - // do not check power type, we can always modify the maximum - // as the client will not see any difference - // also, placing conditions that may change during the aura duration - // inside effect handlers is not a good idea - //if (int32(powerType) != GetMiscValue()) - // return; - - UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + powerType); - - target->HandleStatModifier(unitMod, TOTAL_PCT, float(GetAmount()), apply); -} - -void AuraEffect::HandleAuraModIncreaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - // Unit will keep hp% after MaxHealth being modified if unit is alive. - float percent = target->GetHealthPct(); - target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetAmount()), apply); - if (target->isAlive()) - target->SetHealth(target->CountPctFromMaxHealth(int32(percent))); -} - -void AuraEffect::HandleAuraIncreaseBaseHealthPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - target->HandleStatModifier(UNIT_MOD_HEALTH, BASE_PCT, float(GetAmount()), apply); -} - -/********************************/ -/*** FIGHT ***/ -/********************************/ - -void AuraEffect::HandleAuraModParryPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->ToPlayer()->UpdateParryPercentage(); -} - -void AuraEffect::HandleAuraModDodgePercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->ToPlayer()->UpdateDodgePercentage(); -} - -void AuraEffect::HandleAuraModBlockPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->ToPlayer()->UpdateBlockPercentage(); -} - -void AuraEffect::HandleAuraModRegenInterrupt(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - HandleModManaRegen(aurApp, mode, apply); -} - -void AuraEffect::HandleAuraModWeaponCritPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - for (int i = 0; i < MAX_ATTACK; ++i) - if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true)) - target->ToPlayer()->_ApplyWeaponDependentAuraCritMod(pItem, WeaponAttackType(i), this, apply); - - // mods must be applied base at equipped weapon class and subclass comparison - // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask - // GetMiscValue() comparison with item generated damage types - - if (GetSpellProto()->EquippedItemClass == -1) - { - target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - } - else - { - // done in Player::_ApplyWeaponDependentAuraMods - } -} - -void AuraEffect::HandleModHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() == TYPEID_PLAYER) - { - target->ToPlayer()->UpdateMeleeHitChances(); - target->ToPlayer()->UpdateRangedHitChances(); - } - else - { - target->m_modMeleeHitChance += (apply) ? GetAmount() : (-GetAmount()); - target->m_modRangedHitChance += (apply) ? GetAmount() : (-GetAmount()); - } -} - -void AuraEffect::HandleModSpellHitChance(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->UpdateSpellHitChances(); - else - target->m_modSpellHitChance += (apply) ? GetAmount(): (-GetAmount()); -} - -void AuraEffect::HandleModSpellCritChance(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->UpdateAllSpellCritChances(); - else - target->m_baseSpellCritChance += (apply) ? GetAmount():-GetAmount(); -} - -void AuraEffect::HandleModSpellCritChanceShool(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - for (int school = SPELL_SCHOOL_NORMAL; school < MAX_SPELL_SCHOOL; ++school) - if (GetMiscValue() & (1<ToPlayer()->UpdateSpellCritChance(school); -} - -void AuraEffect::HandleAuraModCritPct(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - { - target->m_baseSpellCritChance += (apply) ? GetAmount():-GetAmount(); - return; - } - - target->ToPlayer()->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - target->ToPlayer()->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetAmount()), apply); - - // included in Player::UpdateSpellCritChance calculation - target->ToPlayer()->UpdateAllSpellCritChances(); -} - -/********************************/ -/*** ATTACK SPEED ***/ -/********************************/ - -void AuraEffect::HandleModCastingSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - target->ApplyCastTimePercentMod((float)GetAmount(), apply); -} - -void AuraEffect::HandleModMeleeRangedSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply); - target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), apply); - target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); -} - -void AuraEffect::HandleModCombatSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - target->ApplyCastTimePercentMod(float(m_amount), apply); - target->ApplyAttackTimePercentMod(BASE_ATTACK, float(GetAmount()), apply); - target->ApplyAttackTimePercentMod(OFF_ATTACK, float(GetAmount()), apply); - target->ApplyAttackTimePercentMod(RANGED_ATTACK, float(GetAmount()), apply); -} - -void AuraEffect::HandleModAttackSpeed(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply); - target->UpdateDamagePhysical(BASE_ATTACK); -} - -void AuraEffect::HandleModMeleeSpeedPct(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - target->ApplyAttackTimePercentMod(BASE_ATTACK, (float)GetAmount(), apply); - target->ApplyAttackTimePercentMod(OFF_ATTACK, (float)GetAmount(), apply); -} - -void AuraEffect::HandleAuraModRangedHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); -} - -void AuraEffect::HandleRangedAmmoHaste(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; - - target->ApplyAttackTimePercentMod(RANGED_ATTACK, (float)GetAmount(), apply); -} - -/********************************/ -/*** COMBAT RATING ***/ -/********************************/ - -void AuraEffect::HandleModRating(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_PLAYER) - return; + if ((IsQuestTameSpell(GetId())) && caster && caster->isAlive() && target->isAlive()) + { + uint32 finalSpelId = 0; + switch(GetId()) + { + case 19548: finalSpelId = 19597; break; + case 19674: finalSpelId = 19677; break; + case 19687: finalSpelId = 19676; break; + case 19688: finalSpelId = 19678; break; + case 19689: finalSpelId = 19679; break; + case 19692: finalSpelId = 19680; break; + case 19693: finalSpelId = 19684; break; + case 19694: finalSpelId = 19681; break; + case 19696: finalSpelId = 19682; break; + case 19697: finalSpelId = 19683; break; + case 19699: finalSpelId = 19685; break; + case 19700: finalSpelId = 19686; break; + case 30646: finalSpelId = 30647; break; + case 30653: finalSpelId = 30648; break; + case 30654: finalSpelId = 30652; break; + case 30099: finalSpelId = 30100; break; + case 30102: finalSpelId = 30103; break; + case 30105: finalSpelId = 30104; break; + } - for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating) - if (GetMiscValue() & (1 << rating)) - target->ToPlayer()->ApplyRatingMod(CombatRating(rating), GetAmount(), apply); -} + if (finalSpelId) + caster->CastSpell(target, finalSpelId, true, NULL, this); + } -void AuraEffect::HandleModRatingFromStat(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; + switch(m_spellProto->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + switch(GetId()) + { + case 2584: // Waiting to Resurrect + // Waiting to resurrect spell cancel, we must remove player from resurrect queue + if (target->GetTypeId() == TYPEID_PLAYER) + if (Battleground *bg = target->ToPlayer()->GetBattleground()) + bg->RemovePlayerFromResurrectQueue(target->GetGUID()); + break; + case 36730: // Flame Strike + { + target->CastSpell(target, 36731, true, NULL, this); + break; + } + case 44191: // Flame Strike + { + if (target->GetMap()->IsDungeon()) + { + uint32 spellId = target->GetMap()->IsHeroic() ? 46163 : 44190; - Unit* target = aurApp->GetTarget(); + target->CastSpell(target, spellId, true, NULL, this); + } + break; + } + case 43681: // Inactive + { + if (!target || target->GetTypeId() != TYPEID_PLAYER || aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) + return; - if (target->GetTypeId() != TYPEID_PLAYER) - return; + if (target->GetMap()->IsBattleground()) + target->ToPlayer()->LeaveBattleground(); + break; + } + case 42783: // Wrath of the Astromancer + target->CastSpell(target, GetAmount(), true, NULL, this); + break; + case 46308: // Burning Winds casted only at creatures at spawn + target->CastSpell(target, 47287, true, NULL, this); + break; + case 52172: // Coyote Spirit Despawn Aura + case 60244: // Blood Parrot Despawn Aura + target->CastSpell((Unit*)NULL, GetAmount(), true, NULL, this); + break; + case 58600: // Restricted Flight Area + if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + target->CastSpell(target, 58601, true); + break; + } + break; + case SPELLFAMILY_MAGE: + // Living Bomb + if (m_spellProto->SpellFamilyFlags[1] & 0x20000) + { + AuraRemoveMode mode = aurApp->GetRemoveMode(); + if (caster && (mode == AURA_REMOVE_BY_ENEMY_SPELL || mode == AURA_REMOVE_BY_EXPIRE)) + caster->CastSpell(target, GetAmount(), true); + } + break; + case SPELLFAMILY_WARLOCK: + // Haunt + if (m_spellProto->SpellFamilyFlags[1] & 0x40000) + { + if (caster) + target->CastCustomSpell(caster, 48210, &m_amount, 0, 0, true, NULL, this, GetCasterGUID()); + } + break; + case SPELLFAMILY_DRUID: + // Lifebloom + if (GetSpellProto()->SpellFamilyFlags[1] & 0x10) + { + // Final heal only on duration end + if (aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) + return; - // Just recalculate ratings - for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating) - if (GetMiscValue() & (1 << rating)) - target->ToPlayer()->ApplyRatingMod(CombatRating(rating), 0, apply); -} + // final heal + int32 stack = GetBase()->GetStackAmount(); + target->CastCustomSpell(target, 33778, &m_amount, &stack, NULL, true, NULL, this, GetCasterGUID()); -/********************************/ -/*** ATTACK POWER ***/ -/********************************/ + // restore mana + if (caster) + { + int32 returnmana = CalculatePctU(caster->GetCreateMana(), GetSpellProto()->ManaCostPercentage) * stack / 2; + caster->CastCustomSpell(caster, 64372, &returnmana, NULL, NULL, true, NULL, this, GetCasterGUID()); + } + } + break; + case SPELLFAMILY_PRIEST: + // Vampiric Touch + if (m_spellProto->SpellFamilyFlags[1] & 0x0400 && aurApp->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && GetEffIndex() == 0) + { + if (AuraEffect const* aurEff = GetBase()->GetEffect(1)) + { + int32 damage = aurEff->GetAmount() * 8; + // backfire damage + target->CastCustomSpell(target, 64085, &damage, NULL, NULL, true, NULL, NULL, GetCasterGUID()); + } + } + break; + case SPELLFAMILY_HUNTER: + // Misdirection + if (GetId() == 34477) + target->SetReducedThreatPercent(0, 0); + break; + case SPELLFAMILY_DEATHKNIGHT: + // Summon Gargoyle (Dismiss Gargoyle at remove) + if (GetId() == 61777) + target->CastSpell(target, GetAmount(), true); + break; + default: + break; + } + } + } -void AuraEffect::HandleAuraModAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; + // AT APPLY & REMOVE - Unit* target = aurApp->GetTarget(); + switch(m_spellProto->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + { + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + break; + switch(GetId()) + { + // Recently Bandaged + case 11196: + target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply); + break; + // Unstable Power + case 24658: + { + uint32 spellId = 24659; + if (apply && caster) + { + SpellEntry const* spell = sSpellStore.LookupEntry(spellId); - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetAmount()), apply); -} + for (uint32 i = 0; i < spell->StackAmount; ++i) + caster->CastSpell(target, spell->Id, true, NULL, NULL, GetCasterGUID()); + break; + } + target->RemoveAurasDueToSpell(spellId); + break; + } + // Restless Strength + case 24661: + { + uint32 spellId = 24662; + if (apply && caster) + { + SpellEntry const* spell = sSpellStore.LookupEntry(spellId); + for (uint32 i = 0; i < spell->StackAmount; ++i) + caster->CastSpell(target, spell->Id, true, NULL, NULL, GetCasterGUID()); + break; + } + target->RemoveAurasDueToSpell(spellId); + break; + } + // Tag Murloc + case 30877: + { + // Tag/untag Blacksilt Scout + target->SetEntry(apply ? 17654 : 17326); + break; + } + //Summon Fire Elemental + case 40133: + { + if (!caster) + break; -void AuraEffect::HandleAuraModRangedAttackPower(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; + Unit *owner = caster->GetOwner(); + if (owner && owner->GetTypeId() == TYPEID_PLAYER) + { + if (apply) + owner->CastSpell(owner, 8985, true); + else + owner->ToPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); + } + break; + } + //Summon Earth Elemental + case 40132 : + { + if (!caster) + break; - Unit* target = aurApp->GetTarget(); + Unit *owner = caster->GetOwner(); + if (owner && owner->GetTypeId() == TYPEID_PLAYER) + { + if (apply) + owner->CastSpell(owner, 19704, true); + else + owner->ToPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); + } + break; + } + case 57723: // Exhaustion + case 57724: // Sated + { + switch(GetId()) + { + case 57723: target->ApplySpellImmune(GetId(), IMMUNITY_ID, 32182, apply); break; // Heroism + case 57724: target->ApplySpellImmune(GetId(), IMMUNITY_ID, 2825, apply); break; // Bloodlust + } + break; + } + case 57819: // Argent Champion + case 57820: // Ebon Champion + case 57821: // Champion of the Kirin Tor + case 57822: // Wyrmrest Champion + { + if (!caster || caster->GetTypeId() != TYPEID_PLAYER) + break; - if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0) - return; + uint32 FactionID = 0; - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetAmount()), apply); -} + if (apply) + { + switch(m_spellProto->Id) + { + case 57819: FactionID = 1106; break; // Argent Crusade + case 57820: FactionID = 1098; break; // Knights of the Ebon Blade + case 57821: FactionID = 1090; break; // Kirin Tor + case 57822: FactionID = 1091; break; // The Wyrmrest Accord + } + } + caster->ToPlayer()->SetChampioningFaction(FactionID); + break; + } + // LK Intro VO (1) + case 58204: + if (target->GetTypeId() == TYPEID_PLAYER) + { + // Play part 1 + if (apply) + target->PlayDirectSound(14970, target->ToPlayer()); + // continue in 58205 + else + target->CastSpell(target, 58205, true); + } + break; + // LK Intro VO (2) + case 58205: + if (target->GetTypeId() == TYPEID_PLAYER) + { + // Play part 2 + if (apply) + target->PlayDirectSound(14971, target->ToPlayer()); + // Play part 3 + else + target->PlayDirectSound(14972, target->ToPlayer()); + } + break; + case 62061: // Festive Holiday Mount + if (target->HasAuraType(SPELL_AURA_MOUNTED)) + { + uint32 creatureEntry = 0; + if (apply) + { + if (target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) + creatureEntry = 24906; + else + creatureEntry = 15665; + } + else + creatureEntry = target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetMiscValue(); -void AuraEffect::HandleAuraModAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; + if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry)) + { + uint32 team = 0; + if (target->GetTypeId() == TYPEID_PLAYER) + team = target->ToPlayer()->GetTeam(); - Unit* target = aurApp->GetTarget(); + uint32 displayID = sObjectMgr->ChooseDisplayId(team, creatureInfo); + sObjectMgr->GetCreatureModelRandomGender(&displayID); - //UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1 - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetAmount()), apply); -} + target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, displayID); + } + } + break; + } -void AuraEffect::HandleAuraModRangedAttackPowerPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; + break; + } + case SPELLFAMILY_MAGE: + { + //if (!(mode & AURA_EFFECT_HANDLE_REAL)) + //break; + break; + } + case SPELLFAMILY_PRIEST: + { + //if (!(mode & AURA_EFFECT_HANDLE_REAL)) + //break; + break; + } + case SPELLFAMILY_DRUID: + { + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + break; + switch(GetId()) + { + case 52610: // Savage Roar + { + uint32 spellId = 62071; + if (apply) + { + if (target->GetShapeshiftForm() != FORM_CAT) + break; - Unit* target = aurApp->GetTarget(); + target->CastSpell(target, spellId, true, NULL, NULL, GetCasterGUID()); + break; + } + target->RemoveAurasDueToSpell(spellId); + break; + } + case 61336: // Survival Instincts + { + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + break; - if ((target->getClassMask() & CLASSMASK_WAND_USERS) != 0) - return; + if (apply) + { + if (!target->IsInFeralForm()) + break; - //UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1 - target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetAmount()), apply); + int32 bp0 = int32(target->CountPctFromMaxHealth(GetAmount())); + target->CastCustomSpell(target, 50322, &bp0, NULL, NULL, true); + } + else + target-> RemoveAurasDueToSpell(50322); + break; + } + } + // Predatory Strikes + if (target->GetTypeId() == TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563) + { + target->ToPlayer()->UpdateAttackPowerAndDamage(); + } + break; + } + case SPELLFAMILY_SHAMAN: + { + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + break; + // Sentry Totem + if (GetId() == 6495 && caster->GetTypeId() == TYPEID_PLAYER) + { + if (apply) + { + uint64 guid = caster->m_SummonSlot[3]; + if (guid) + { + Creature *totem = caster->GetMap()->GetCreature(guid); + if (totem && totem->isTotem()) + caster->ToPlayer()->CastSpell(totem, 6277, true); + } + } + else + caster->ToPlayer()->StopCastingBindSight(); + return; + } + break; + } + case SPELLFAMILY_PALADIN: + // if (!(mode & AURA_EFFECT_HANDLE_REAL)) + // break; + break; + } } -void AuraEffect::HandleAuraModRangedAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; - Unit* target = aurApp->GetTarget(); - - // Recalculate bonus - if (target->GetTypeId() == TYPEID_PLAYER && !(target->getClassMask() & CLASSMASK_WAND_USERS)) - target->ToPlayer()->UpdateAttackPowerAndDamage(true); -} - -void AuraEffect::HandleAuraModAttackPowerOfStatPercent(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - HandleAuraModAttackPowerOfArmor(aurApp, mode, apply); -} - -void AuraEffect::HandleAuraModAttackPowerOfArmor(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; + if (!apply) + { + Unit* caster = GetCaster(); - Unit* target = aurApp->GetTarget(); + if (!caster || caster->GetTypeId() != TYPEID_PLAYER) + return; - // Recalculate bonus - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->UpdateAttackPowerAndDamage(false); -} -/********************************/ -/*** DAMAGE BONUS ***/ -/********************************/ -void AuraEffect::HandleModDamageDone(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) - return; + Player *plCaster = caster->ToPlayer(); + Unit* target = aurApp->GetTarget(); - Unit* target = aurApp->GetTarget(); + if (target->getDeathState() != JUST_DIED) + return; - // apply item specific bonuses for already equipped weapon - if (target->GetTypeId() == TYPEID_PLAYER) - { - for (int i = 0; i < MAX_ATTACK; ++i) - if (Item* pItem = target->ToPlayer()->GetWeaponForAttack(WeaponAttackType(i), true)) - target->ToPlayer()->_ApplyWeaponDependentAuraDamageMod(pItem, WeaponAttackType(i), this, apply); - } + // Item amount + if (GetAmount() <= 0) + return; - // GetMiscValue() is bitmask of spell schools - // 1 (0-bit) - normal school damage (SPELL_SCHOOL_MASK_NORMAL) - // 126 - full bitmask all magic damages (SPELL_SCHOOL_MASK_MAGIC) including wands - // 127 - full bitmask any damages - // - // mods must be applied base at equipped weapon class and subclass comparison - // with spell->EquippedItemClass and EquippedItemSubClassMask and EquippedItemInventoryTypeMask - // GetMiscValue() comparison with item generated damage types + if (GetSpellProto()->EffectItemType[m_effIndex] == 0) + return; - if ((GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL) != 0) - { - // apply generic physical damage bonuses including wand case - if (GetSpellProto()->EquippedItemClass == -1 || target->GetTypeId() != TYPEID_PLAYER) + // Soul Shard + if (GetSpellProto()->EffectItemType[m_effIndex] == 6265) { - target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetAmount()), apply); - target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetAmount()), apply); + // Soul Shard only from units that grant XP or honor + if (!plCaster->isHonorOrXPTarget(target) || + (target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->isTappedBy(plCaster))) + return; - if (target->GetTypeId() == TYPEID_PLAYER) + // If this is Drain Soul, check for Glyph of Drain Soul + if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags[0] & 0x00004000)) { - if (GetAmount() > 0) - target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, GetAmount(), apply); - else - target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, GetAmount(), apply); + // Glyph of Drain Soul - chance to create an additional Soul Shard + if (AuraEffect *aur = caster->GetAuraEffect(58070, 0)) + if (roll_chance_i(aur->GetMiscValue())) + caster->CastSpell(caster, 58068, true, 0, aur); // We _could_ simply do ++count here, but Blizz does it this way :) } } - else - { - // done in Player::_ApplyWeaponDependentAuraMods - } - } - - // Skip non magic case for speedup - if ((GetMiscValue() & SPELL_SCHOOL_MASK_MAGIC) == 0) - return; - - if (GetSpellProto()->EquippedItemClass != -1 || GetSpellProto()->EquippedItemInventoryTypeMask != 0) - { - // wand magic case (skip generic to all item spell bonuses) - // done in Player::_ApplyWeaponDependentAuraMods - // Skip item specific requirements for not wand magic damage - return; - } + //Adding items + uint32 noSpaceForCount = 0; + uint32 count = m_amount; - // Magic damage modifiers implemented in Unit::SpellDamageBonus - // This information for client side use only - if (target->GetTypeId() == TYPEID_PLAYER) - { - if (GetAmount() > 0) + ItemPosCountVec dest; + InventoryResult msg = plCaster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, GetSpellProto()->EffectItemType[m_effIndex], count, &noSpaceForCount); + if (msg != EQUIP_ERR_OK) { - for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) - { - if ((GetMiscValue() & (1<ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, GetAmount(), apply); - } + count-=noSpaceForCount; + plCaster->SendEquipError(msg, NULL, NULL, GetSpellProto()->EffectItemType[m_effIndex]); + if (count == 0) + return; } - else + + Item* newitem = plCaster->StoreNewItem(dest, GetSpellProto()->EffectItemType[m_effIndex], true); + if (!newitem) { - for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) - { - if ((GetMiscValue() & (1<ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i, GetAmount(), apply); - } + plCaster->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); + return; } - if (Guardian* pet = target->ToPlayer()->GetGuardianPet()) - pet->UpdateAttackPowerAndDamage(); + plCaster->SendNewItem(newitem, count, true, true); } } -void AuraEffect::HandleModDamagePercentDone(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleBindSight(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; - Player* target = aurApp->GetTarget()->ToPlayer(); - if (!target) + Unit* target = aurApp->GetTarget(); + + Unit* caster = GetCaster(); + + if (!caster || caster->GetTypeId() != TYPEID_PLAYER) return; - if (target->HasItemFitToSpellRequirements(GetSpellProto())) - aurApp->GetTarget()->ApplyModSignedFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT, GetAmount()/100.0f, apply); + caster->ToPlayer()->SetViewpoint(target, apply); } -void AuraEffect::HandleModOffhandDamagePercent(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleForceReaction(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); - target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetAmount()), apply); -} - -void AuraEffect::HandleShieldBlockValue(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_STAT))) + if (target->GetTypeId() != TYPEID_PLAYER) return; - Unit* target = aurApp->GetTarget(); + Player* player = (Player*)target; - BaseModType modType = FLAT_MOD; - if (GetAuraType() == SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT) - modType = PCT_MOD; + uint32 faction_id = GetMiscValue(); + ReputationRank faction_rank = ReputationRank(m_amount); - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetAmount()), apply); -} + player->GetReputationMgr().ApplyForceReaction(faction_id, faction_rank, apply); + player->GetReputationMgr().SendForceReactions(); -/********************************/ -/*** POWER COST ***/ -/********************************/ + // stop fighting if at apply forced rank friendly or at remove real rank friendly + if ((apply && faction_rank >= REP_FRIENDLY) || (!apply && player->GetReputationRank(faction_id) >= REP_FRIENDLY)) + player->StopAttackFaction(faction_id); +} -void AuraEffect::HandleModPowerCostPCT(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - float amount = CalculatePctN(1.0f, GetAmount()); - for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) - if (GetMiscValue() & (1 << i)) - target->ApplyModSignedFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + i, amount, apply); + if (target->GetTypeId() != TYPEID_UNIT) + return; + + if (!apply) + { + // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit + if (target->HasAuraType(GetAuraType())) + return; + } + + CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->GetEntry()); + if (ci && ci->type == CREATURE_TYPE_BEAST) + target->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply); } -void AuraEffect::HandleModPowerCost(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModFaction(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - for (int i = 0; i < MAX_SPELL_SCHOOL; ++i) - if (GetMiscValue() & (1<ApplyModInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i, GetAmount(), apply); + if (apply) + { + target->setFaction(GetMiscValue()); + if (target->GetTypeId() == TYPEID_PLAYER) + target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + } + else + { + target->RestoreFaction(); + if (target->GetTypeId() == TYPEID_PLAYER) + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + } } -void AuraEffect::HandleArenaPreparation(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleComprehendLanguage(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) return; Unit* target = aurApp->GetTarget(); if (apply) - target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION); + target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG); else { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit if (target->HasAuraType(GetAuraType())) return; - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREPARATION); + + target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG); } } -void AuraEffect::HandleNoReagentUseAura(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const +void AuraEffect::HandleAuraConvertRune(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; @@ -5736,986 +5356,1250 @@ void AuraEffect::HandleNoReagentUseAura(AuraApplication const* aurApp, uint8 mod if (target->GetTypeId() != TYPEID_PLAYER) return; - flag96 mask; - Unit::AuraEffectList const& noReagent = target->GetAuraEffectsByType(SPELL_AURA_NO_REAGENT_USE); - for (Unit::AuraEffectList::const_iterator i = noReagent.begin(); i != noReagent.end(); ++i) - mask |= (*i)->m_spellProto->EffectSpellClassMask[(*i)->m_effIndex]; + Player *plr = (Player*)target; - target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1 , mask[0]); - target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+1, mask[1]); - target->SetUInt32Value(PLAYER_NO_REAGENT_COST_1+2, mask[2]); + if (plr->getClass() != CLASS_DEATH_KNIGHT) + return; + + uint32 runes = m_amount; + // convert number of runes specified in aura amount of rune type in miscvalue to runetype in miscvalueb + if (apply) + { + for (uint32 i = 0; i < MAX_RUNES && runes; ++i) + { + if (GetMiscValue() != plr->GetCurrentRune(i)) + continue; + if (!plr->GetRuneCooldown(i)) + { + plr->AddRuneByAuraEffect(i, RuneType(GetMiscValueB()), this); + --runes; + } + } + } + else + plr->RemoveRunesByAuraEffect(this); } -void AuraEffect::HandleAuraRetainComboPoints(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + Unit* target = aurApp->GetTarget(); + + uint32 triggeredSpellId = m_spellProto->EffectTriggerSpell[m_effIndex]; + + if (mode & AURA_EFFECT_HANDLE_REAL) + { + if (apply) + { + Unit* caster = GetTriggeredSpellCaster(m_spellProto, GetCaster(), target); + + if (!caster) + return; + // If amount avalible cast with basepoints (Crypt Fever for example) + if (GetAmount()) + caster->CastCustomSpell(target, triggeredSpellId, &m_amount, NULL, NULL, true, NULL, this); + else + caster->CastSpell(target, triggeredSpellId, true, NULL, this); + } + else + { + uint64 casterGUID = IsSpellRequiringFocusedTarget(GetSpellProto()) ? GetCasterGUID() : target->GetGUID(); + target->RemoveAura(triggeredSpellId, casterGUID, 0, aurApp->GetRemoveMode()); + } + } + else if (mode & AURA_EFFECT_HANDLE_REAPPLY && apply) + { + uint64 casterGUID = IsSpellRequiringFocusedTarget(GetSpellProto()) ? GetCasterGUID() : target->GetGUID(); + + // change the stack amount to be equal to stack amount of our aura + if (Aura* triggeredAura = target->GetAura(triggeredSpellId, casterGUID)) + triggeredAura->ModStackAmount(GetBase()->GetStackAmount() - triggeredAura->GetStackAmount()); + } +} + +void AuraEffect::HandleAuraOpenStable(AuraApplication const* aurApp, uint8 mode, bool apply) const { if (!(mode & AURA_EFFECT_HANDLE_REAL)) return; Unit* target = aurApp->GetTarget(); - if (target->GetTypeId() != TYPEID_PLAYER) + if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) return; - // combo points was added in SPELL_EFFECT_ADD_COMBO_POINTS handler - // remove only if aura expire by time (in case combo points amount change aura removed without combo points lost) - if (!(apply) && GetBase()->GetDuration() == 0 && target->ToPlayer()->GetComboTarget()) - if (Unit* unit = ObjectAccessor::GetUnit(*target, target->ToPlayer()->GetComboTarget())) - target->ToPlayer()->AddComboPoints(unit, -GetAmount()); -} + if (apply) + target->ToPlayer()->GetSession()->SendStablePet(target->GetGUID()); -/*********************************************************/ -/*** OTHERS ***/ -/*********************************************************/ + // client auto close stable dialog at !apply aura +} -void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleAuraModFakeInebriation(AuraApplication const* aurApp, uint8 mode, bool apply) const { - if (!(mode & (AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK | AURA_EFFECT_HANDLE_REAPPLY))) + if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) return; Unit* target = aurApp->GetTarget(); - Unit* caster = GetCaster(); + if (apply) + { + target->m_invisibilityDetect.AddFlag(INVISIBILITY_DRUNK); + target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, GetAmount()); + + if (target->GetTypeId() == TYPEID_PLAYER) + { + int32 oldval = target->ToPlayer()->GetInt32Value(PLAYER_FAKE_INEBRIATION); + target->ToPlayer()->SetInt32Value(PLAYER_FAKE_INEBRIATION, oldval + GetAmount()); + } + } + else + { + bool removeDetect = !target->HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE); + + target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, -GetAmount()); + + if (target->GetTypeId() == TYPEID_PLAYER) + { + int32 oldval = target->ToPlayer()->GetInt32Value(PLAYER_FAKE_INEBRIATION); + target->ToPlayer()->SetInt32Value(PLAYER_FAKE_INEBRIATION, oldval - GetAmount()); + + if (removeDetect) + removeDetect = !target->ToPlayer()->GetDrunkValue(); + } + + if (removeDetect) + target->m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK); + } + + // call functions which may have additional effects after chainging state of unit + target->UpdateObjectVisibility(); +} + +void AuraEffect::HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; + + Player* target = aurApp->GetTarget()->ToPlayer(); + + if (!target || !target->IsInWorld()) + return; + + uint32 overrideId = uint32(GetMiscValue()); - if (mode & AURA_EFFECT_HANDLE_REAL) + if (apply) { - // pet auras - if (PetAura const* petSpell = sSpellMgr->GetPetAura(GetId(), m_effIndex)) - { - if (apply) - target->AddPetAura(petSpell); - else - target->RemovePetAura(petSpell); - } + target->SetUInt16Value(PLAYER_FIELD_BYTES2, 0, overrideId); + if (OverrideSpellDataEntry const* overrideSpells = sOverrideSpellDataStore.LookupEntry(overrideId)) + for (uint8 i = 0; i < MAX_OVERRIDE_SPELL; ++i) + if (uint32 spellId = overrideSpells->spellId[i]) + target->AddTemporarySpell(spellId); } - - if (mode & (AURA_EFFECT_HANDLE_REAL | AURA_EFFECT_HANDLE_REAPPLY)) + else { - // AT APPLY - if (apply) - { - // Overpower - if (caster && m_spellProto->SpellFamilyName == SPELLFAMILY_WARRIOR && - m_spellProto->SpellFamilyFlags[0] & 0x4) - { - // In addition, if you strike a player.. - if (target->GetTypeId() != TYPEID_PLAYER) - return; - // ..while they are casting - if (target->IsNonMeleeSpellCasted(false, false, true, false, false)) - if (AuraEffect * aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARRIOR, 2775, 0)) - switch (aurEff->GetId()) - { - // Unrelenting Assault, rank 1 - case 46859: - target->CastSpell(target, 64849, true, NULL, aurEff); - break; - // Unrelenting Assault, rank 2 - case 46860: - target->CastSpell(target, 64850, true, NULL, aurEff); - break; - } - } - switch(GetId()) - { - case 1515: // Tame beast - // FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness - if (caster && target->CanHaveThreatList()) - target->AddThreat(caster, 10.0f); - break; - case 13139: // net-o-matic - // root to self part of (root_target->charge->root_self sequence - if (caster) - caster->CastSpell(caster, 13138, true, NULL, this); - break; - case 34026: // kill command - { - Unit* pet = target->GetGuardianPet(); - if (!pet) - break; + target->SetUInt16Value(PLAYER_FIELD_BYTES2, 0, 0); + if (OverrideSpellDataEntry const* overrideSpells = sOverrideSpellDataStore.LookupEntry(overrideId)) + for (uint8 i = 0; i < MAX_OVERRIDE_SPELL; ++i) + if (uint32 spellId = overrideSpells->spellId[i]) + target->RemoveTemporarySpell(spellId); + } +} - target->CastSpell(target, 34027, true, NULL, this); +void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const +{ + if (!(mode & AURA_EFFECT_HANDLE_REAL)) + return; - // set 3 stacks and 3 charges (to make all auras not disappear at once) - Aura * owner_aura = target->GetAura(34027, GetCasterGUID()); - Aura * pet_aura = pet->GetAura(58914, GetCasterGUID()); - if (owner_aura) - { - owner_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount); - } - if (pet_aura) - { - pet_aura->SetCharges(0); - pet_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount); - } - break; - } - case 37096: // Blood Elf Illusion - { - if (caster) - { - switch(caster->getGender()) - { - case GENDER_FEMALE: - caster->CastSpell(target, 37095, true, NULL, this); // Blood Elf Disguise - break; - case GENDER_MALE: - caster->CastSpell(target, 37093, true, NULL, this); - break; - default: - break; - } - } - break; - } - case 55198: // Tidal Force - { - target->CastSpell(target, 55166, true, NULL, this); - // set 3 stacks and 3 charges (to make all auras not disappear at once) - Aura * owner_aura = target->GetAura(55166, GetCasterGUID()); - if (owner_aura) - { - // This aura lasts 2 sec, need this hack to properly proc spells - // TODO: drop aura charges for ApplySpellMod in ProcDamageAndSpell - GetBase()->SetDuration(owner_aura->GetDuration()); - // Make aura be not charged-this prevents removing charge on not crit spells - owner_aura->SetCharges(0); - owner_aura->SetStackAmount(owner_aura->GetSpellProto()->StackAmount); - } - break; - } - case 39850: // Rocket Blast - if (roll_chance_i(20)) // backfire stun - target->CastSpell(target, 51581, true, NULL, this); - break; - case 43873: // Headless Horseman Laugh - target->PlayDistanceSound(11965); - break; - case 46354: // Blood Elf Illusion - if (caster) - { - switch(caster->getGender()) - { - case GENDER_FEMALE: - caster->CastSpell(target, 46356, true, NULL, this); - break; - case GENDER_MALE: - caster->CastSpell(target, 46355, true, NULL, this); - break; - } - } - break; - case 46361: // Reinforced Net - if (caster) - { - float currentGroundLevel = target->GetBaseMap()->GetHeight(target->GetPositionX(), target->GetPositionY(), MAX_HEIGHT); - if (target->GetPositionZ() > currentGroundLevel) - target->GetMotionMaster()->MoveFall(currentGroundLevel); - } - break; - case 46699: // Requires No Ammo - if (target->GetTypeId() == TYPEID_PLAYER) - target->ToPlayer()->RemoveAmmo(); // not use ammo and not allow use - break; - case 49028: - if (caster) - if (AuraEffect *aurEff = caster->GetAuraEffect(63330, 0)) // glyph of Dancing Rune Weapon - GetBase()->SetDuration(GetBase()->GetDuration() + aurEff->GetAmount()); - break; - case 52916: // Honor Among Thieves - if (target->GetTypeId() == TYPEID_PLAYER) - if (Unit* spellTarget = ObjectAccessor::GetUnit(*target, target->ToPlayer()->GetComboTarget())) - target->CastSpell(spellTarget, 51699, true); - break; - case 28832: // Mark of Korth'azz - case 28833: // Mark of Blaumeux - case 28834: // Mark of Rivendare - case 28835: // Mark of Zeliek - if (caster) // actually we can also use cast(this, originalcasterguid) - { - int32 damage; - switch(GetBase()->GetStackAmount()) - { - case 1: damage = 0; break; - case 2: damage = 500; break; - case 3: damage = 1000; break; - case 4: damage = 1500; break; - case 5: damage = 4000; break; - case 6: damage = 12000; break; - default:damage = 20000 + 1000 * (GetBase()->GetStackAmount() - 7); break; - } - if (damage) - caster->CastCustomSpell(28836, SPELLVALUE_BASE_POINT0, damage, target); - } - break; - case 63322: // Saronite Vapors - { - int32 mana = int32(GetAmount() * pow(2.0f, GetBase()->GetStackAmount())); // mana restore - bp * 2^stackamount - int32 damage = mana * 2; // damage - caster->CastCustomSpell(target, 63337, &mana, NULL, NULL, true); - caster->CastCustomSpell(target, 63338, &damage, NULL, NULL, true); - break; - } - case 71563: - if (Aura* newAura = target->AddAura(71564, target)) - newAura->SetStackAmount(newAura->GetSpellProto()->StackAmount); - } - } - // AT REMOVE - else - { - if ((IsQuestTameSpell(GetId())) && caster && caster->isAlive() && target->isAlive()) - { - uint32 finalSpelId = 0; - switch(GetId()) - { - case 19548: finalSpelId = 19597; break; - case 19674: finalSpelId = 19677; break; - case 19687: finalSpelId = 19676; break; - case 19688: finalSpelId = 19678; break; - case 19689: finalSpelId = 19679; break; - case 19692: finalSpelId = 19680; break; - case 19693: finalSpelId = 19684; break; - case 19694: finalSpelId = 19681; break; - case 19696: finalSpelId = 19682; break; - case 19697: finalSpelId = 19683; break; - case 19699: finalSpelId = 19685; break; - case 19700: finalSpelId = 19686; break; - case 30646: finalSpelId = 30647; break; - case 30653: finalSpelId = 30648; break; - case 30654: finalSpelId = 30652; break; - case 30099: finalSpelId = 30100; break; - case 30102: finalSpelId = 30103; break; - case 30105: finalSpelId = 30104; break; - } + Unit* target = aurApp->GetTarget(); - if (finalSpelId) - caster->CastSpell(target, finalSpelId, true, NULL, this); - } + if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) + return; - switch(m_spellProto->SpellFamilyName) - { - case SPELLFAMILY_GENERIC: - switch(GetId()) - { - case 2584: // Waiting to Resurrect - // Waiting to resurrect spell cancel, we must remove player from resurrect queue - if (target->GetTypeId() == TYPEID_PLAYER) - if (Battleground *bg = target->ToPlayer()->GetBattleground()) - bg->RemovePlayerFromResurrectQueue(target->GetGUID()); - break; - case 36730: // Flame Strike - { - target->CastSpell(target, 36731, true, NULL, this); - break; - } - case 44191: // Flame Strike - { - if (target->GetMap()->IsDungeon()) - { - uint32 spellId = target->GetMap()->IsHeroic() ? 46163 : 44190; + uint32 vehicleId = GetMiscValue(); + + if (apply) + { + if (!target->CreateVehicleKit(vehicleId, 0)) + return; + } + else if (target->GetVehicleKit()) + target->RemoveVehicleKit(); - target->CastSpell(target, spellId, true, NULL, this); - } - break; - } - case 43681: // Inactive - { - if (!target || target->GetTypeId() != TYPEID_PLAYER || aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) - return; + WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, target->GetPackGUID().size()+4); + data.appendPackGUID(target->GetGUID()); + data << uint32(apply ? vehicleId : 0); + target->SendMessageToSet(&data, true); - if (target->GetMap()->IsBattleground()) - target->ToPlayer()->LeaveBattleground(); - break; - } - case 42783: // Wrath of the Astromancer - target->CastSpell(target, GetAmount(), true, NULL, this); - break; - case 46308: // Burning Winds casted only at creatures at spawn - target->CastSpell(target, 47287, true, NULL, this); - break; - case 52172: // Coyote Spirit Despawn Aura - case 60244: // Blood Parrot Despawn Aura - target->CastSpell((Unit*)NULL, GetAmount(), true, NULL, this); - break; - case 58600: // Restricted Flight Area - if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) - target->CastSpell(target, 58601, true); - break; + if (apply) + { + data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); + target->ToPlayer()->GetSession()->SendPacket(&data); + } +} + +void AuraEffect::HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const +{ + switch (GetSpellProto()->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + switch (GetId()) + { + case 54798: // FLAMING Arrow Triggered Effect + { + if (!caster || !target || !target->ToCreature() || !caster->IsVehicle() || target->HasAura(54683)) + break; + + if (Unit* rider = caster->GetVehicleKit()->GetPassenger(0)) + { + target->CastSpell(target, 54683, true); + + // Credit Frostworgs + if (target->GetEntry() == 29358) + rider->CastSpell(rider, 54896, true); + // Credit Frost Giants + else if (target->GetEntry() == 29351) + rider->CastSpell(rider, 54893, true); } break; - case SPELLFAMILY_MAGE: - // Living Bomb - if (m_spellProto->SpellFamilyFlags[1] & 0x20000) + } + case 62292: // Blaze (Pool of Tar) + // should we use custom damage? + target->CastSpell((Unit*)NULL, m_spellProto->EffectTriggerSpell[m_effIndex], true); + break; + case 62399: // Overload Circuit + if (target->GetMap()->IsDungeon() && int(target->GetAppliedAuras().count(62399)) >= (target->GetMap()->IsHeroic() ? 4 : 2)) { - AuraRemoveMode mode = aurApp->GetRemoveMode(); - if (caster && (mode == AURA_REMOVE_BY_ENEMY_SPELL || mode == AURA_REMOVE_BY_EXPIRE)) - caster->CastSpell(target, GetAmount(), true); + target->CastSpell(target, 62475, true); // System Shutdown + if (Unit *veh = target->GetVehicleBase()) + veh->CastSpell(target, 62475, true); } break; - case SPELLFAMILY_WARLOCK: - // Haunt - if (m_spellProto->SpellFamilyFlags[1] & 0x40000) + case 64821: // Fuse Armor (Razorscale) + if (GetBase()->GetStackAmount() == GetSpellProto()->StackAmount) { - if (caster) - target->CastCustomSpell(caster, 48210, &m_amount, 0, 0, true, NULL, this, GetCasterGUID()); + target->CastSpell(target, 64774, true, NULL, NULL, GetCasterGUID()); + target->RemoveAura(64821); } break; - case SPELLFAMILY_DRUID: - // Lifebloom - if (GetSpellProto()->SpellFamilyFlags[1] & 0x10) + } + break; + case SPELLFAMILY_MAGE: + { + // Mirror Image + if (GetId() == 55342) + // Set name of summons to name of caster + target->CastSpell((Unit *)NULL, m_spellProto->EffectTriggerSpell[m_effIndex], true); + break; + } + case SPELLFAMILY_WARLOCK: + { + switch (GetSpellProto()->Id) + { + // Demonic Circle + case 48018: + if (GameObject* obj = target->GetGameObject(GetSpellProto()->Id)) { - // Final heal only on duration end - if (aurApp->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE) - return; - - // final heal - int32 stack = GetBase()->GetStackAmount(); - target->CastCustomSpell(target, 33778, &m_amount, &stack, NULL, true, NULL, this, GetCasterGUID()); - - // restore mana - if (caster) + if (target->IsWithinDist(obj, GetSpellMaxRange(48020, true))) { - int32 returnmana = CalculatePctU(caster->GetCreateMana(), GetSpellProto()->ManaCostPercentage) * stack / 2; - caster->CastCustomSpell(caster, 64372, &returnmana, NULL, NULL, true, NULL, this, GetCasterGUID()); + if (!target->HasAura(62388)) + target->CastSpell(target, 62388, true); } + else + target->RemoveAura(62388); } break; - case SPELLFAMILY_PRIEST: - // Vampiric Touch - if (m_spellProto->SpellFamilyFlags[1] & 0x0400 && aurApp->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL && GetEffIndex() == 0) + } + break; + } + case SPELLFAMILY_DRUID: + { + switch (GetSpellProto()->Id) + { + // Frenzied Regeneration + case 22842: + { + // Converts up to 10 rage per second into health for $d. Each point of rage is converted into ${$m2/10}.1% of max health. + // Should be manauser + if (target->getPowerType() != POWER_RAGE) + break; + uint32 rage = target->GetPower(POWER_RAGE); + // Nothing todo + if (rage == 0) + break; + int32 mod = (rage < 100) ? rage : 100; + int32 points = target->CalculateSpellDamage(target, GetSpellProto(), 1); + int32 regen = target->GetMaxHealth() * (mod * points / 10) / 1000; + target->CastCustomSpell(target, 22845, ®en, 0, 0, true, 0, this); + target->SetPower(POWER_RAGE, rage-mod); + break; + } + } + break; + } + case SPELLFAMILY_ROGUE: + { + switch (GetSpellProto()->Id) + { + // Master of Subtlety + case 31666: + if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) + target->RemoveAurasDueToSpell(31665); + break; + // Killing Spree + case 51690: + { + // TODO: this should use effect[1] of 51690 + UnitList targets; { - if (AuraEffect const* aurEff = GetBase()->GetEffect(1)) - { - int32 damage = aurEff->GetAmount() * 8; - // backfire damage - target->CastCustomSpell(target, 64085, &damage, NULL, NULL, true, NULL, NULL, GetCasterGUID()); - } + // eff_radius == 0 + float radius = GetSpellMaxRange(GetSpellProto(), false); + + CellPair p(Trinity::ComputeCellPair(target->GetPositionX(), target->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + + Trinity::AnyUnfriendlyVisibleUnitInObjectRangeCheck u_check(target, target, radius); + Trinity::UnitListSearcher checker(target, targets, u_check); + + TypeContainerVisitor, GridTypeMapContainer > grid_object_checker(checker); + TypeContainerVisitor, WorldTypeMapContainer > world_object_checker(checker); + + cell.Visit(p, grid_object_checker, *GetBase()->GetOwner()->GetMap(), *target, radius); + cell.Visit(p, world_object_checker, *GetBase()->GetOwner()->GetMap(), *target, radius); } + + if (targets.empty()) + return; + + UnitList::const_iterator itr = targets.begin(); + std::advance(itr, rand()%targets.size()); + Unit* spellTarget = *itr; + + target->CastSpell(spellTarget, 57840, true); + target->CastSpell(spellTarget, 57841, true); break; - case SPELLFAMILY_HUNTER: - // Misdirection - if (GetId() == 34477) - target->SetReducedThreatPercent(0, 0); - break; - case SPELLFAMILY_DEATHKNIGHT: - // Summon Gargoyle (Dismiss Gargoyle at remove) - if (GetId() == 61777) - target->CastSpell(target, GetAmount(), true); + } + // Overkill + case 58428: + if (!target->HasAuraType(SPELL_AURA_MOD_STEALTH)) + target->RemoveAurasDueToSpell(58427); break; + } + break; + } + case SPELLFAMILY_HUNTER: + { + // Explosive Shot + if (GetSpellProto()->SpellFamilyFlags[1] & 0x80000000) + { + if (caster) + caster->CastCustomSpell(53352, SPELLVALUE_BASE_POINT0, m_amount, target, true, NULL, this); + break; + } + switch (GetSpellProto()->Id) + { + // Feeding Frenzy Rank 1 + case 53511: + if (target->getVictim() && target->getVictim()->HealthBelowPct(35)) + target->CastSpell(target, 60096, true, 0, this); + return; + // Feeding Frenzy Rank 2 + case 53512: + if (target->getVictim() && target->getVictim()->HealthBelowPct(35)) + target->CastSpell(target, 60097, true, 0, this); + return; default: break; } + break; } + case SPELLFAMILY_SHAMAN: + if (GetId() == 52179) // Astral Shift + { + // Periodic need for remove visual on stun/fear/silence lost + if (!(target->GetUInt32Value(UNIT_FIELD_FLAGS)&(UNIT_FLAG_STUNNED|UNIT_FLAG_FLEEING|UNIT_FLAG_SILENCED))) + target->RemoveAurasDueToSpell(52179); + break; + } + break; + case SPELLFAMILY_DEATHKNIGHT: + switch (GetId()) + { + case 49016: // Hysteria + uint32 damage = uint32(target->CountPctFromMaxHealth(1)); + target->DealDamage(target, damage, NULL, NODAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + break; + } + // Death and Decay + if (GetSpellProto()->SpellFamilyFlags[0] & 0x20) + { + if (caster) + caster->CastCustomSpell(target, 52212, &m_amount, NULL, NULL, true, 0, this); + break; + } + // Blood of the North + // Reaping + // Death Rune Mastery + if (GetSpellProto()->SpellIconID == 3041 || GetSpellProto()->SpellIconID == 22 || GetSpellProto()->SpellIconID == 2622) + { + if (target->GetTypeId() != TYPEID_PLAYER) + return; + if (target->ToPlayer()->getClass() != CLASS_DEATH_KNIGHT) + return; + + // timer expired - remove death runes + target->ToPlayer()->RemoveRunesByAuraEffect(this); + } + break; + default: + break; } +} + +void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) const +{ + // generic casting code with custom spells and target/caster customs + uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[GetEffIndex()]; - // AT APPLY & REMOVE + SpellEntry const* triggeredSpellInfo = sSpellStore.LookupEntry(triggerSpellId); + SpellEntry const* auraSpellInfo = GetSpellProto(); + uint32 auraId = auraSpellInfo->Id; - switch(m_spellProto->SpellFamilyName) + // specific code for cases with no trigger spell provided in field + if (triggeredSpellInfo == NULL) { - case SPELLFAMILY_GENERIC: + switch (auraSpellInfo->SpellFamilyName) { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - break; - switch(GetId()) + case SPELLFAMILY_GENERIC: { - // Recently Bandaged - case 11196: - target->ApplySpellImmune(GetId(), IMMUNITY_MECHANIC, GetMiscValue(), apply); - break; - // Unstable Power - case 24658: - { - uint32 spellId = 24659; - if (apply && caster) - { - SpellEntry const* spell = sSpellStore.LookupEntry(spellId); - - for (uint32 i = 0; i < spell->StackAmount; ++i) - caster->CastSpell(target, spell->Id, true, NULL, NULL, GetCasterGUID()); - break; - } - target->RemoveAurasDueToSpell(spellId); - break; - } - // Restless Strength - case 24661: + switch (auraId) { - uint32 spellId = 24662; - if (apply && caster) - { - SpellEntry const* spell = sSpellStore.LookupEntry(spellId); - for (uint32 i = 0; i < spell->StackAmount; ++i) - caster->CastSpell(target, spell->Id, true, NULL, NULL, GetCasterGUID()); + // Thaumaturgy Channel + case 9712: + triggerSpellId = 21029; break; - } - target->RemoveAurasDueToSpell(spellId); - break; - } - // Tag Murloc - case 30877: - { - // Tag/untag Blacksilt Scout - target->SetEntry(apply ? 17654 : 17326); - break; - } - //Summon Fire Elemental - case 40133: - { - if (!caster) + // Brood Affliction: Bronze + case 23170: + triggerSpellId = 23171; break; - - Unit *owner = caster->GetOwner(); - if (owner && owner->GetTypeId() == TYPEID_PLAYER) + // Restoration + case 24379: + case 23493: { - if (apply) - owner->CastSpell(owner, 8985, true); - else - owner->ToPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); - } - break; - } - //Summon Earth Elemental - case 40132 : - { - if (!caster) - break; + if (caster) + { + int32 heal = caster->CountPctFromMaxHealth(10); + caster->HealBySpell(target, auraSpellInfo, heal); - Unit *owner = caster->GetOwner(); - if (owner && owner->GetTypeId() == TYPEID_PLAYER) - { - if (apply) - owner->CastSpell(owner, 19704, true); - else - owner->ToPlayer()->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); - } - break; - } - case 57723: // Exhaustion - case 57724: // Sated - { - switch(GetId()) - { - case 57723: target->ApplySpellImmune(GetId(), IMMUNITY_ID, 32182, apply); break; // Heroism - case 57724: target->ApplySpellImmune(GetId(), IMMUNITY_ID, 2825, apply); break; // Bloodlust + if (int32 mana = caster->GetMaxPower(POWER_MANA)) + { + mana /= 10; + caster->EnergizeBySpell(caster, 23493, mana, POWER_MANA); + } + } + return; } - break; - } - case 57819: // Argent Champion - case 57820: // Ebon Champion - case 57821: // Champion of the Kirin Tor - case 57822: // Wyrmrest Champion - { - if (!caster || caster->GetTypeId() != TYPEID_PLAYER) + // Nitrous Boost + case 27746: + if (caster && target->GetPower(POWER_MANA) >= 10) + { + target->ModifyPower(POWER_MANA, -10); + target->SendEnergizeSpellLog(caster, 27746, 10, POWER_MANA); + } + else + target->RemoveAurasDueToSpell(27746); + return; + // Frost Blast + case 27808: + if (caster) + caster->CastCustomSpell(29879, SPELLVALUE_BASE_POINT0, int32(target->CountPctFromMaxHealth(21)), target, true, NULL, this); + return; + // Detonate Mana + case 27819: + if (int32 mana = (int32)(target->GetMaxPower(POWER_MANA) / 10)) + { + mana = target->ModifyPower(POWER_MANA, -mana); + target->CastCustomSpell(27820, SPELLVALUE_BASE_POINT0, -mana*10, target, true, NULL, this); + } + return; + // Inoculate Nestlewood Owlkin + case 29528: + if (target->GetTypeId() != TYPEID_UNIT) // prevent error reports in case ignored player target + return; break; - - uint32 FactionID = 0; - - if (apply) + // Feed Captured Animal + case 29917: + triggerSpellId = 29916; + break; + // Extract Gas + case 30427: { - switch(m_spellProto->Id) + // move loot to player inventory and despawn target + if (caster && caster->GetTypeId() == TYPEID_PLAYER && + target->GetTypeId() == TYPEID_UNIT && + target->ToCreature()->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD) { - case 57819: FactionID = 1106; break; // Argent Crusade - case 57820: FactionID = 1098; break; // Knights of the Ebon Blade - case 57821: FactionID = 1090; break; // Kirin Tor - case 57822: FactionID = 1091; break; // The Wyrmrest Accord + Player* player = caster->ToPlayer(); + Creature* creature = target->ToCreature(); + // missing lootid has been reported on startup - just return + if (!creature->GetCreatureInfo()->SkinLootId) + return; + + player->AutoStoreLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, true); + + creature->DespawnOrUnsummon(); } + return; } - caster->ToPlayer()->SetChampioningFaction(FactionID); - break; - } - // LK Intro VO (1) - case 58204: - if (target->GetTypeId() == TYPEID_PLAYER) + // Quake + case 30576: + triggerSpellId = 30571; + break; + // Doom + // TODO: effect trigger spell may be independant on spell targets, and executed in spell finish phase + // so instakill will be naturally done before trigger spell + case 31347: { - // Play part 1 - if (apply) - target->PlayDirectSound(14970, target->ToPlayer()); - // continue in 58205 - else - target->CastSpell(target, 58205, true); + target->CastSpell(target, 31350, true, NULL, this); + target->Kill(target); + return; } - break; - // LK Intro VO (2) - case 58205: - if (target->GetTypeId() == TYPEID_PLAYER) + // Spellcloth + case 31373: { - // Play part 2 - if (apply) - target->PlayDirectSound(14971, target->ToPlayer()); - // Play part 3 - else - target->PlayDirectSound(14972, target->ToPlayer()); + // Summon Elemental after create item + target->SummonCreature(17870, 0, 0, 0, target->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0); + return; } - break; - case 62061: // Festive Holiday Mount - if (target->HasAuraType(SPELL_AURA_MOUNTED)) + // Flame Quills + case 34229: { - uint32 creatureEntry = 0; - if (apply) - { - if (target->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED)) - creatureEntry = 24906; - else - creatureEntry = 15665; - } - else - creatureEntry = target->GetAuraEffectsByType(SPELL_AURA_MOUNTED).front()->GetMiscValue(); - - if (CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry)) - { - uint32 team = 0; - if (target->GetTypeId() == TYPEID_PLAYER) - team = target->ToPlayer()->GetTeam(); - - uint32 displayID = sObjectMgr->ChooseDisplayId(team, creatureInfo); - sObjectMgr->GetCreatureModelRandomGender(&displayID); - - target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID, displayID); - } + // cast 24 spells 34269-34289, 34314-34316 + for (uint32 spell_id = 34269; spell_id != 34290; ++spell_id) + target->CastSpell(target, spell_id, true, NULL, this); + for (uint32 spell_id = 34314; spell_id != 34317; ++spell_id) + target->CastSpell(target, spell_id, true, NULL, this); + return; } - break; - } - - break; - } - case SPELLFAMILY_MAGE: - { - //if (!(mode & AURA_EFFECT_HANDLE_REAL)) - //break; - break; - } - case SPELLFAMILY_PRIEST: - { - //if (!(mode & AURA_EFFECT_HANDLE_REAL)) - //break; - break; - } - case SPELLFAMILY_DRUID: - { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) - break; - switch(GetId()) - { - case 52610: // Savage Roar - { - uint32 spellId = 62071; - if (apply) + // Remote Toy + case 37027: triggerSpellId = 37029; break; + // Eye of Grillok + case 38495: { - if (target->GetShapeshiftForm() != FORM_CAT) - break; + target->CastSpell(target, 38530, true, NULL, this); + return; + } + // Absorb Eye of Grillok (Zezzak's Shard) + case 38554: + { + if (!caster || target->GetTypeId() != TYPEID_UNIT) + return; - target->CastSpell(target, spellId, true, NULL, NULL, GetCasterGUID()); - break; + caster->CastSpell(caster, 38495, true, NULL, this); + + Creature* creatureTarget = target->ToCreature(); + + creatureTarget->DespawnOrUnsummon(); + return; } - target->RemoveAurasDueToSpell(spellId); - break; + // Tear of Azzinoth Summon Channel - it's not really supposed to do anything, and this only prevents the console spam + case 39857: + triggerSpellId = 39856; + break; + // Personalized Weather + case 46736: + triggerSpellId = 46737; + break; } - case 61336: // Survival Instincts + break; + } + case SPELLFAMILY_SHAMAN: + { + switch(auraId) { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - break; - - if (apply) + // Lightning Shield (The Earthshatterer set trigger after cast Lighting Shield) + case 28820: { - if (!target->IsInFeralForm()) - break; + // Need remove self if Lightning Shield not active + if (!target->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, 0x400)) + target->RemoveAurasDueToSpell(28820); + return; + } + // Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus) + case 38443: + { + bool all = true; + for (int i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) + { + if (!target->m_SummonSlot[i]) + { + all = false; + break; + } + } - int32 bp0 = int32(target->CountPctFromMaxHealth(GetAmount())); - target->CastCustomSpell(target, 50322, &bp0, NULL, NULL, true); + if (all) + target->CastSpell(target, 38437, true, NULL, this); + else + target->RemoveAurasDueToSpell(38437); + return; } - else - target-> RemoveAurasDueToSpell(50322); - break; } + break; } - // Predatory Strikes - if (target->GetTypeId() == TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563) - { - target->ToPlayer()->UpdateAttackPowerAndDamage(); - } - break; + default: + break; } - case SPELLFAMILY_SHAMAN: + } + else + { + // Spell exist but require custom code + switch (auraId) { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - break; - // Sentry Totem - if (GetId() == 6495 && caster->GetTypeId() == TYPEID_PLAYER) - { - if (apply) + // Pursuing Spikes (Anub'arak) + case 65920: + case 65922: + case 65923: { - uint64 guid = caster->m_SummonSlot[3]; - if (guid) + Unit* permafrostCaster = NULL; + Aura* permafrostAura = NULL; + if (permafrostAura = target->GetAura(66193)) + permafrostCaster = permafrostAura->GetCaster(); + else if (permafrostAura = target->GetAura(67855)) + permafrostCaster = permafrostAura->GetCaster(); + else if (permafrostAura = target->GetAura(67856)) + permafrostCaster = permafrostAura->GetCaster(); + else if (permafrostAura = target->GetAura(67857)) + permafrostCaster = permafrostAura->GetCaster(); + + if (permafrostCaster) { - Creature *totem = caster->GetMap()->GetCreature(guid); - if (totem && totem->isTotem()) - caster->ToPlayer()->CastSpell(totem, 6277, true); + if (Creature* permafrostCasterCreature = permafrostCaster->ToCreature()) + permafrostCasterCreature->DespawnOrUnsummon(3000); + + target->CastSpell(target, 66181, false); + target->RemoveAllAuras(); + if (Creature* targetCreature = target->ToCreature()) + targetCreature->DisappearAndDie(); } } - else - caster->ToPlayer()->StopCastingBindSight(); + break; + // Mana Tide + case 16191: + target->CastCustomSpell(target, triggerSpellId, &m_amount, NULL, NULL, true, NULL, this); + return; + // Negative Energy Periodic + case 46284: + target->CastCustomSpell(triggerSpellId, SPELLVALUE_MAX_TARGETS, m_tickNumber / 10 + 1, NULL, true, NULL, this); + return; + // Poison (Grobbulus) + case 28158: + case 54362: + // Slime Pool (Dreadscale & Acidmaw) + case 66882: + target->CastCustomSpell(triggerSpellId, SPELLVALUE_RADIUS_MOD, (int32)((((float)m_tickNumber / 60) * 0.9f + 0.1f) * 10000 * 2 / 3), NULL, true, NULL, this); + return; + // Beacon of Light + case 53563: + { + // area aura owner casts the spell + GetBase()->GetUnitOwner()->CastSpell(target, triggeredSpellInfo, true, 0, this, GetBase()->GetUnitOwner()->GetGUID()); + return; + } + // Slime Spray - temporary here until preventing default effect works again + // added on 9.10.2010 + case 69508: + { + if (caster) + caster->CastSpell(target, triggerSpellId, true, NULL, NULL, caster->GetGUID()); return; } - break; } - case SPELLFAMILY_PALADIN: - // if (!(mode & AURA_EFFECT_HANDLE_REAL)) - // break; - break; + } + + // Reget trigger spell proto + if (triggeredSpellInfo = sSpellStore.LookupEntry(triggerSpellId)) + { + if (Unit* triggerCaster = GetTriggeredSpellCaster(triggeredSpellInfo, caster, target)) + { + triggerCaster->CastSpell(target, triggeredSpellInfo, true, NULL, this); + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell %u Trigger %u", GetId(), triggeredSpellInfo->Id); + } + } + else + { + Creature* c = target->ToCreature(); + if (!c || (c && !sScriptMgr->OnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex()), target->ToCreature())) || + (c && !c->AI()->sOnDummyEffect(caster, GetId(), SpellEffIndex(GetEffIndex())))) + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandlePeriodicTriggerSpellAuraTick: Spell %u has non-existent spell %u in EffectTriggered[%d] and is therefor not triggered.", GetId(), triggerSpellId, GetEffIndex()); } } -void AuraEffect::HandleChannelDeathItem(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick(Unit* target, Unit* caster) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - return; - - if (!apply) + uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[m_effIndex]; + if (SpellEntry const *triggeredSpellInfo = sSpellStore.LookupEntry(triggerSpellId)) { - Unit* caster = GetCaster(); - - if (!caster || caster->GetTypeId() != TYPEID_PLAYER) - return; - - Player *plCaster = caster->ToPlayer(); - Unit* target = aurApp->GetTarget(); + if (Unit* triggerCaster = GetTriggeredSpellCaster(triggeredSpellInfo, caster, target)) + { + int32 basepoints0 = GetAmount(); + triggerCaster->CastCustomSpell(target, triggerSpellId, &basepoints0, 0, 0, true, 0, this); + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick: Spell %u Trigger %u", GetId(), triggeredSpellInfo->Id); + } + } + else + sLog->outDebug(LOG_FILTER_SPELLS_AURAS,"AuraEffect::HandlePeriodicTriggerSpellWithValueAuraTick: Spell %u has non-existent spell %u in EffectTriggered[%d] and is therefor not triggered.", GetId(), triggerSpellId, GetEffIndex()); +} - if (target->getDeathState() != JUST_DIED) - return; +void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const +{ + if (!caster || !target->isAlive()) + return; - // Item amount - if (GetAmount() <= 0) - return; + if (target->HasUnitState(UNIT_STAT_ISOLATED) || target->IsImmunedToDamage(GetSpellProto())) + { + SendTickImmune(target, caster); + return; + } - if (GetSpellProto()->EffectItemType[m_effIndex] == 0) - return; + // Consecrate ticks can miss and will not show up in the combat log + if (GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA && + caster->SpellHitResult(target, GetSpellProto(), false) != SPELL_MISS_NONE) + return; - // Soul Shard - if (GetSpellProto()->EffectItemType[m_effIndex] == 6265) + // some auras remove at specific health level or more + if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) + { + switch (GetId()) { - // Soul Shard only from units that grant XP or honor - if (!plCaster->isHonorOrXPTarget(target) || - (target->GetTypeId() == TYPEID_UNIT && !target->ToCreature()->isTappedBy(plCaster))) - return; - - // If this is Drain Soul, check for Glyph of Drain Soul - if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags[0] & 0x00004000)) + case 43093: case 31956: case 38801: // Grievous Wound + case 35321: case 38363: case 39215: // Gushing Wound + if (target->IsFullHealth()) + { + target->RemoveAurasDueToSpell(GetId()); + return; + } + break; + case 38772: // Grievous Wound { - // Glyph of Drain Soul - chance to create an additional Soul Shard - if (AuraEffect *aur = caster->GetAuraEffect(58070, 0)) - if (roll_chance_i(aur->GetMiscValue())) - caster->CastSpell(caster, 58068, true, 0, aur); // We _could_ simply do ++count here, but Blizz does it this way :) + uint32 percent = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), 1, caster); + if (!target->HealthBelowPct(percent)) + { + target->RemoveAurasDueToSpell(GetId()); + return; + } + break; } } + } - //Adding items - uint32 noSpaceForCount = 0; - uint32 count = m_amount; + uint32 absorb = 0; + uint32 resist = 0; + CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); - ItemPosCountVec dest; - InventoryResult msg = plCaster->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, GetSpellProto()->EffectItemType[m_effIndex], count, &noSpaceForCount); - if (msg != EQUIP_ERR_OK) + // ignore non positive values (can be result apply spellmods to aura damage + uint32 damage = std::max(GetAmount(), 0); + + if (GetAuraType() == SPELL_AURA_PERIODIC_DAMAGE) + { + damage = caster->SpellDamageBonus(target, GetSpellProto(), damage, DOT, GetBase()->GetStackAmount()); + + // Calculate armor mitigation + if (Unit::IsDamageReducedByArmor(GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), m_effIndex)) { - count-=noSpaceForCount; - plCaster->SendEquipError(msg, NULL, NULL, GetSpellProto()->EffectItemType[m_effIndex]); - if (count == 0) - return; + uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellProto()); + cleanDamage.mitigated_damage += damage - damageReductedArmor; + damage = damageReductedArmor; } - Item* newitem = plCaster->StoreNewItem(dest, GetSpellProto()->EffectItemType[m_effIndex], true); - if (!newitem) + // Curse of Agony damage-per-tick calculation + if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags[0] & 0x400) && GetSpellProto()->SpellIconID == 544) { - plCaster->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL); - return; + uint32 totalTick = GetTotalTicks(); + // 1..4 ticks, 1/2 from normal tick damage + if (m_tickNumber <= totalTick / 3) + damage = damage/2; + // 9..12 ticks, 3/2 from normal tick damage + else if (m_tickNumber > totalTick * 2 / 3) + damage += (damage+1)/2; // +1 prevent 0.5 damage possible lost at 1..4 ticks + // 5..8 ticks have normal tick damage + } + // There is a Chance to make a Soul Shard when Drain soul does damage + if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags[0] & 0x00004000)) + { + if (caster->GetTypeId() == TYPEID_PLAYER && caster->ToPlayer()->isHonorOrXPTarget(target)) + { + if (roll_chance_i(20)) + { + caster->CastSpell(caster, 43836, true, 0, this); + // Glyph of Drain Soul - chance to create an additional Soul Shard + if (AuraEffect *aur = caster->GetAuraEffect(58070, 0)) + if (roll_chance_i(aur->GetMiscValue())) + caster->CastSpell(caster, 58068, true, 0, aur); + } + } + } + if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_GENERIC) + { + switch (GetId()) + { + case 70911: // Unbound Plague + case 72854: // Unbound Plague + case 72855: // Unbound Plague + case 72856: // Unbound Plague + damage *= uint32(pow(1.25f, int32(m_tickNumber))); + break; + default: + break; + } } - plCaster->SendNewItem(newitem, count, true, true); } + else + damage = uint32(target->CountPctFromMaxHealth(damage)); + + bool crit = IsPeriodicTickCrit(target, caster); + if (crit) + damage = caster->SpellCriticalDamageBonus(m_spellProto, damage, target); + + int32 dmg = damage; + caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL); + damage = dmg; + + caster->CalcAbsorbResist(target, GetSpellSchoolMask(GetSpellProto()), DOT, damage, &absorb, &resist, m_spellProto); + + sLog->outDetail("PeriodicTick: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u", + GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), damage, GetId(), absorb); + + caster->DealDamageMods(target, damage, &absorb); + + // Set trigger flag + uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; + uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; + uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT; + damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist); + if (damage) + procVictim |= PROC_FLAG_TAKEN_DAMAGE; + + int32 overkill = damage - target->GetHealth(); + if (overkill < 0) + overkill = 0; + + SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit); + target->SendPeriodicAuraLog(&pInfo); + + caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellProto()); + + caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); } -void AuraEffect::HandleBindSight(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - return; +void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const +{ + if (!caster || !caster->isAlive() || !target->isAlive()) + return; + + if (target->HasUnitState(UNIT_STAT_ISOLATED) || target->IsImmunedToDamage(GetSpellProto())) + { + SendTickImmune(target, caster); + return; + } + + if (GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA && + caster->SpellHitResult(target, GetSpellProto(), false) != SPELL_MISS_NONE) + return; + + uint32 absorb = 0; + uint32 resist = 0; + CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); + + uint32 damage = std::max(GetAmount(), 0); + damage = caster->SpellDamageBonus(target, GetSpellProto(), damage, DOT, GetBase()->GetStackAmount()); + + bool crit = IsPeriodicTickCrit(target, caster); + if (crit) + damage = caster->SpellCriticalDamageBonus(m_spellProto, damage, target); + + // Calculate armor mitigation + if (Unit::IsDamageReducedByArmor(GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), m_effIndex)) + { + uint32 damageReductedArmor = caster->CalcArmorReducedDamage(target, damage, GetSpellProto()); + cleanDamage.mitigated_damage += damage - damageReductedArmor; + damage = damageReductedArmor; + } + + int32 dmg = damage; + caster->ApplyResilience(target, NULL, &dmg, crit, CR_CRIT_TAKEN_SPELL); + damage = dmg; - Unit* target = aurApp->GetTarget(); + caster->CalcAbsorbResist(target, GetSpellSchoolMask(GetSpellProto()), DOT, damage, &absorb, &resist, m_spellProto); - Unit* caster = GetCaster(); + if (target->GetHealth() < damage) + damage = uint32(target->GetHealth()); - if (!caster || caster->GetTypeId() != TYPEID_PLAYER) - return; + sLog->outDetail("PeriodicTick: %u (TypeId: %u) health leech of %u (TypeId: %u) for %u dmg inflicted by %u abs is %u", + GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), damage, GetId(), absorb); - caster->ToPlayer()->SetViewpoint(target, apply); + caster->SendSpellNonMeleeDamageLog(target, GetId(), damage, GetSpellSchoolMask(GetSpellProto()), absorb, resist, false, 0, crit); + + // Set trigger flag + uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; + uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; + uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_DOT; + damage = (damage <= absorb+resist) ? 0 : (damage-absorb-resist); + if (damage) + procVictim |= PROC_FLAG_TAKEN_DAMAGE; + caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellProto()); + int32 new_damage = caster->DealDamage(target, damage, &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), false); + + float gainMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(GetSpellProto(), GetEffIndex(), caster); + + uint32 heal = uint32(caster->SpellHealingBonus(caster, GetSpellProto(), uint32(new_damage * gainMultiplier), DOT, GetBase()->GetStackAmount())); + + int32 gain = caster->HealBySpell(caster, GetSpellProto(), heal); + caster->getHostileRefManager().threatAssist(caster, gain * 0.5f, GetSpellProto()); } -void AuraEffect::HandleForceReaction(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) + if (!caster || !caster->isAlive() || !target->isAlive()) return; - Unit* target = aurApp->GetTarget(); + if (target->HasUnitState(UNIT_STAT_ISOLATED)) + { + SendTickImmune(target, caster); + return; + } - if (target->GetTypeId() != TYPEID_PLAYER) + uint32 damage = std::max(GetAmount(), 0); + // do not kill health donator + if (caster->GetHealth() < damage) + damage = caster->GetHealth() - 1; + if (!damage) return; - Player* player = (Player*)target; + caster->ModifyHealth(-(int32)damage); + sLog->outDebug(LOG_FILTER_SPELLS_AURAS, "PeriodicTick: donator %u target %u damage %u.", caster->GetEntry(), target->GetEntry(), damage); - uint32 faction_id = GetMiscValue(); - ReputationRank faction_rank = ReputationRank(m_amount); + float gainMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(GetSpellProto(), GetEffIndex(), caster); - player->GetReputationMgr().ApplyForceReaction(faction_id, faction_rank, apply); - player->GetReputationMgr().SendForceReactions(); + damage = int32(damage * gainMultiplier); - // stop fighting if at apply forced rank friendly or at remove real rank friendly - if ((apply && faction_rank >= REP_FRIENDLY) || (!apply && player->GetReputationRank(faction_id) >= REP_FRIENDLY)) - player->StopAttackFaction(faction_id); + caster->HealBySpell(target, GetSpellProto(), damage); } -void AuraEffect::HandleAuraEmpathy(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - return; - - Unit* target = aurApp->GetTarget(); - - if (target->GetTypeId() != TYPEID_UNIT) + if (!caster || !target->isAlive()) return; - if (!apply) + if (target->HasUnitState(UNIT_STAT_ISOLATED)) { - // do not remove unit flag if there are more than this auraEffect of that kind on unit on unit - if (target->HasAuraType(GetAuraType())) - return; + SendTickImmune(target, caster); + return; } - CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->GetEntry()); - if (ci && ci->type == CREATURE_TYPE_BEAST) - target->ApplyModUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_SPECIALINFO, apply); -} + // heal for caster damage (must be alive) + if (target != caster && GetSpellProto()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL && !caster->isAlive()) + return; -void AuraEffect::HandleAuraModFaction(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + // don't regen when permanent aura target has full power + if (GetBase()->IsPermanent() && target->IsFullHealth()) return; - Unit* target = aurApp->GetTarget(); + // ignore negative values (can be result apply spellmods to aura damage + int32 damage = std::max(m_amount, 0); - if (apply) + if (GetAuraType() == SPELL_AURA_OBS_MOD_HEALTH) { - target->setFaction(GetMiscValue()); - if (target->GetTypeId() == TYPEID_PLAYER) - target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + // Taken mods + float TakenTotalMod = 1.0f; + + // Tenacity increase healing % taken + if (AuraEffect const* Tenacity = target->GetAuraEffect(58549, 0)) + AddPctN(TakenTotalMod, Tenacity->GetAmount()); + + // Healing taken percent + float minval = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT); + if (minval) + AddPctF(TakenTotalMod, minval); + + float maxval = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HEALING_PCT); + if (maxval) + AddPctF(TakenTotalMod, maxval); + + // Healing over time taken percent + float minval_hot = (float)target->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT); + if (minval_hot) + AddPctF(TakenTotalMod, minval_hot); + + float maxval_hot = (float)target->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT); + if (maxval_hot) + AddPctF(TakenTotalMod, maxval_hot); + + TakenTotalMod = std::max(TakenTotalMod, 0.0f); + + damage = uint32(target->CountPctFromMaxHealth(damage)); + damage = uint32(damage * TakenTotalMod); } else { - target->RestoreFaction(); - if (target->GetTypeId() == TYPEID_PLAYER) - target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + // Wild Growth = amount + (6 - 2*doneTicks) * ticks* amount / 100 + if (m_spellProto->SpellFamilyName == SPELLFAMILY_DRUID && m_spellProto->SpellIconID == 2864) + { + int32 addition = int32(float(damage * GetTotalTicks()) * ((6-float(2*(GetTickNumber()-1)))/100)); + + // Item - Druid T10 Restoration 2P Bonus + if (AuraEffect* aurEff = caster->GetAuraEffect(70658, 0)) + // divided by 50 instead of 100 because calculated as for every 2 tick + addition += abs(int32((addition * aurEff->GetAmount()) / 50)); + + damage += addition; + } + + damage = caster->SpellHealingBonus(target, GetSpellProto(), damage, DOT, GetBase()->GetStackAmount()); } -} -void AuraEffect::HandleComprehendLanguage(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_SEND_FOR_CLIENT_MASK)) - return; + bool crit = IsPeriodicTickCrit(target, caster); + if (crit) + damage = caster->SpellCriticalHealingBonus(m_spellProto, damage, target); - Unit* target = aurApp->GetTarget(); + sLog->outDetail("PeriodicTick: %u (TypeId: %u) heal of %u (TypeId: %u) for %u health inflicted by %u", + GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), damage, GetId()); - if (apply) - target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG); - else + uint32 absorb = 0; + uint32 heal = uint32(damage); + caster->CalcHealAbsorb(target, GetSpellProto(), heal, absorb); + int32 gain = caster->DealHeal(target, heal); + + SpellPeriodicAuraLogInfo pInfo(this, damage, damage - gain, absorb, 0, 0.0f, crit); + target->SendPeriodicAuraLog(&pInfo); + + target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellProto()); + + bool haveCastItem = GetBase()->GetCastItemGUID() != 0; + + // Health Funnel + // damage caster for heal amount + if (target != caster && GetSpellProto()->AttributesEx2 & SPELL_ATTR2_HEALTH_FUNNEL) { - if (target->HasAuraType(GetAuraType())) - return; + uint32 damage = SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), 0); // damage is not affected by spell power + if ((int32)damage > gain) + damage = gain; + uint32 absorb = 0; + caster->DealDamageMods(caster, damage, &absorb); + caster->SendSpellNonMeleeDamageLog(caster, GetId(), damage, GetSpellSchoolMask(GetSpellProto()), absorb, 0, false, 0, false); - target->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_COMPREHEND_LANG); + CleanDamage cleanDamage = CleanDamage(0, 0, BASE_ATTACK, MELEE_HIT_NORMAL); + caster->DealDamage(caster, damage, &cleanDamage, NODAMAGE, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); } + + uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; + uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; + uint32 procEx = (crit ? PROC_EX_CRITICAL_HIT : PROC_EX_NORMAL_HIT) | PROC_EX_INTERNAL_HOT; + // ignore item heals + if (!haveCastItem) + caster->ProcDamageAndSpell(target, procAttacker, procVictim, procEx, damage, BASE_ATTACK, GetSpellProto()); } -void AuraEffect::HandleAuraConvertRune(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - return; - - Unit* target = aurApp->GetTarget(); + Powers powerType = Powers(GetMiscValue()); - if (target->GetTypeId() != TYPEID_PLAYER) + if (!caster || !caster->isAlive() || !target->isAlive() || target->getPowerType() != powerType) return; - Player *plr = (Player*)target; + if (target->HasUnitState(UNIT_STAT_ISOLATED) || target->IsImmunedToDamage(GetSpellProto())) + { + SendTickImmune(target, caster); + return; + } - if (plr->getClass() != CLASS_DEATH_KNIGHT) + if (GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA && + caster->SpellHitResult(target, GetSpellProto(), false) != SPELL_MISS_NONE) return; - uint32 runes = m_amount; - // convert number of runes specified in aura amount of rune type in miscvalue to runetype in miscvalueb - if (apply) + // ignore negative values (can be result apply spellmods to aura damage + int32 drainAmount = std::max(m_amount, 0); + + // Special case: draining x% of mana (up to a maximum of 2*x% of the caster's maximum mana) + // It's mana percent cost spells, m_amount is percent drain from target + if (m_spellProto->ManaCostPercentage) { - for (uint32 i = 0; i < MAX_RUNES && runes; ++i) - { - if (GetMiscValue() != plr->GetCurrentRune(i)) - continue; - if (!plr->GetRuneCooldown(i)) - { - plr->AddRuneByAuraEffect(i, RuneType(GetMiscValueB()), this); - --runes; - } - } + // max value + int32 maxmana = CalculatePctF(caster->GetMaxPower(powerType), drainAmount * 2.0f); + ApplyPctU(drainAmount, target->GetMaxPower(powerType)); + if (drainAmount > maxmana) + drainAmount = maxmana; } - else - plr->RemoveRunesByAuraEffect(this); -} -void AuraEffect::HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - Unit* target = aurApp->GetTarget(); + sLog->outDetail("PeriodicTick: %u (TypeId: %u) power leech of %u (TypeId: %u) for %u dmg inflicted by %u", + GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), drainAmount, GetId()); - uint32 triggeredSpellId = m_spellProto->EffectTriggerSpell[m_effIndex]; + // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) + if (powerType == POWER_MANA) + drainAmount -= target->GetSpellCritDamageReduction(drainAmount); - if (mode & AURA_EFFECT_HANDLE_REAL) + int32 drainedAmount = target->ModifyPower(powerType, -drainAmount); + + float gainMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(GetSpellProto(), GetEffIndex(), caster); + + SpellPeriodicAuraLogInfo pInfo(this, drainedAmount, 0, 0, 0, gainMultiplier, false); + target->SendPeriodicAuraLog(&pInfo); + + int32 gainAmount = int32(drainedAmount * gainMultiplier); + int32 gainedAmount = caster->ModifyPower(powerType, gainAmount); + + target->AddThreat(caster, float(gainedAmount) * 0.5f, GetSpellSchoolMask(GetSpellProto()), GetSpellProto()); + + // spell-specific code + switch(GetId()) { - if (apply) + case 31447: // Mark of Kaz'rogal + if (target->GetPower(powerType) == 0) + { + target->CastSpell(target, 31463, true, 0, this); + // Remove aura + GetBase()->SetDuration(0); + } + break; + case 32960: // Mark of Kazzak { - Unit* caster = GetTriggeredSpellCaster(m_spellProto, GetCaster(), target); + int32 modifier = int32(target->GetPower(powerType) * 0.05f); + target->ModifyPower(powerType, -modifier); - if (!caster) - return; - // If amount avalible cast with basepoints (Crypt Fever for example) - if (GetAmount()) - caster->CastCustomSpell(target, triggeredSpellId, &m_amount, NULL, NULL, true, NULL, this); - else - caster->CastSpell(target, triggeredSpellId, true, NULL, this); - } - else - { - uint64 casterGUID = IsSpellRequiringFocusedTarget(GetSpellProto()) ? GetCasterGUID() : target->GetGUID(); - target->RemoveAura(triggeredSpellId, casterGUID, 0, aurApp->GetRemoveMode()); + if (target->GetPower(powerType) == 0) + { + target->CastSpell(target, 32961, true, 0, this); + // Remove aura + GetBase()->SetDuration(0); + } + break; } + default: + break; } - else if (mode & AURA_EFFECT_HANDLE_REAPPLY && apply) + // Drain Mana + if (m_spellProto->SpellFamilyName == SPELLFAMILY_WARLOCK + && m_spellProto->SpellFamilyFlags[0] & 0x00000010) { - uint64 casterGUID = IsSpellRequiringFocusedTarget(GetSpellProto()) ? GetCasterGUID() : target->GetGUID(); - - // change the stack amount to be equal to stack amount of our aura - if (Aura* triggeredAura = target->GetAura(triggeredSpellId, casterGUID)) - triggeredAura->ModStackAmount(GetBase()->GetStackAmount() - triggeredAura->GetStackAmount()); + int32 manaFeedVal = 0; + if (AuraEffect const* aurEff = GetBase()->GetEffect(1)) + manaFeedVal = aurEff->GetAmount(); + // Mana Feed - Drain Mana + if (manaFeedVal > 0) + { + int32 feedAmount = CalculatePctN(gainedAmount, manaFeedVal); + caster->CastCustomSpell(caster, 32554, &feedAmount, NULL, NULL, true, NULL, this); + } } } -void AuraEffect::HandleAuraOpenStable(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandleObsModPowerAuraTick(Unit* target, Unit* caster) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) + Powers powerType; + if (GetMiscValue() == POWER_ALL) + powerType = target->getPowerType(); + else + powerType = Powers(GetMiscValue()); + + if (!target->isAlive() || target->GetMaxPower(powerType) == 0) return; - Unit* target = aurApp->GetTarget(); + if (target->HasUnitState(UNIT_STAT_ISOLATED)) + { + SendTickImmune(target, caster); + return; + } - if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) + // don't regen when permanent aura target has full power + if (GetBase()->IsPermanent() && target->GetPower(powerType) == target->GetMaxPower(powerType)) return; - if (apply) - target->ToPlayer()->GetSession()->SendStablePet(target->GetGUID()); + // ignore negative values (can be result apply spellmods to aura damage + uint32 amount = std::max(m_amount, 0) * target->GetMaxPower(powerType) /100; + sLog->outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u", + GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), amount, GetId()); - // client auto close stable dialog at !apply aura + SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false); + target->SendPeriodicAuraLog(&pInfo); + + int32 gain = target->ModifyPower(powerType, amount); + + if (caster) + target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellProto()); } -void AuraEffect::HandleAuraModFakeInebriation(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) const { - if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK)) - return; + Powers powerType = Powers(GetMiscValue()); - Unit* target = aurApp->GetTarget(); + if (!target->isAlive() || target->GetMaxPower(powerType) == 0) + return; - if (apply) + if (target->HasUnitState(UNIT_STAT_ISOLATED)) { - target->m_invisibilityDetect.AddFlag(INVISIBILITY_DRUNK); - target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, GetAmount()); - - if (target->GetTypeId() == TYPEID_PLAYER) - { - int32 oldval = target->ToPlayer()->GetInt32Value(PLAYER_FAKE_INEBRIATION); - target->ToPlayer()->SetInt32Value(PLAYER_FAKE_INEBRIATION, oldval + GetAmount()); - } + SendTickImmune(target, caster); + return; } - else - { - bool removeDetect = !target->HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE); - target->m_invisibilityDetect.AddValue(INVISIBILITY_DRUNK, -GetAmount()); + // don't regen when permanent aura target has full power + if (GetBase()->IsPermanent() && target->GetPower(powerType) == target->GetMaxPower(powerType)) + return; - if (target->GetTypeId() == TYPEID_PLAYER) - { - int32 oldval = target->ToPlayer()->GetInt32Value(PLAYER_FAKE_INEBRIATION); - target->ToPlayer()->SetInt32Value(PLAYER_FAKE_INEBRIATION, oldval - GetAmount()); + // ignore negative values (can be result apply spellmods to aura damage + int32 amount = std::max(m_amount, 0); - if (removeDetect) - removeDetect = !target->ToPlayer()->GetDrunkValue(); - } + SpellPeriodicAuraLogInfo pInfo(this, amount, 0, 0, 0, 0.0f, false); + target->SendPeriodicAuraLog(&pInfo); - if (removeDetect) - target->m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK); - } + sLog->outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u", + GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), target->GetGUIDLow(), target->GetTypeId(), amount, GetId()); - // call functions which may have additional effects after chainging state of unit - target->UpdateObjectVisibility(); + int32 gain = target->ModifyPower(powerType, amount); + + if (caster) + target->getHostileRefManager().threatAssist(caster, float(gain) * 0.5f, GetSpellProto()); } -void AuraEffect::HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 mode, bool apply) const +void AuraEffect::HandlePeriodicPowerBurnManaAuraTick(Unit* target, Unit* caster) const { - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - return; - - Player* target = aurApp->GetTarget()->ToPlayer(); + Powers powerType = Powers(GetMiscValue()); - if (!target || !target->IsInWorld()) + if (!caster || !target->isAlive() || target->getPowerType() != powerType) return; - uint32 overrideId = uint32(GetMiscValue()); - - if (apply) - { - target->SetUInt16Value(PLAYER_FIELD_BYTES2, 0, overrideId); - if (OverrideSpellDataEntry const* overrideSpells = sOverrideSpellDataStore.LookupEntry(overrideId)) - for (uint8 i = 0; i < MAX_OVERRIDE_SPELL; ++i) - if (uint32 spellId = overrideSpells->spellId[i]) - target->AddTemporarySpell(spellId); - } - else + if (target->HasUnitState(UNIT_STAT_ISOLATED) || target->IsImmunedToDamage(GetSpellProto())) { - target->SetUInt16Value(PLAYER_FIELD_BYTES2, 0, 0); - if (OverrideSpellDataEntry const* overrideSpells = sOverrideSpellDataStore.LookupEntry(overrideId)) - for (uint8 i = 0; i < MAX_OVERRIDE_SPELL; ++i) - if (uint32 spellId = overrideSpells->spellId[i]) - target->RemoveTemporarySpell(spellId); + SendTickImmune(target, caster); + return; } -} -void AuraEffect::HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const -{ - if (!(mode & AURA_EFFECT_HANDLE_REAL)) - return; + // ignore negative values (can be result apply spellmods to aura damage + int32 damage = std::max(m_amount, 0); - Unit* target = aurApp->GetTarget(); + // resilience reduce mana draining effect at spell crit damage reduction (added in 2.4) + if (powerType == POWER_MANA) + damage -= target->GetSpellCritDamageReduction(damage); - if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld()) - return; + uint32 gain = uint32(-target->ModifyPower(powerType, -damage)); - uint32 vehicleId = GetMiscValue(); + float dmgMultiplier = SpellMgr::CalculateSpellEffectValueMultiplier(GetSpellProto(), GetEffIndex(), caster); - if (apply) - { - if (!target->CreateVehicleKit(vehicleId, 0)) - return; - } - else if (target->GetVehicleKit()) - target->RemoveVehicleKit(); + SpellEntry const* spellProto = GetSpellProto(); + // maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG + SpellNonMeleeDamage damageInfo(caster, target, spellProto->Id, spellProto->SchoolMask); + // no SpellDamageBonus for burn mana + caster->CalculateSpellDamageTaken(&damageInfo, int32(gain * dmgMultiplier), spellProto); - WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, target->GetPackGUID().size()+4); - data.appendPackGUID(target->GetGUID()); - data << uint32(apply ? vehicleId : 0); - target->SendMessageToSet(&data, true); + caster->DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb); - if (apply) - { - data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); - target->ToPlayer()->GetSession()->SendPacket(&data); - } + caster->SendSpellNonMeleeDamageLog(&damageInfo); + + // Set trigger flag + uint32 procAttacker = PROC_FLAG_DONE_PERIODIC; + uint32 procVictim = PROC_FLAG_TAKEN_PERIODIC; + uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE) | PROC_EX_INTERNAL_DOT; + if (damageInfo.damage) + procVictim |= PROC_FLAG_TAKEN_DAMAGE; + + caster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto); + + caster->DealSpellDamage(&damageInfo, true); } diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.h b/src/server/game/Spells/Auras/SpellAuraEffects.h index 45b4d86c35b..2f1bab3f9fc 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.h +++ b/src/server/game/Spells/Auras/SpellAuraEffects.h @@ -65,11 +65,7 @@ class AuraEffect bool IsAffectedOnSpell(SpellEntry const *spell) const; void SendTickImmune(Unit* target, Unit *caster) const; - void PeriodicTick(AuraApplication * aurApp, Unit* caster) const; - void PeriodicDummyTick(Unit* target, Unit* caster) const; - void TriggerSpell(Unit* target, Unit* caster) const; - void TriggerSpellWithValue(Unit* target, Unit* caster) const; void CleanupTriggeredSpells(Unit* target); @@ -95,7 +91,7 @@ class AuraEffect bool IsPeriodicTickCrit(Unit* target, Unit const* caster) const; public: - // aura effect handlers + // aura effect apply/remove handlers void HandleNULL(AuraApplication const* /*aurApp*/, uint8 /*mode*/, bool /*apply*/) const { // not implemented @@ -259,9 +255,22 @@ class AuraEffect void HandleAuraConvertRune(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraLinked(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraOpenStable(AuraApplication const* aurApp, uint8 mode, bool apply) const; + void HandleAuraModFakeInebriation(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraOverrideSpells(AuraApplication const* aurApp, uint8 mode, bool apply) const; void HandleAuraSetVehicle(AuraApplication const* aurApp, uint8 mode, bool apply) const; - void HandleAuraModFakeInebriation(AuraApplication const* aurApp, uint8 mode, bool apply) const; + + // aura effect periodic tick handlers + void HandlePeriodicDummyAuraTick(Unit* target, Unit* caster) const; + void HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster) const; + void HandlePeriodicTriggerSpellWithValueAuraTick(Unit* target, Unit* caster) const; + void HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const; + void HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) const; + void HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const; + void HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const; + void HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) const; + void HandleObsModPowerAuraTick(Unit* target, Unit* caster) const; + void HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) const; + void HandlePeriodicPowerBurnManaAuraTick(Unit* target, Unit* caster) const; }; namespace Trinity -- cgit v1.2.3