diff options
Diffstat (limited to 'src/game/Spell.cpp')
-rw-r--r-- | src/game/Spell.cpp | 705 |
1 files changed, 491 insertions, 214 deletions
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index ed818d95570..991b525afa7 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -82,7 +82,7 @@ struct PrioritizeMana { int operator()( PrioritizeManaUnitWraper const& x, PrioritizeManaUnitWraper const& y ) const { - return x.getPercent() < y.getPercent(); + return x.getPercent() > y.getPercent(); } }; @@ -106,7 +106,7 @@ struct PrioritizeHealth { int operator()( PrioritizeHealthUnitWraper const& x, PrioritizeHealthUnitWraper const& y ) const { - return x.getPercent() < y.getPercent(); + return x.getPercent() > y.getPercent(); } }; @@ -363,6 +363,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi m_referencedFromCurrentSpell = false; m_executedCurrently = false; m_needComboPoints = NeedsComboPoints(m_spellInfo); + m_comboPointGain = 0; m_delayStart = 0; m_delayAtDamageCount = 0; @@ -370,6 +371,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi m_applyMultiplierMask = 0; m_effectMask = 0; + m_auraScaleMask = 0; // Get data for type of attack switch (m_spellInfo->DmgClass) @@ -700,7 +702,6 @@ void Spell::FillTargetMap() break; } } - if(IsChanneledSpell(m_spellInfo)) { uint8 mask = (1<<i); @@ -713,6 +714,29 @@ void Spell::FillTargetMap() } } } + else if (m_auraScaleMask) + { + bool checkLvl = !m_UniqueTargetInfo.empty(); + for(std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end();) + { + // remove targets which did not pass min level check + if(m_auraScaleMask && ihit->effectMask == m_auraScaleMask) + { + // Do not check for selfcast + if (!ihit->scaleAura && ihit->targetGUID != m_caster->GetGUID()) + { + m_UniqueTargetInfo.erase(ihit++); + continue; + } + } + ++ihit; + } + if (checkLvl && m_UniqueTargetInfo.empty()) + { + SendCastResult(SPELL_FAILED_LOWLEVEL); + finish(false); + } + } } if(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION) @@ -734,6 +758,7 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura) // Create base triggers flags for Attacker and Victim ( m_procAttacker, m_procVictim and m_procEx) //========================================================================================== + m_procVictim = m_procAttacker = 0; // Get data for type of attack and fill base info for trigger switch (m_spellInfo->DmgClass) { @@ -755,37 +780,15 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura) } break; default: - if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell - { - if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) - { - m_procAttacker = PROC_FLAG_SUCCESSFUL_HEALING_SPELL; - m_procVictim = PROC_FLAG_TAKEN_HEALING_SPELL; - } - else - { - m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL; - m_procVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL; - } - } - else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack + if (m_spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON && + m_spellInfo->EquippedItemSubClassMask & (1<<ITEM_SUBCLASS_WEAPON_WAND) + && m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack { m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT; m_procVictim = PROC_FLAG_TAKEN_RANGED_HIT; } - else // Negative spell - { - if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) - { - m_procAttacker = PROC_FLAG_SUCCESSFUL_DAMAGING_SPELL_HIT; - m_procVictim = PROC_FLAG_TAKEN_DAMAGING_SPELL_HIT; - } - else - { - m_procAttacker = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT; - m_procVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT; - } - } + // For other spells trigger procflags are set in Spell::DoAllEffectOnTarget + // Because spell positivity is dependant on target } m_procEx= PROC_EX_NONE; @@ -794,40 +797,34 @@ void Spell::prepareDataForTriggerSystem(AuraEffect * triggeredByAura) if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (m_spellInfo->SpellFamilyFlags[1] & 0x00002000 || m_spellInfo->SpellFamilyFlags[0] & 0x1C)) { m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION; + // Trigger only from spells originally casted by hunter(trap activation) to prevent multiple trigger from trap triggered spells + if (m_originalCasterGUID != m_caster->GetGUID() && m_originalCasterGUID) + return; } - else + /* + Effects which are result of aura proc from triggered spell cannot proc + to prevent chain proc of these spells + */ + if ((triggeredByAura && !triggeredByAura->GetParentAura()->GetTarget()->CanProc())) { - /* - Effects which are result of aura proc from triggered spell cannot proc - to prevent chain proc of these spells - */ - if ((triggeredByAura && !triggeredByAura->GetParentAura()->GetTarget()->CanProc()) || !m_caster->CanProc()) - { - m_canTrigger=false; - } + m_canTrigger=false; + } + // Ranged autorepeat attack is set as triggered spell - ignore it + if (!(m_procAttacker & PROC_FLAG_SUCCESSFUL_RANGED_HIT)) + { if (m_IsTriggeredSpell && (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_TRIGGERED_CAN_TRIGGER || m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2)) + m_procEx |= PROC_EX_INTERNAL_CANT_PROC; + else if (m_IsTriggeredSpell) m_procEx |= PROC_EX_INTERNAL_TRIGGERED; - - // Totem casts require spellfamilymask defined in spell_proc_event to proc - if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isTotem() && m_caster->IsControlledByPlayer()) - { - m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY; - } - // Check done for judgements to make them not trigger seal effects - else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_UNK1) - { - // Rogue poisons - if (m_spellInfo->SpellFamilyName && m_spellInfo->SpellFamilyFlags) - m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY; - else - m_canTrigger=false; - } } - if (m_IsTriggeredSpell || triggeredByAura) - m_procEx |= PROC_EX_INTERNAL_CANT_PROC; + // Totem casts require spellfamilymask defined in spell_proc_event to proc + if (m_originalCaster && m_caster != m_originalCaster && m_caster->GetTypeId()==TYPEID_UNIT && ((Creature*)m_caster)->isTotem() && m_caster->IsControlledByPlayer()) + { + m_procEx |= PROC_EX_INTERNAL_REQ_FAMILY; + } } void Spell::CleanupTargetList() @@ -858,6 +855,13 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex) { if (!immuned) ihit->effectMask |= 1 << effIndex; // Add only effect mask if not immuned + ihit->scaleAura = false; + if (m_auraScaleMask && ihit->effectMask == m_auraScaleMask && m_caster != pVictim) + { + SpellEntry const * auraSpell = sSpellStore.LookupEntry(spellmgr.GetFirstSpellInChain(m_spellInfo->Id)); + if ((pVictim->getLevel() + 10) >= auraSpell->spellLevel) + ihit->scaleAura = true; + } return; } } @@ -872,6 +876,13 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex) target.alive = pVictim->isAlive(); target.damage = 0; target.crit = false; + target.scaleAura = false; + if (m_auraScaleMask && target.effectMask == m_auraScaleMask && m_caster != pVictim) + { + SpellEntry const * auraSpell = sSpellStore.LookupEntry(spellmgr.GetFirstSpellInChain(m_spellInfo->Id)); + if ((pVictim->getLevel() + 10) >= auraSpell->spellLevel) + target.scaleAura = true; + } // Calculate hit result if(m_originalCaster) @@ -1052,7 +1063,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) if(spellHitTarget) { - SpellMissInfo missInfo = DoSpellHitOnUnit(spellHitTarget, mask); + SpellMissInfo missInfo = DoSpellHitOnUnit(spellHitTarget, mask, target->scaleAura); if(missInfo != SPELL_MISS_NONE) { if(missInfo != SPELL_MISS_MISS) @@ -1067,6 +1078,50 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) if( missInfo != SPELL_MISS_NONE && missInfo != SPELL_MISS_MISS) m_needComboPoints = false; + // Trigger info was not filled in spell::preparedatafortriggersystem - we do it now + if (canEffectTrigger && !procAttacker && !procVictim) + { + bool positive = true; + if (m_damage > 0) + positive = false; + else if (!m_healing) + { + for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + // If at least one effect negative spell is negative hit + if (mask & (1<<i) && !IsPositiveEffect(m_spellInfo->Id, i)) + { + positive = false; + break; + } + } + switch(m_spellInfo->DmgClass) + { + case SPELL_DAMAGE_CLASS_MAGIC: + if (positive) + { + procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL; + procVictim |= PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL; + } + else + { + procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL; + procVictim |= PROC_FLAG_TAKEN_NEGATIVE_MAGIC_SPELL; + } + break; + case SPELL_DAMAGE_CLASS_NONE: + if (positive) + { + procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT; + procVictim |= PROC_FLAG_TAKEN_POSITIVE_SPELL; + } + else + { + procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT; + procVictim |= PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT; + } + break; + } + } // All calculated do it! // Do healing and triggers if (m_healing > 0) @@ -1109,11 +1164,15 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge) if (canEffectTrigger && missInfo != SPELL_MISS_REFLECT) + { caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo, m_triggeredByAuraSpell); + if(caster->GetTypeId() == TYPEID_PLAYER && (m_spellInfo->Attributes & SPELL_ATTR_STOP_ATTACK_TARGET) == 0 && + (m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE || m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)) + ((Player *)caster)->CastItemCombatSpell(unitTarget, m_attackType, procVictim, procEx); + } if (m_spellAura) m_spellAura->SetProcDamage(damageInfo.damage); - caster->DealSpellDamage(&damageInfo, true); // Judgement of Blood @@ -1136,11 +1195,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) if( !m_caster->IsFriendlyTo(unit) && !IsPositiveSpell(m_spellInfo->Id)) { - if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) - { - m_caster->CombatStart(unit); - } - else if(m_customAttr & SPELL_ATTR_CU_AURA_CC) + m_caster->CombatStart(unit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO)); + + if(m_customAttr & SPELL_ATTR_CU_AURA_CC) { if(!unit->IsStandState()) unit->SetStandState(UNIT_STAND_STATE_STAND); @@ -1174,7 +1231,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target) } } -SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) +SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool scaleAura) { if(!unit || !effectMask) return SPELL_MISS_EVADE; @@ -1242,7 +1299,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) } if( unit->isInCombat() && !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) ) { - m_caster->SetInCombatState(unit->GetCombatTimer() > 0); + m_caster->SetInCombatState(unit->GetCombatTimer() > 0, unit); unit->getHostilRefManager().threatAssist(m_caster, 0.0f); } } @@ -1265,21 +1322,43 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) if (aura_effmask) { + // Select rank for aura with level requirements only in specific cases + // Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target + SpellEntry const * aurSpellInfo = m_spellInfo; + int32 basePoints[3]; + if (scaleAura) + { + aurSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(m_spellInfo,unitTarget->getLevel()); + assert (aurSpellInfo); + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + basePoints[i] = aurSpellInfo->EffectBasePoints[i]; + } + } + else + { + for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) + { + basePoints[i] = m_currentBasePoints[i]; + } + } + Unit * caster = m_originalCaster ? m_originalCaster : m_caster; - Aura * Aur = new Aura(m_spellInfo, aura_effmask, m_currentBasePoints, unit, m_caster, caster, m_CastItem); + Aura * Aur = new Aura(aurSpellInfo, aura_effmask, basePoints, unit, m_caster, caster, m_CastItem); if (!Aur->IsAreaAura()) { // Now Reduce spell duration using data received at spell hit int32 duration = Aur->GetAuraMaxDuration(); - unit->ApplyDiminishingToDuration(m_diminishGroup,duration,caster,m_diminishLevel); + int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup,aurSpellInfo); + unitTarget->ApplyDiminishingToDuration(m_diminishGroup, duration, caster, m_diminishLevel,limitduration); Aur->setDiminishGroup(m_diminishGroup); - duration = caster->ModSpellDuration(m_spellInfo, unit, duration, Aur->IsPositive()); + duration = caster->ModSpellDuration(aurSpellInfo, unit, duration, Aur->IsPositive()); //mod duration of channeled aura by spell haste if (IsChanneledSpell(m_spellInfo)) - caster->ModSpellCastTime(m_spellInfo, duration, this); + caster->ModSpellCastTime(aurSpellInfo, duration, this); if(duration != Aur->GetAuraMaxDuration()) { @@ -1288,9 +1367,9 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask) } // Prayer of Mending (jump animation), we need formal caster instead original for correct animation - if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST) + if( aurSpellInfo->SpellFamilyName == SPELLFAMILY_PRIEST) { - if(m_spellInfo->SpellFamilyFlags[1] & 0x000020) + if(aurSpellInfo->SpellFamilyFlags[1] & 0x000020) m_caster->CastSpell(unit, 41637, true, NULL, NULL, m_originalCasterGUID); } } @@ -1337,7 +1416,7 @@ void Spell::DoTriggersOnSpellHit(Unit *unit) if(roll_chance_i(i->second)) { m_caster->CastSpell(unit, i->first, true); - sLog.outDebug("Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first); + sLog.outDebug("Spell %d triggered spell %d by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->first->Id); } if (GetSpellDuration(i->first)==-1) { @@ -1651,6 +1730,15 @@ WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType) { switch(i_spellST->second.type) { + case SPELL_TARGET_TYPE_CONTROLLED: + for(Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr) + if ((*itr)->GetEntry() == i_spellST->second.targetEntry && (*itr)->IsWithinDistInMap(m_caster, range)) + { + goScriptTarget = NULL; + range = m_caster->GetDistance(creatureScriptTarget); + creatureScriptTarget = ((Creature *)*itr); + } + break; case SPELL_TARGET_TYPE_GAMEOBJECT: if(i_spellST->second.targetEntry) { @@ -2143,6 +2231,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) case TARGET_UNIT_AREA_ENEMY_DST: case TARGET_UNIT_CONE_ENEMY: case TARGET_UNIT_CONE_ENEMY_UNKNOWN: + case TARGET_UNIT_AREA_PATH: radius = GetSpellRadius(m_spellInfo, i, false); targetType = SPELL_TARGETS_ENEMY; break; @@ -2181,8 +2270,6 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) { case 46584: // Raise Dead { - // TODO: change visual of corpses which gave ghoul? - // Allow corpses to be ghouled only once? m_targets.m_targetMask &= ~TARGET_FLAG_DEST_LOCATION; WorldObject* result = FindCorpseUsing<MaNGOS::RaiseDeadObjectCheck> (); if(result) @@ -2195,6 +2282,45 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) } break; } + // Corpse Explosion + case 49158: + case 51325: + case 51326: + case 51327: + case 51328: + // Search for ghoul if our ghoul or dead body not valid unit target + if (!(m_targets.getUnitTarget() && (m_targets.getUnitTarget()->GetEntry() == 26125 && m_targets.getUnitTarget()->GetOwnerGUID() == m_caster->GetGUID() + || (m_targets.getUnitTarget()->getDeathState() == CORPSE + && m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId() + && m_targets.getUnitTarget()->GetTypeId()== TYPEID_UNIT + && !((Creature*)m_targets.getUnitTarget())->isDeadByDefault() + && !(m_targets.getUnitTarget()->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL)) + && m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId()))) + { + CleanupTargetList(); + + WorldObject* result = FindCorpseUsing <Trinity::ExplodeCorpseObjectCheck> (); + + if(result) + { + switch(result->GetTypeId()) + { + case TYPEID_UNIT: + case TYPEID_PLAYER: + m_targets.setUnitTarget((Unit*)result); + break; + } + } + else + { + if (m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->RemoveSpellCooldown(m_spellInfo->Id,true); + SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW); + finish(false); + } + } + break; + default: sLog.outDebug("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry()); @@ -2213,6 +2339,13 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) { if(i_spellST->second.type == SPELL_TARGET_TYPE_CREATURE) SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry); + else if (i_spellST->second.type == SPELL_TARGET_TYPE_CONTROLLED) + { + for(Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr) + if ((*itr)->GetEntry() == i_spellST->second.targetEntry && + /*(*itr)->IsWithinDistInMap(m_caster, radius)*/ (*itr)->IsInMap(m_caster)) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect) + unitList.push_back(*itr); + } } } } @@ -2319,7 +2452,7 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) case 59725: // Improved Spell Reflection - aoe aura unitList.remove(m_caster); break; - case 57699: //Replenishment (special target selection) 10 targets with lowest mana + case 57669: //Replenishment (special target selection) 10 targets with lowest mana { typedef std::priority_queue<PrioritizeManaUnitWraper, std::vector<PrioritizeManaUnitWraper>, PrioritizeMana> TopMana; TopMana manaUsers; @@ -2380,6 +2513,34 @@ void Spell::SetTargetMap(uint32 i, uint32 cur) healedMembers.pop(); } } + // Death Pact + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) + { + Unit * unit_to_add = NULL; + for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();++itr) + { + if ((*itr)->GetTypeId() == TYPEID_UNIT + && (*itr)->GetOwnerGUID() == m_caster->GetGUID() + && ((Creature*)(*itr))->GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD) + { + unit_to_add = (*itr); + break; + } + } + if (unit_to_add) + { + unitList.clear(); + unitList.push_back(unit_to_add); + } + // Pet not found - remove cooldown + else + { + if (modOwner->GetTypeId()==TYPEID_PLAYER) + modOwner->RemoveSpellCooldown(m_spellInfo->Id,true); + SendCastResult(SPELL_FAILED_NO_PET); + finish(false); + } + } } for(std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) AddUnitTarget(*itr, i); @@ -2414,6 +2575,27 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura } } + // Fill aura scaling information + if (m_caster->IsControlledByPlayer() && !IsPassiveSpell(m_spellInfo->Id) && m_spellInfo->spellLevel && !IsChanneledSpell(m_spellInfo) && !m_IsTriggeredSpell) + { + for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + { + if (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) + { + // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive + if (IsPositiveEffect(m_spellInfo->Id, i)) + { + m_auraScaleMask |= (1<<i); + if (m_currentBasePoints[i] != m_spellInfo->EffectBasePoints[i]) + { + m_auraScaleMask = 0; + break; + } + } + } + } + } + m_spellState = SPELL_STATE_PREPARING; if(triggeredByAura) @@ -2458,8 +2640,12 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura } } - // Fill cost data - m_powerCost = CalculatePowerCost(); + if (m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->SetSpellModTakingSpell(this, true); + // Fill cost data (not use power for item casts + m_powerCost = m_CastItem ? 0 : CalculatePowerCost(m_spellInfo, m_caster, m_spellSchoolMask); + if (m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->SetSpellModTakingSpell(this, false); SpellCastResult result = CheckCast(true); if(result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering @@ -2500,7 +2686,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect* triggeredByAura { // stealth must be removed at cast starting (at show channel bar) // skip triggered spell (item equip spell casting and other not explicit character casts/item uses) - if(isSpellBreakStealth(m_spellInfo) ) + if(!m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo) ) { m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST); for(uint32 i = 0; i < 3; ++i) @@ -2593,6 +2779,7 @@ void Spell::cast(bool skipCheck) && !target->IsFriendlyTo(m_caster) && !m_caster->canSeeOrDetect(target, true)) { SendCastResult(SPELL_FAILED_BAD_TARGETS); + SendInterrupted(0); finish(false); return; } @@ -2626,6 +2813,7 @@ void Spell::cast(bool skipCheck) if(castResult != SPELL_CAST_OK) { SendCastResult(castResult); + SendInterrupted(0); finish(false); SetExecutedCurrently(false); return; @@ -2634,6 +2822,14 @@ void Spell::cast(bool skipCheck) FillTargetMap(); + // Spell may be finished after target map check + if(m_spellState == SPELL_STATE_FINISHED) + { + SendInterrupted(0); + SetExecutedCurrently(false); + return; + } + if(m_spellInfo->SpellFamilyName) { if (m_spellInfo->excludeCasterAuraSpell && !IsPositiveSpell(m_spellInfo->excludeCasterAuraSpell)) @@ -2647,8 +2843,18 @@ void Spell::cast(bool skipCheck) { if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages m_preCastSpell = 11196; // Recently Bandaged - else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20) - m_preCastSpell = 23230; // Blood Fury - Healing Reduction + break; + } + case SPELLFAMILY_DRUID: + { + // Faerie Fire (Feral) + if (m_spellInfo->SpellFamilyFlags[0] & 0x00000400) + { + // Trigger only if has correct shapeshift for triggered spell + SpellEntry const * spellInfo = sSpellStore.LookupEntry(60089); + if (GetErrorAtShapeshiftedCast(spellInfo, m_caster->m_form) == SPELL_CAST_OK) + m_preCastSpell = 60089; + } break; } } @@ -2664,7 +2870,13 @@ void Spell::cast(bool skipCheck) ((Player*)m_caster)->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id); } - // this is related to combo points so must be done before takepower + if(!m_IsTriggeredSpell) + { + // Powers have to be taken before SendSpellGo + TakePower(); + TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot + } + // are there any spells need to be triggered after hit? // handle SPELL_AURA_ADD_TARGET_TRIGGER auras Unit::AuraEffectList const& targetTriggers = m_caster->GetAurasByType(SPELL_AURA_ADD_TARGET_TRIGGER); @@ -2682,17 +2894,9 @@ void Spell::cast(bool skipCheck) } } - // this is related to combo points so must be done before takepower if(m_customAttr & SPELL_ATTR_CU_DIRECT_DAMAGE) CalculateDamageDoneForAllTargets(); - if(!m_IsTriggeredSpell) - { - // Powers have to be taken before SendSpellGo - TakePower(); - TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot - } - // CAST SPELL SendSpellCooldown(); //SendCastResult(castResult); @@ -2726,6 +2930,9 @@ void Spell::cast(bool skipCheck) m_immediateHandled = false; m_spellState = SPELL_STATE_DELAYED; SetDelayStart(0); + + if(m_caster->hasUnitState(UNIT_STAT_CASTING) && !m_caster->IsNonMeleeSpellCasted(false, false, true)) + m_caster->clearUnitState(UNIT_STAT_CASTING); } else { @@ -2882,6 +3089,7 @@ void Spell::_handle_immediate_phase() if(!m_originalCaster) return; + uint8 oldEffMask = m_effectMask; // process ground for(uint32 j = 0; j < 3; ++j) { @@ -2898,6 +3106,38 @@ void Spell::_handle_immediate_phase() m_effectMask |= (1<<j); } } + if (oldEffMask != m_effectMask && m_UniqueTargetInfo.empty()) + { + uint32 procAttacker = m_procAttacker; + if (!procAttacker) + { + bool positive = true; + for (uint8 i = 0; i< MAX_SPELL_EFFECTS; ++i) + // If at least one effect negative spell is negative hit + if (m_effectMask & (1<<i) && !IsPositiveEffect(m_spellInfo->Id, i)) + { + positive = false; + break; + } + switch(m_spellInfo->DmgClass) + { + case SPELL_DAMAGE_CLASS_MAGIC: + if (positive) + procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_MAGIC_SPELL; + else + procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL; + break; + case SPELL_DAMAGE_CLASS_NONE: + if (positive) + procAttacker |= PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL_HIT; + else + procAttacker |= PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT; + break; + } + } + // Proc damage for spells which have only dest targets (2484 should proc 51486 for example) + m_originalCaster->ProcDamageAndSpell(0, procAttacker, 0, m_procEx | PROC_EX_NORMAL_HIT, 0, BASE_ATTACK, m_spellInfo, m_triggeredByAuraSpell); + } } void Spell::_handle_finish_phase() @@ -2906,6 +3146,10 @@ void Spell::_handle_finish_phase() if (m_needComboPoints) ((Player*)m_caster)->ClearComboPoints(); + // Real add combo points from effects + if (m_caster->GetTypeId()==TYPEID_PLAYER) + ((Player*)m_caster)->GainSpellComboPoints(m_comboPointGain); + // spell log if(m_needSpellLog) SendLogExecute(); @@ -3046,7 +3290,7 @@ void Spell::finish(bool ok) if(IsChanneledSpell(m_spellInfo)) m_caster->UpdateInterruptMask(); - if(!m_caster->IsNonMeleeSpellCasted(false, false, true)) + if(m_caster->hasUnitState(UNIT_STAT_CASTING) && !m_caster->IsNonMeleeSpellCasted(false, false, true)) m_caster->clearUnitState(UNIT_STAT_CASTING); // Unsummon summon as possessed creatures on spell cancel @@ -3103,9 +3347,10 @@ void Spell::finish(bool ok) } // potions disabled by client, send event "not in combat" if need - if (!m_triggeredByAuraSpell && m_caster->GetTypeId() == TYPEID_PLAYER) + if (m_caster->GetTypeId() == TYPEID_PLAYER) { - ((Player*)m_caster)->UpdatePotionCooldown(this); + if (!m_triggeredByAuraSpell) + ((Player*)m_caster)->UpdatePotionCooldown(this); // triggered spell pointer can be not set in some cases // this is needed for proper apply of triggered spell mods @@ -3251,11 +3496,11 @@ void Spell::SendSpellGo() //sLog.outDebug("Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id); uint32 castFlags = CAST_FLAG_UNKNOWN3; - + // triggered spells with spell visual != 0 - if(m_IsTriggeredSpell || m_triggeredByAuraSpell) + if((m_IsTriggeredSpell && !IsAutoRepeatRangedSpell(m_spellInfo)) || m_triggeredByAuraSpell) castFlags |= CAST_FLAG_UNKNOWN0; - + if(m_spellInfo->Attributes & SPELL_ATTR_REQ_AMMO) castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual if ((m_caster->GetTypeId() == TYPEID_PLAYER || @@ -3352,7 +3597,7 @@ void Spell::WriteAmmoToPacket( WorldPacket * data ) ammoInventoryType = pProto->InventoryType; } } - else if(m_caster->GetDummyAura(46699)) // Requires No Ammo + else if(m_caster->HasAura(46699)) // Requires No Ammo { ammoDisplayID = 5996; // normal arrow ammoInventoryType = INVTYPE_AMMO; @@ -3887,6 +4132,7 @@ void Spell::TakeRunePower() if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0)) { plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec + plr->SetLastUsedRune(RuneType(rune)); runeCost[rune]--; } } @@ -3901,8 +4147,52 @@ void Spell::TakeRunePower() if((plr->GetRuneCooldown(i) == 0) && (rune == RUNE_DEATH)) { plr->SetRuneCooldown(i, RUNE_COOLDOWN); // 5*2=10 sec + plr->SetLastUsedRune(RuneType(rune)); runeCost[rune]--; + bool auraFound = false; plr->ConvertRune(i, plr->GetBaseRune(i)); + // * * * * * * * * * * * + // update convert rune auras + // * * * * * * * * * * * + // Remove rune from SPELL_AURA_CONVERT_RUNE when rune is used + // To prevent overriding other rune convert effects + Unit::AuraEffectList const& runeconvert = m_caster->GetAurasByType(SPELL_AURA_CONVERT_RUNE); + for(Unit::AuraEffectList::const_iterator itr = runeconvert.begin(); itr != runeconvert.end(); ++itr) + { + // Remove rune of aura if avalible + if ((*itr)->GetAmount() & (1<<i)) + { + (*itr)->SetAmount((*itr)->GetAmount() & ~(1<<i)); + auraFound = true; + } + // All runes from aura used - remove aura + if (!(*itr)->GetAmount()) + plr->RemoveAura((*itr)->GetParentAura(), AURA_REMOVE_BY_EXPIRE); + break; + } + if (!auraFound) + { + // Decrease used rune count for dk talent auras + // To prevent overriding other rune convert effects + Unit::AuraEffectList const& runeconvert = m_caster->GetAurasByType(SPELL_AURA_CONVERT_RUNE); + for(Unit::AuraEffectList::const_iterator itr = runeconvert.begin(); itr != runeconvert.end(); ++itr) + { + if (plr->GetBaseRune(i) != RUNE_DEATH) + { + if ((*itr)->GetSpellProto()->SpellIconID != 2622) + continue; + } + else if ((*itr)->GetSpellProto()->SpellIconID != 3041 && + (*itr)->GetSpellProto()->SpellIconID != 22) + continue; + + // Remove rune of aura if avalible + if ((*itr)->GetAmount() & (1<<i)) + (*itr)->SetAmount((*itr)->GetAmount() & ~(1<<i)); + break; + } + } + if(runeCost[RUNE_DEATH] == 0) break; } @@ -3976,13 +4266,14 @@ void Spell::HandleThreatSpells(uint32 spellId) if(!m_targets.getUnitTarget()->CanHaveThreatList()) return; - SpellThreatEntry const *threatSpell = sSpellThreatStore.LookupEntry<SpellThreatEntry>(spellId); - if(!threatSpell) + uint16 threat = spellmgr.GetSpellThreat(spellId); + + if(!threat) return; - m_targets.getUnitTarget()->AddThreat(m_caster, float(threatSpell->threat)); + m_targets.getUnitTarget()->AddThreat(m_caster, float(threat)); - DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threatSpell->threat); + DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threat); } void Spell::HandleEffects(Unit *pUnitTarget,Item *pItemTarget,GameObject *pGOTarget,uint32 i) @@ -4021,15 +4312,19 @@ void Spell::TriggerSpell() SpellCastResult Spell::CheckCast(bool strict) { // check cooldowns to prevent cheating - if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) + if(m_caster->GetTypeId()==TYPEID_PLAYER) { //can cast triggered (by aura only?) spells while have this flag if (!m_IsTriggeredSpell && ((Player*)m_caster)->HasFlag(PLAYER_FLAGS, PLAYER_ALLOW_ONLY_ABILITY)) return SPELL_FAILED_SPELL_IN_PROGRESS; - if(m_triggeredByAuraSpell) - return SPELL_FAILED_DONT_REPORT; - else - return SPELL_FAILED_NOT_READY; + + if (((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) + { + if(m_triggeredByAuraSpell) + return SPELL_FAILED_DONT_REPORT; + else + return SPELL_FAILED_NOT_READY; + } } // only allow triggered spells if at an ended battleground @@ -4118,7 +4413,12 @@ SpellCastResult Spell::CheckCast(bool strict) if(m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell)) return SPELL_FAILED_TARGET_AURASTATE; - if(target != m_caster) + if(!m_IsTriggeredSpell && target == m_caster && m_spellInfo->AttributesEx & SPELL_ATTR_EX_CANT_TARGET_SELF) + return SPELL_FAILED_BAD_TARGETS; + + bool non_caster_target = target != m_caster && !spellmgr.IsSpellWithCasterSourceTargetsOnly(m_spellInfo); + + if(non_caster_target) { // target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds if(!m_IsTriggeredSpell && m_spellInfo->TargetAuraState && !target->HasAuraState(AuraState(m_spellInfo->TargetAuraState), m_spellInfo, m_caster)) @@ -4131,13 +4431,6 @@ SpellCastResult Spell::CheckCast(bool strict) if(!m_IsTriggeredSpell && VMAP::VMapFactory::checkSpellForLoS(m_spellInfo->Id) && !m_caster->IsWithinLOSInMap(target)) return SPELL_FAILED_LINE_OF_SIGHT; - // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode - // this case can be triggered if rank not found (too low-level target for first rank) - if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) - for(int i=0;i<3;i++) - if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) - if(target->getLevel() + 10 < m_spellInfo->spellLevel) - return SPELL_FAILED_LOWLEVEL; } else if (m_caster->GetTypeId() == TYPEID_PLAYER) // Target - is player caster { @@ -4173,7 +4466,7 @@ SpellCastResult Spell::CheckCast(bool strict) //check creature type //ignore self casts (including area casts when caster selected as target) - if(target != m_caster) + if(non_caster_target) { if(!CheckTargetCreatureType(target)) { @@ -4186,7 +4479,7 @@ SpellCastResult Spell::CheckCast(bool strict) // TODO: this check can be applied and for player to prevent cheating when IsPositiveSpell will return always correct result. // check target for pet/charmed casts (not self targeted), self targeted cast used for area effects and etc - if(m_caster != target && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID()) + if(non_caster_target && m_caster->GetTypeId() == TYPEID_UNIT && m_caster->GetCharmerOrOwnerGUID()) { // check correctness positive/negative cast target (pet cast real check and cheating check) if(IsPositiveSpell(m_spellInfo->Id)) @@ -4225,7 +4518,7 @@ SpellCastResult Spell::CheckCast(bool strict) } // check if target is in combat - if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) + if (non_caster_target && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) return SPELL_FAILED_TARGET_AFFECTING_COMBAT; } @@ -4442,12 +4735,23 @@ SpellCastResult Spell::CheckCast(bool strict) if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, m_targets.getUnitTarget() )) return SPELL_FAILED_UNIT_NOT_INFRONT; } + else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] == 0x2000) // Death Coil (DeathKnight) + { + Unit* target = m_targets.getUnitTarget(); + if (!target || (target->IsFriendlyTo(m_caster) && target->GetCreatureType() != CREATURE_TYPE_UNDEAD)) + return SPELL_FAILED_BAD_TARGETS; + } else if (m_spellInfo->Id == 19938) // Awaken Peon { Unit *unit = m_targets.getUnitTarget(); if(!unit || !unit->HasAura(17743, 0)) return SPELL_FAILED_BAD_TARGETS; } + else if (m_spellInfo->Id == 52264) // Deliver Stolen Horse + { + if(!m_caster->FindNearestCreature(28653,5)) + return SPELL_FAILED_OUT_OF_RANGE; + } break; } case SPELL_EFFECT_LEARN_SPELL: @@ -4492,6 +4796,14 @@ SpellCastResult Spell::CheckCast(bool strict) break; } + case SPELL_EFFECT_APPLY_GLYPH: + { + uint32 glyphId = m_spellInfo->EffectMiscValue[i]; + if(GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyphId)) + if(m_caster->HasAura(gp->SpellId)) + return SPELL_FAILED_UNIQUE_GLYPH; + break; + } case SPELL_EFFECT_FEED_PET: { if (m_caster->GetTypeId() != TYPEID_PLAYER) @@ -4529,9 +4841,14 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_EFFECT_CHARGE: { + if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR) + { + // Warbringer - can't be handled in proc system - should be done before checkcast root check and charge effect process + if (strict && m_caster->IsScriptOverriden(m_spellInfo, 6953)) + m_caster->RemoveMovementImpairingAuras(); + } if (m_caster->hasUnitState(UNIT_STAT_ROOT)) return SPELL_FAILED_ROOTED; - break; } case SPELL_EFFECT_SKINNING: @@ -4564,7 +4881,6 @@ SpellCastResult Spell::CheckCast(bool strict) break; } - case SPELL_EFFECT_OPEN_LOCK_ITEM: case SPELL_EFFECT_OPEN_LOCK: { if( m_spellInfo->EffectImplicitTargetA[i] != TARGET_GAMEOBJECT && @@ -4588,7 +4904,7 @@ SpellCastResult Spell::CheckCast(bool strict) uint32 lockId = 0; if (GameObject* go = m_targets.getGOTarget()) { - lockId = go->GetLockId(); + lockId = go->GetGOInfo()->GetLockId(); if (!lockId) return SPELL_FAILED_BAD_TARGETS; } @@ -4762,27 +5078,34 @@ SpellCastResult Spell::CheckCast(bool strict) } case SPELL_AURA_MOD_POSSESS: case SPELL_AURA_MOD_CHARM: - //case SPELL_AURA_MOD_POSSESS_PET: + case SPELL_AURA_MOD_POSSESS_PET: + case SPELL_AURA_AOE_CHARM: { - if(m_caster->GetPetGUID()) - return SPELL_FAILED_ALREADY_HAVE_SUMMON; - - if(m_caster->GetCharmGUID()) - return SPELL_FAILED_ALREADY_HAVE_CHARM; - if(m_caster->GetCharmerGUID()) return SPELL_FAILED_CHARMED; - Unit *target = m_targets.getUnitTarget(); - if(!target || target->GetTypeId() == TYPEID_UNIT - && ((Creature*)target)->isVehicle()) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + if(m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_CHARM + || m_spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS) + { + if(m_caster->GetPetGUID()) + return SPELL_FAILED_ALREADY_HAVE_SUMMON; - if(target->GetCharmerGUID()) - return SPELL_FAILED_CHARMED; + if(m_caster->GetCharmGUID()) + return SPELL_FAILED_ALREADY_HAVE_CHARM; + } + + if(Unit *target = m_targets.getUnitTarget()) + { + if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isVehicle()) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + + if(target->GetCharmerGUID()) + return SPELL_FAILED_CHARMED; - if(int32(target->getLevel()) > CalculateDamage(i, target)) - return SPELL_FAILED_HIGHLEVEL; + int32 damage = CalculateDamage(i, target); + if(damage && int32(target->getLevel()) > damage) + return SPELL_FAILED_HIGHLEVEL; + } break; } @@ -4818,14 +5141,15 @@ SpellCastResult Spell::CheckCast(bool strict) break; } - case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED: case SPELL_AURA_FLY: + case SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED: { - // not allow cast fly spells at old maps by players (all spells is self target) - if(m_originalCaster && m_originalCaster->GetTypeId()==TYPEID_PLAYER) + // not allow cast fly spells if not have req. skills (all spells is self target) + // allow always ghost flight spells + if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->isAlive()) { - if( !((Player*)m_originalCaster)->IsAllowUseFlyMountsHere() ) - return SPELL_FAILED_NOT_HERE; + if (!((Player*)m_originalCaster)->IsKnowHowFlyIn(m_originalCaster->GetMapId(),m_originalCaster->GetZoneId())) + return m_IsTriggeredSpell ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE; } break; } @@ -5092,81 +5416,13 @@ SpellCastResult Spell::CheckRange(bool strict) { if(!m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, max_range)) return SPELL_FAILED_OUT_OF_RANGE; - if(m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, min_range)) + if(min_range && m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ, min_range)) return SPELL_FAILED_TOO_CLOSE; } return SPELL_CAST_OK; } -int32 Spell::CalculatePowerCost() -{ - // item cast not used power - if(m_CastItem) - return 0; - - // Spell drain all exist power on cast (Only paladin lay of Hands) - if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER) - { - // If power type - health drain all - if (m_spellInfo->powerType == POWER_HEALTH) - return m_caster->GetHealth(); - // Else drain all power - if (m_spellInfo->powerType < MAX_POWERS) - return m_caster->GetPower(Powers(m_spellInfo->powerType)); - sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); - return 0; - } - - // Base powerCost - int32 powerCost = m_spellInfo->manaCost; - // PCT cost from total amount - if (m_spellInfo->ManaCostPercentage) - { - switch (m_spellInfo->powerType) - { - // health as power used - case POWER_HEALTH: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateHealth() / 100; - break; - case POWER_MANA: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100; - break; - case POWER_RAGE: - case POWER_FOCUS: - case POWER_ENERGY: - case POWER_HAPPINESS: - powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100; - break; - case POWER_RUNE: - case POWER_RUNIC_POWER: - sLog.outDebug("Spell::CalculateManaCost: Not implemented yet!"); - break; - default: - sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); - return 0; - } - } - SpellSchools school = GetFirstSchoolInMask(m_spellSchoolMask); - // Flat mod from caster auras by spell school - powerCost += m_caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school); - // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) - if ( m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST ) - powerCost += m_caster->GetAttackTime(OFF_ATTACK)/100; - // Apply cost mod by spell - if(Player* modOwner = m_caster->GetSpellModOwner()) - modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, powerCost, this); - - if(m_spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION) - powerCost = int32(powerCost/ (1.117f* m_spellInfo->spellLevel / m_caster->getLevel() -0.1327f)); - - // PCT mod from user auras by school - powerCost = int32(powerCost * (1.0f+m_caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+school))); - if (powerCost < 0) - powerCost = 0; - return powerCost; -} - SpellCastResult Spell::CheckPower() { // item cast not used power @@ -5310,7 +5566,7 @@ SpellCastResult Spell::CheckItems() TypeContainerVisitor<Trinity::GameObjectSearcher<Trinity::GameObjectFocusCheck>, GridTypeMapContainer > object_checker(checker); CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap()); if(!ok) return SPELL_FAILED_REQUIRES_SPELL_FOCUS; @@ -5567,7 +5823,7 @@ SpellCastResult Spell::CheckItems() if(!ammo) { // Requires No Ammo - if(m_caster->GetDummyAura(46699)) + if(m_caster->HasAura(46699)) break; // skip other checks return SPELL_FAILED_NO_AMMO; @@ -5758,8 +6014,10 @@ bool Spell::CheckTargetCreatureType(Unit* target) const { uint32 spellCreatureTargetMask = m_spellInfo->TargetCreatureType; - // Curse of Doom : not find another way to fix spell target check :/ - if(m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->SpellFamilyFlags.IsEqual(0,0x02,0)) + // Curse of Doom & Exorcism: not find another way to fix spell target check :/ + if (m_spellInfo->SpellFamilyName==SPELLFAMILY_WARLOCK && m_spellInfo->Category == 1179 || + // TODO: will be removed in 3.2.x + m_spellInfo->SpellFamilyName==SPELLFAMILY_PALADIN && m_spellInfo->Category == 19) { // not allow cast at player if(target->GetTypeId()==TYPEID_PLAYER) @@ -5834,7 +6092,26 @@ bool Spell::CheckTarget(Unit* target, uint32 eff) return false; } - //Do not check LOS for triggered spells + switch(m_spellInfo->EffectApplyAuraName[eff]) + { + case SPELL_AURA_NONE: + default: + break; + case SPELL_AURA_MOD_POSSESS: + case SPELL_AURA_MOD_CHARM: + case SPELL_AURA_MOD_POSSESS_PET: + case SPELL_AURA_AOE_CHARM: + if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isVehicle()) + return false; + if(target->GetCharmerGUID()) + return false; + if(int32 damage = CalculateDamage(eff, target)) + if((int32)target->getLevel() > damage) + return false; + break; + } + + //Do not do further checks for triggered spells if(m_IsTriggeredSpell) return true; @@ -6115,7 +6392,7 @@ void Spell::CalculateDamageDoneForAllTargets() if (target.missCondition==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target { - target.damage += CalculateDamageDone(unit, mask, multiplier); + target.damage += CalculateDamageDone(unit, mask, multiplier); target.crit = m_caster->isSpellCrit(unit, m_spellInfo, m_spellSchoolMask, m_attackType); } else if (target.missCondition == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit) |