diff options
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 328 |
1 files changed, 215 insertions, 113 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 5016e5ebc2b..510be691d18 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -19,7 +19,7 @@ */ #include "Common.h" -#include "Database/DatabaseEnv.h" +#include "DatabaseEnv.h" #include "WorldPacket.h" #include "WorldSession.h" #include "GridNotifiers.h" @@ -41,7 +41,6 @@ #include "MapManager.h" #include "ObjectAccessor.h" #include "CellImpl.h" -#include "Policies/SingletonImp.h" #include "SharedDefines.h" #include "LootMgr.h" #include "VMapFactory.h" @@ -53,7 +52,7 @@ #include "ScriptMgr.h" #include "ConditionMgr.h" -#define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILISECONDS) +#define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS) extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; @@ -149,6 +148,15 @@ void SpellCastTargets::setItemTarget(Item* item) m_targetMask |= TARGET_FLAG_ITEM; } +void SpellCastTargets::setTradeItemTarget(Player* caster) +{ + m_itemTargetGUID = uint64(TRADE_SLOT_NONTRADED); + m_itemTargetEntry = 0; + m_targetMask |= TARGET_FLAG_TRADE_ITEM; + + Update(caster); +} + void SpellCastTargets::setCorpseTarget(Corpse* corpse) { m_CorpseTargetGUID = corpse->GetGUID(); @@ -164,12 +172,13 @@ void SpellCastTargets::Update(Unit* caster) m_itemTarget = NULL; if (caster->GetTypeId() == TYPEID_PLAYER) { + Player *player = caster->ToPlayer(); if (m_targetMask & TARGET_FLAG_ITEM) - m_itemTarget = caster->ToPlayer()->GetItemByGuid(m_itemTargetGUID); + m_itemTarget = player->GetItemByGuid(m_itemTargetGUID); else if (m_targetMask & TARGET_FLAG_TRADE_ITEM) - if (m_itemTargetGUID == TRADE_SLOT_NONTRADED) // here it is not guid but slot. Also prevent hacking slots - if (Player* pTrader = caster->ToPlayer()->GetTrader()) - m_itemTarget = pTrader->GetItemByTradeSlot(m_itemTargetGUID); + if (m_itemTargetGUID == TRADE_SLOT_NONTRADED) // here it is not guid but slot. Also prevents hacking slots + if (TradeData* pTrade = player->GetTradeData()) + m_itemTarget = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED); if (m_itemTarget) m_itemTargetEntry = m_itemTarget->GetEntry(); @@ -390,13 +399,12 @@ Spell::Spell(Unit* Caster, SpellEntry const *info, bool triggered, uint64 origin } for (int i=0; i <3; ++i) - m_currentBasePoints[i] = m_spellInfo->CalculateSimpleValue(i); + m_currentBasePoints[i] = m_spellInfo->EffectBasePoints[i]; m_spellState = SPELL_STATE_NULL; m_TriggerSpells.clear(); m_IsTriggeredSpell = triggered; - //m_AreaAura = false; m_CastItem = NULL; unitTarget = NULL; @@ -1336,7 +1344,15 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool // Now Reduce spell duration using data received at spell hit int32 duration = m_spellAura->GetMaxDuration(); int32 limitduration = GetDiminishingReturnsLimitDuration(m_diminishGroup,aurSpellInfo); - unit->ApplyDiminishingToDuration(m_diminishGroup, duration, m_originalCaster, m_diminishLevel,limitduration); + float diminishMod = unit->ApplyDiminishingToDuration(m_diminishGroup, duration, m_originalCaster, m_diminishLevel,limitduration); + + // unit is immune to aura if it was diminished to 0 duration + if (diminishMod == 0.0f) + { + m_spellAura->Remove(); + return SPELL_MISS_IMMUNE; + } + ((UnitAura*)m_spellAura)->SetDiminishGroup(m_diminishGroup); bool positive = IsPositiveSpell(m_spellAura->GetId()); @@ -1350,12 +1366,6 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool if (IsChanneledSpell(m_spellInfo)) m_originalCaster->ModSpellCastTime(aurSpellInfo, duration, this); - if (duration == 0 && !positive) - { - m_spellAura->Remove(); - return SPELL_MISS_IMMUNE; - } - if (duration != m_spellAura->GetMaxDuration()) { m_spellAura->SetMaxDuration(duration); @@ -1989,7 +1999,6 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur) if (cur == TARGET_DST_TARGET_ENEMY || cur == TARGET_DEST_TARGET_ANY) { m_targets.setDst(target); - AddUnitTarget(target, i); break; } @@ -2018,9 +2027,6 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur) Position pos; target->GetNearPosition(pos, dist, angle); m_targets.setDst(&pos); - // Teleports use this as destination - if (m_spellInfo->Effect[i] != SPELL_EFFECT_TELEPORT_UNITS) - AddUnitTarget(target, i); break; } @@ -2416,6 +2422,117 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur) if (!unitList.empty()) { + // Special target selection for smart heals and energizes + uint32 maxSize = 0; + int32 power = -1; + switch (m_spellInfo->SpellFamilyName) + { + case SPELLFAMILY_GENERIC: + switch (m_spellInfo->Id) + { + case 52759: // Ancestral Awakening + case 71610: // Echoes of Light (Althor's Abacus normal version) + case 71641: // Echoes of Light (Althor's Abacus heroic version) + maxSize = 1; + power = POWER_HEALTH; + break; + case 54968: // Glyph of Holy Light + maxSize = m_spellInfo->MaxAffectedTargets; + power = POWER_HEALTH; + break; + case 57669: // Replenishment + // In arenas Replenishment may only affect the caster + if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->ToPlayer()->InArena()) + { + unitList.clear(); + unitList.push_back(m_caster); + break; + } + maxSize = 10; + power = POWER_MANA; + break; + default: + break; + } + break; + case SPELLFAMILY_PRIEST: + if (m_spellInfo->SpellFamilyFlags[0] == 0x10000000) // Circle of Healing + { + maxSize = m_caster->HasAura(55675) ? 6 : 5; // Glyph of Circle of Healing + power = POWER_HEALTH; + } + else if (m_spellInfo->Id == 64844) // Divine Hymn + { + maxSize = 3; + power = POWER_HEALTH; + } + else if (m_spellInfo->Id == 64904) // Hymn of Hope + { + maxSize = 3; + power = POWER_MANA; + } + else + break; + + // Remove targets outside caster's raid + for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) + { + if (!(*itr)->IsInRaidWith(m_caster)) + itr = unitList.erase(itr); + else + ++itr; + } + break; + case SPELLFAMILY_DRUID: + if (m_spellInfo->SpellFamilyFlags[1] == 0x04000000) // Wild Growth + { + maxSize = m_caster->HasAura(62970) ? 6 : 5; // Glyph of Wild Growth + power = POWER_HEALTH; + } + else + break; + + // Remove targets outside caster's raid + for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) + { + if (!(*itr)->IsInRaidWith(m_caster)) + itr = unitList.erase(itr); + else + ++itr; + } + break; + default: + break; + } + + if (maxSize && power != -1) + { + if (power == POWER_HEALTH) + { + if (unitList.size() > maxSize) + { + unitList.sort(Trinity::HealthPctOrderPred()); + unitList.resize(maxSize); + } + } + else + { + for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) + { + if ((*itr)->getPowerType() != (Powers)power) + itr = unitList.erase(itr); + else + ++itr; + } + if (unitList.size() > maxSize) + { + unitList.sort(Trinity::PowerPctOrderPred((Powers)power)); + unitList.resize(maxSize); + } + } + } + + // Other special target selection goes here if (uint32 maxTargets = m_spellValue->MaxAffectedTargets) { Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS); @@ -2438,56 +2555,6 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur) case 59725: // Improved Spell Reflection - aoe aura unitList.remove(m_caster); break; - case 57669: //Replenishment (special target selection) 10 targets with lowest mana - { - for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) - { - if ((*itr)->getPowerType() != POWER_MANA) - itr = unitList.erase(itr); - else - ++itr; - } - if (unitList.size() > 10) - { - unitList.sort(Trinity::PowerPctOrderPred(POWER_MANA)); - unitList.resize(10); - } - break; - } - case 52759: // Ancestral Awakening - { - if (unitList.size() > 1) - { - unitList.sort(Trinity::HealthPctOrderPred()); - unitList.resize(1); - } - break; - } - } - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_DEST_TARGET_ANY - && m_spellInfo->EffectImplicitTargetB[i] == TARGET_UNIT_AREA_ALLY_DST)// Wild Growth, Circle of Healing, Glyph of holy light target special selection - { - for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) - { - if (!(*itr)->IsInRaidWith(m_targets.getUnitTarget())) - itr = unitList.erase(itr); - else - ++itr; - } - - uint32 maxsize = 5; - - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && m_spellInfo->SpellFamilyFlags[1] & 0x04000000) // Wild Growth - maxsize += m_caster->HasAura(62970) ? 1 : 0; // Glyph of Wild Growth - - if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags[0] & 0x10000000 && m_spellInfo->SpellIconID == 2214) // Circle of Healing - maxsize += m_caster->HasAura(55675) ? 1 : 0; // Glyph of Circle of Healing - - if (unitList.size() > maxsize) - { - unitList.sort(Trinity::HealthPctOrderPred()); - unitList.resize(maxsize); - } } // Death Pact if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) @@ -2844,6 +2911,32 @@ void Spell::cast(bool skipCheck) SetExecutedCurrently(false); return; } + + // additional check after cast bar completes (must not be in CheckCast) + // if trade not complete then remember it in trade data + if (m_targets.getTargetMask() & TARGET_FLAG_TRADE_ITEM) + { + if (m_caster->GetTypeId() == TYPEID_PLAYER) + { + if (TradeData* my_trade = m_caster->ToPlayer()->GetTradeData()) + { + if (!my_trade->IsInAcceptProcess()) + { + // Spell will be casted at completing the trade. Silently ignore at this place + my_trade->SetSpell(m_spellInfo->Id, m_CastItem); + SendCastResult(SPELL_FAILED_DONT_REPORT); + SendInterrupted(0); + m_caster->ToPlayer()->RestoreSpellMods(this); + // cleanup after mod system + // triggered spell pointer can be not removed in some cases + m_caster->ToPlayer()->SetSpellModTakingSpell(this, false); + finish(false); + SetExecutedCurrently(false); + return; + } + } + } + } } SelectSpellTargets(); @@ -2909,6 +3002,12 @@ void Spell::cast(bool skipCheck) TakePower(); TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot } + else if (Item* targetItem = m_targets.getItemTarget()) + { + /// Not own traded item (in trader trade slot) req. reagents including triggered spell case + if (targetItem->GetOwnerGUID() != m_caster->GetGUID()) + TakeReagents(); + } // are there any spells need to be triggered after hit? // handle SPELL_AURA_ADD_TARGET_TRIGGER auras @@ -2938,8 +3037,9 @@ void Spell::cast(bool skipCheck) switch(m_spellInfo->Effect[i]) { case SPELL_EFFECT_CHARGE: + case SPELL_EFFECT_CHARGE_DEST: case SPELL_EFFECT_JUMP: - case SPELL_EFFECT_JUMP2: + case SPELL_EFFECT_JUMP_DEST: case SPELL_EFFECT_LEAP_BACK: case SPELL_EFFECT_ACTIVATE_RUNE: HandleEffects(NULL,NULL,NULL,i); @@ -4274,7 +4374,12 @@ void Spell::TakeRunePower() void Spell::TakeReagents() { if (m_IsTriggeredSpell) // reagents used in triggered spell removed by original spell or don't must be removed. - return; + { + Item* targetItem = m_targets.getItemTarget(); + /// Not own traded item (in trader trade slot) req. reagents including triggered spell case + if (!(targetItem && targetItem->GetOwnerGUID() != m_caster->GetGUID())) + return; + } if (m_caster->GetTypeId() != TYPEID_PLAYER) return; @@ -4669,7 +4774,7 @@ SpellCastResult Spell::CheckCast(bool strict) // - with greater than 10 min CD without SPELL_ATTR_EX4_USABLE_IN_ARENA flag // - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag if ((m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) || - GetSpellRecoveryTime(m_spellInfo) > 10 * MINUTE * IN_MILISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA)) + GetSpellRecoveryTime(m_spellInfo) > 10 * MINUTE * IN_MILLISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA)) if (MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId())) if (mapEntry->IsBattleArena()) return SPELL_FAILED_NOT_IN_ARENA; @@ -5212,24 +5317,6 @@ SpellCastResult Spell::CheckCast(bool strict) if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_caster->ToPlayer()->IsInFeralForm()) return SPELL_FAILED_ONLY_SHAPESHIFT; break; - // Wild Growth - case 48438: - case 53248: - case 53249: - case 53251: - { - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return SPELL_FAILED_DONT_REPORT; - - Unit* target = m_targets.getUnitTarget(); - if (!target || target->GetTypeId() != TYPEID_PLAYER) - return SPELL_FAILED_BAD_TARGETS; - - if (!m_caster->ToPlayer()->IsInSameRaidWith(target->ToPlayer())) - return SPELL_FAILED_TARGET_NOT_IN_RAID; - - break; - } case 1515: { if (m_caster->GetTypeId() != TYPEID_PLAYER) @@ -5304,6 +5391,9 @@ SpellCastResult Spell::CheckCast(bool strict) if (target->GetTypeId() == TYPEID_UNIT && target->ToCreature()->IsVehicle()) return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + if (target->IsMounted()) + return SPELL_FAILED_CANT_BE_CHARMED; + if (target->GetCharmerGUID()) return SPELL_FAILED_CHARMED; @@ -5357,23 +5447,12 @@ SpellCastResult Spell::CheckCast(bool strict) // allow always ghost flight spells if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->isAlive()) { - // 4197 = Wintergrasp || 4395 = Dalaran && 4564 = Krasus Landing - if (m_originalCaster->GetZoneId() == 4197 || m_originalCaster->GetZoneId() == 4395 && m_originalCaster->GetAreaId() != 4564) - return m_IsTriggeredSpell ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE; + if (AreaTableEntry const* pArea = GetAreaEntryByAreaID(m_originalCaster->GetAreaId())) + if (pArea->flags & AREA_FLAG_NO_FLY_ZONE) + return m_IsTriggeredSpell ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE; } break; } - case SPELL_AURA_RANGED_AP_ATTACKER_CREATURES_BONUS: - { - if (!m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() != TYPEID_UNIT) - return SPELL_FAILED_BAD_IMPLICIT_TARGETS; - - // can be casted at non-friendly unit or own pet/charm - if (m_caster->IsFriendlyTo(m_targets.getUnitTarget())) - return SPELL_FAILED_TARGET_FRIENDLY; - - break; - } case SPELL_AURA_PERIODIC_MANA_LEECH: { if (!m_targets.getUnitTarget()) @@ -5392,6 +5471,26 @@ SpellCastResult Spell::CheckCast(bool strict) } } + // check trade slot case (last, for allow catch any another cast problems) + if (m_targets.getTargetMask() & TARGET_FLAG_TRADE_ITEM) + { + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return SPELL_FAILED_NOT_TRADING; + + TradeData* my_trade = m_caster->ToPlayer()->GetTradeData(); + + if (!my_trade) + return SPELL_FAILED_NOT_TRADING; + + TradeSlots slot = TradeSlots(m_targets.getItemTargetGUID()); + if (slot != TRADE_SLOT_NONTRADED) + return SPELL_FAILED_ITEM_NOT_READY; + + if (!m_IsTriggeredSpell) + if (my_trade->GetSpell()) + return SPELL_FAILED_ITEM_ALREADY_ENCHANTED; + } + // all ok return SPELL_CAST_OK; } @@ -5892,7 +5991,7 @@ SpellCastResult Spell::CheckItems() else if (!(p_caster->HasItemCount(m_spellInfo->EffectItemType[i],1))) return SPELL_FAILED_TOO_MANY_OF_ITEM; else - p_caster->CastSpell(m_caster,m_spellInfo->CalculateSimpleValue(1),false); // move this to anywhere + p_caster->CastSpell(m_caster,SpellMgr::CalculateSpellEffectAmount(m_spellInfo, 1),false); // move this to anywhere return SPELL_FAILED_DONT_REPORT; } } @@ -6346,6 +6445,8 @@ bool Spell::CheckTarget(Unit* target, uint32 eff) case SPELL_AURA_AOE_CHARM: if (target->GetTypeId() == TYPEID_UNIT && target->IsVehicle()) return false; + if (target->IsMounted()) + return false; if (target->GetCharmerGUID()) return false; if (int32 damage = CalculateDamage(eff, target)) @@ -6687,8 +6788,9 @@ int32 Spell::CalculateDamageDone(Unit *unit, const uint32 effectMask, float *mul { if (IsAreaEffectTarget[m_spellInfo->EffectImplicitTargetA[i]] || IsAreaEffectTarget[m_spellInfo->EffectImplicitTargetB[i]]) { - if (int32 reducedPct = unit->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE)) - m_damage = m_damage * (100 + reducedPct) / 100; + m_damage = float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask); + if (m_caster->GetTypeId() == TYPEID_UNIT) + m_damage = float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask); if (m_caster->GetTypeId() == TYPEID_PLAYER) { @@ -6748,8 +6850,8 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk if (skillId != SKILL_NONE) { // skill bonus provided by casting spell (mostly item spells) - // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) (use m_currentBasePoints, CalculateDamage returns wrong value) - uint32 spellSkillBonus = uint32(m_currentBasePoints[effIndex]); + // add the damage modifier from the spell casted (cheat lock / skeleton key etc.) + uint32 spellSkillBonus = uint32(CalculateDamage(effIndex, NULL)); reqSkillValue = lockInfo->Skill[j]; // castitem check: rogue using skeleton keys. the skill values should not be added in this case. @@ -6778,15 +6880,15 @@ void Spell::SetSpellValue(SpellValueMod mod, int32 value) switch(mod) { case SPELLVALUE_BASE_POINT0: - m_spellValue->EffectBasePoints[0] = value - int32(1); + m_spellValue->EffectBasePoints[0] = SpellMgr::CalculateSpellEffectBaseAmount(value); m_currentBasePoints[0] = m_spellValue->EffectBasePoints[0]; //this should be removed in the future break; case SPELLVALUE_BASE_POINT1: - m_spellValue->EffectBasePoints[1] = value - int32(1); + m_spellValue->EffectBasePoints[1] = SpellMgr::CalculateSpellEffectBaseAmount(value); m_currentBasePoints[1] = m_spellValue->EffectBasePoints[1]; break; case SPELLVALUE_BASE_POINT2: - m_spellValue->EffectBasePoints[2] = value - int32(1); + m_spellValue->EffectBasePoints[2] = SpellMgr::CalculateSpellEffectBaseAmount(value); m_currentBasePoints[2] = m_spellValue->EffectBasePoints[2]; break; case SPELLVALUE_RADIUS_MOD: |
