Core/Spells: Named and implemented most of SpellAttr8
This commit is contained in:
1 parent
1dfe0f0974
commit
388c504047
14 files changed
+248
-153
No files matched your search
@@ -3103,7 +3103,10 @@ bool WorldObject::IsValidAttackTarget(WorldObject const* target, SpellInfo const
|
||||
|
||||
// PvP case - can't attack when attacker or target are in sanctuary
|
||||
// however, 13850 client doesn't allow to attack when one of the unit's has sanctuary flag and is pvp
|
||||
if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && unitOrOwner && unitOrOwner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && (unitTarget->IsInSanctuary() || unitOrOwner->IsInSanctuary()))
|
||||
if (unitTarget && unitTarget->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)
|
||||
&& unitOrOwner && unitOrOwner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED)
|
||||
&& (unitTarget->IsInSanctuary() || unitOrOwner->IsInSanctuary())
|
||||
&& (!bySpell || bySpell->HasAttribute(SPELL_ATTR8_IGNORE_SANCTUARY)))
|
||||
return false;
|
||||
|
||||
// additional checks - only PvP case
|
||||
@@ -3206,8 +3209,8 @@ bool WorldObject::IsValidAssistTarget(WorldObject const* target, SpellInfo const
|
||||
return false;
|
||||
|
||||
// can't assist player out of sanctuary from sanctuary if has pvp enabled
|
||||
if (unitTarget->IsPvP())
|
||||
if (unit && unit->IsInSanctuary() && !unitTarget->IsInSanctuary())
|
||||
if (unitTarget->IsPvP() && (!bySpell || bySpell->HasAttribute(SPELL_ATTR8_IGNORE_SANCTUARY)))
|
||||
if (unit->IsInSanctuary() && !unitTarget->IsInSanctuary())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3127,7 +3127,7 @@ bool Player::HandlePassiveSpellLearn(SpellInfo const* spellInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR8_MASTERY_SPECIALIZATION))
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR8_MASTERY_AFFECTS_POINTS))
|
||||
need_cast &= IsCurrentSpecMasterySpell(spellInfo);
|
||||
|
||||
//Check CasterAuraStates
|
||||
@@ -26941,7 +26941,7 @@ void Player::UpdateArmorSpecialization()
|
||||
for (AuraApplicationMap::iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
|
||||
{
|
||||
SpellInfo const* spell = itr->second->GetBase()->GetSpellInfo();
|
||||
if (spell->AttributesEx8 & SPELL_ATTR8_ARMOR_SPECIALIZATION)
|
||||
if (spell->AttributesEx8 & SPELL_ATTR8_REQUIRES_EQUIPPED_INV_TYPES)
|
||||
RemoveAura(itr);
|
||||
else
|
||||
++itr;
|
||||
|
||||
@@ -2305,7 +2305,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit* victim, SpellInfo const* spellInfo
|
||||
|
||||
bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_DODGE);
|
||||
bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_PARRY);
|
||||
bool canBlock = !spellInfo->HasAttribute(SPELL_ATTR8_CANT_BLOCK);
|
||||
bool canBlock = !spellInfo->HasAttribute(SPELL_ATTR8_NO_ATTACK_BLOCK);
|
||||
|
||||
// if victim is casting or cc'd it can't avoid attacks
|
||||
bool canUseDefenseWhileChanneling = victim->GetCurrentSpell(CURRENT_CHANNELED_SPELL) ? victim->GetCurrentSpell(CURRENT_CHANNELED_SPELL)->GetSpellInfo()->HasAttribute(SPELL_ATTR10_ALLOW_DEFENSE_WHILE_CHANNELING) : false;
|
||||
@@ -14277,7 +14277,7 @@ float Unit::GetCollisionHeight() const
|
||||
return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
|
||||
}
|
||||
|
||||
SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const
|
||||
SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag) const
|
||||
{
|
||||
Unit::AuraEffectList swaps = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS);
|
||||
Unit::AuraEffectList const& swaps2 = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED);
|
||||
@@ -14287,8 +14287,15 @@ SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const
|
||||
for (AuraEffect const* auraEffect : swaps)
|
||||
{
|
||||
if (uint32(auraEffect->GetMiscValue()) == spellInfo->Id || auraEffect->IsAffectingSpell(spellInfo))
|
||||
{
|
||||
if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount()))
|
||||
{
|
||||
if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST))
|
||||
triggerFlag |= TRIGGERED_IGNORE_POWER_AND_REAGENT_COST;
|
||||
|
||||
return newInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return spellInfo;
|
||||
@@ -14403,7 +14410,9 @@ void Unit::ProcessPendingSpellCastRequest()
|
||||
}
|
||||
}
|
||||
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->IsRaidMarker() &&
|
||||
TriggerCastFlags triggerFlag = TRIGGERED_NONE;
|
||||
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->HasAttribute(SPELL_ATTR8_SKIP_IS_KNOWN_CHECK) &&
|
||||
!caster->ToPlayer()->HasArchProject(static_cast<uint16>(spellInfo->ResearchProjectId)))
|
||||
{
|
||||
bool allow = false;
|
||||
@@ -14431,7 +14440,7 @@ void Unit::ProcessPendingSpellCastRequest()
|
||||
}
|
||||
|
||||
// Check possible spell cast overrides
|
||||
spellInfo = caster->GetCastSpellInfo(spellInfo);
|
||||
spellInfo = caster->GetCastSpellInfo(spellInfo, triggerFlag);
|
||||
|
||||
// can't use our own spells when we're in possession of another unit,
|
||||
if (caster->isPossessing())
|
||||
@@ -14493,7 +14502,7 @@ void Unit::ProcessPendingSpellCastRequest()
|
||||
player->SetArchData(archaeologyCastData);
|
||||
}
|
||||
|
||||
Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE);
|
||||
Spell* spell = new Spell(caster, spellInfo, triggerFlag);
|
||||
spell->m_cast_count = _pendingSpellCastRequest->CastRequest.CastID; // set count of casts
|
||||
spell->m_glyphIndex = _pendingSpellCastRequest->CastRequest.Misc;
|
||||
spell->prepare(targets);
|
||||
|
||||
@@ -1438,7 +1438,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
Spell* GetCurrentSpell(uint32 spellType) const { return m_currentSpells[spellType]; }
|
||||
Spell* FindCurrentSpellBySpellId(uint32 spell_id) const;
|
||||
int32 GetCurrentSpellCastTime(uint32 spell_id) const;
|
||||
SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const;
|
||||
SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag) const;
|
||||
|
||||
virtual bool HasSpellFocus(Spell const* /*focusSpell*/ = nullptr) const { return false; }
|
||||
virtual bool IsMovementPreventedByCasting() const;
|
||||
|
||||
@@ -646,40 +646,40 @@ enum SpellAttr7 : uint32
|
||||
SPELL_ATTR7_ALWAYS_CAST_LOG = 0x80000000 // TITLE Always Cast Log
|
||||
};
|
||||
|
||||
enum SpellAttr8
|
||||
enum SpellAttr8 : uint32
|
||||
{
|
||||
SPELL_ATTR8_CANT_BLOCK = 0x00000001, // 0 No Attack Block
|
||||
SPELL_ATTR8_UNK1 = 0x00000002, // 1
|
||||
SPELL_ATTR8_UNK2 = 0x00000004, // 2
|
||||
SPELL_ATTR8_UNK3 = 0x00000008, // 3
|
||||
SPELL_ATTR8_UNK4 = 0x00000010, // 4
|
||||
SPELL_ATTR8_UNK5 = 0x00000020, // 5
|
||||
SPELL_ATTR8_UNK6 = 0x00000040, // 6
|
||||
SPELL_ATTR8_UNK7 = 0x00000080, // 7
|
||||
SPELL_ATTR8_AFFECT_PARTY_AND_RAID = 0x00000100, // 8 Nearly all spells have "all party and raid" in description
|
||||
SPELL_ATTR8_PERIODIC_CAN_CRIT = 0x00000200, // 9 Periodic Can Crit
|
||||
SPELL_ATTR8_NAME_CHANGED_DURING_TRANSFORM = 0x00000400, // 10 according to wowhead comments, name changes, title remains
|
||||
SPELL_ATTR8_UNK11 = 0x00000800, // 11
|
||||
SPELL_ATTR8_AURA_SEND_AMOUNT = 0x00001000, // 12 Aura must have flag AFLAG_ANY_EFFECT_AMOUNT_SENT to send amount
|
||||
SPELL_ATTR8_UNK13 = 0x00002000, // 13
|
||||
SPELL_ATTR8_UNK14 = 0x00004000, // 14
|
||||
SPELL_ATTR8_WATER_MOUNT = 0x00008000, // 15 only one River Boat used in Thousand Needles
|
||||
SPELL_ATTR8_UNK16 = 0x00010000, // 16
|
||||
SPELL_ATTR8_HASTE_AFFECTS_DURATION = 0x00020000, // 17 Haste Affects Duration
|
||||
SPELL_ATTR8_REMEMBER_SPELLS = 0x00040000, // 18 at some point in time, these auras remember spells and allow to cast them later
|
||||
SPELL_ATTR8_USE_COMBO_POINTS_ON_ANY_TARGET = 0x00080000, // 19 allows to consume combo points from dead targets
|
||||
SPELL_ATTR8_ARMOR_SPECIALIZATION = 0x00100000, // 20
|
||||
SPELL_ATTR8_UNK21 = 0x00200000, // 21
|
||||
SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC = 0x00400000, // 22 Melee Haste Affects Periodic
|
||||
SPELL_ATTR8_BATTLE_RESURRECTION = 0x00800000, // 23 Used to limit the Amount of Resurrections in Boss Encounters
|
||||
SPELL_ATTR8_HEAL_PREDICTION = 0x01000000, // 24 Displays a predicted health amount on the targets frame
|
||||
SPELL_ATTR8_UNK25 = 0x02000000, // 25
|
||||
SPELL_ATTR8_RAID_MARKER = 0x04000000, // 26 probably spell no need learn to cast
|
||||
SPELL_ATTR8_AI_FACE_TARGET = 0x08000000, // 27 AI Face Target
|
||||
SPELL_ATTR8_NOT_IN_BG_OR_ARENA = 0x10000000, // 28 not allow to cast or deactivate currently active effect, not sure about Fast Track
|
||||
SPELL_ATTR8_MASTERY_SPECIALIZATION = 0x20000000, // 29
|
||||
SPELL_ATTR8_UNK30 = 0x40000000, // 30
|
||||
SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG = 0x80000000 // 31 Do not check UNIT_FLAG_IMMUNE_TO_PC in IsValidAttackTarget
|
||||
SPELL_ATTR8_NO_ATTACK_BLOCK = 0x00000001, // TITLE No Attack Block
|
||||
SPELL_ATTR8_IGNORE_DYNAMIC_OBJECT_CASTER = 0x00000002, /*NYI*/ // TITLE Ignore Dynamic Object Caster
|
||||
SPELL_ATTR8_REMOVE_OUTSIDE_DUNGEONS_AND_RAIDS = 0x00000004, // TITLE Remove Outside Dungeons and Raids
|
||||
SPELL_ATTR8_ONLY_TARGET_IF_SAME_CREATOR = 0x00000008, // TITLE Only Target If Same Creator
|
||||
SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE = 0x00000010, /*NYI - no aoe immunity implementation*/ // TITLE Can Hit AOE Untargetable
|
||||
SPELL_ATTR8_ALLOW_WHILE_CHARMED = 0x00000020, /*NYI - not implementable currently, charming replaces AI*/ // TITLE Allow While Charmed
|
||||
SPELL_ATTR8_AURA_REQUIRED_BY_CLIENT = 0x00000040, /*NYI - we send all auras to client*/ // TITLE Aura Required by Client
|
||||
SPELL_ATTR8_IGNORE_SANCTUARY = 0x00000080, // TITLE Ignore Sanctuary
|
||||
SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING = 0x00000100, // TITLE Use Target's Level for Spell Scaling
|
||||
SPELL_ATTR8_PERIODIC_CAN_CRIT = 0x00000200, // TITLE Periodic Can Crit
|
||||
SPELL_ATTR8_MIRROR_CREATURE_NAME = 0x00000400, // TITLE Mirror creature name DESCRIPTION Transform auras also override name (handled clientside)
|
||||
SPELL_ATTR8_ONLY_PLAYERS_CAN_CAST_THIS_SPELL = 0x00000800, // TITLE Only Players Can Cast This Spell
|
||||
SPELL_ATTR8_AURA_POINTS_ON_CLIENT = 0x00001000, // TITLE Aura Points On Client
|
||||
SPELL_ATTR8_NOT_IN_SPELLBOOK_UNTIL_LEARNED = 0x00002000, // TITLE Not In Spellbook Until Learned DESCRIPTION Hides autolearned spell from spellbook before learning (handled clientside)
|
||||
SPELL_ATTR8_TARGET_PROCS_ON_CASTER = 0x00004000, // TITLE Target Procs On Caster DESCRIPTION Target (taken) procs happen on caster (actor) instead of aura target (action target)
|
||||
SPELL_ATTR8_REQUIRES_LOCATION_TO_BE_ON_LIQUID_SURFACE = 0x00008000, // TITLE Requires location to be on liquid surface
|
||||
SPELL_ATTR8_ONLY_TARGET_OWN_SUMMONS = 0x00010000, // TITLE Only Target Own Summons
|
||||
SPELL_ATTR8_HASTE_AFFECTS_DURATION = 0x00020000, // TITLE Haste Affects Duration
|
||||
SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST = 0x00040000, // TTILE Ignore Spellcast Override Cost
|
||||
SPELL_ATTR8_ALLOW_TARGETS_HIDDEN_BY_SPAWN_TRACKING = 0x00080000, /*NYI - no spawn tracking implementation*/ // TITLE Allow Targets Hidden by Spawn Tracking
|
||||
SPELL_ATTR8_REQUIRES_EQUIPPED_INV_TYPES = 0x00100000, // TITLE Requires Equipped Inv Types
|
||||
SPELL_ATTR8_NO_SUMMON_DEST_FROM_CLIENT_TARGETING_PATHING_REQUIREMENT = 0x00200000, /*NYI - vald path to a spell dest is not required currently if the dest comes from client*/ // TITLE No 'Summon + Dest from Client' Targeting Pathing Requirement
|
||||
SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC = 0x00400000, // TITLE Melee Haste Affects Periodic
|
||||
SPELL_ATTR8_ENFORCE_IN_COMBAT_RESSURECTION_LIMIT = 0x00800000, // TITLE Enforce In Combat Ressurection Limit DESCRIPTION Used to limit the number of resurrections in boss encounters
|
||||
SPELL_ATTR8_HEAL_PREDICTION = 0x01000000, // TITLE Heal Prediction
|
||||
SPELL_ATTR8_NO_LEVEL_UP_TOAST = 0x02000000, // TITLE No Level Up Toast
|
||||
SPELL_ATTR8_SKIP_IS_KNOWN_CHECK = 0x04000000, // TITLE Skip Is Known Check
|
||||
SPELL_ATTR8_AI_FACE_TARGET = 0x08000000, /*NYI - unknown facing conditions, needs research*/ // TITLE AI Face Target
|
||||
SPELL_ATTR8_NOT_IN_BATTLEGROUND = 0x10000000, // TITLE Not in Battleground
|
||||
SPELL_ATTR8_MASTERY_AFFECTS_POINTS = 0x20000000, // TITLE Mastery Affects Points
|
||||
SPELL_ATTR8_DISPLAY_LARGE_AURA_ICON_ON_UNIT_FRAMES_BOSS_AURA = 0x40000000, // TITLE Display Large Aura Icon On Unit Frames (Boss Aura)
|
||||
SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG = 0x80000000 // TITLE Can Attack ImmunePC DESCRIPTION Do not check UNIT_FLAG_IMMUNE_TO_PC in IsValidAttackTarget
|
||||
};
|
||||
|
||||
enum SpellAttr9
|
||||
|
||||
@@ -23,7 +23,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::SpellHealPredicti
|
||||
{
|
||||
data << int32(predict.Points);
|
||||
data << uint8(predict.Type);
|
||||
if (predict.BeaconGUID.has_value())
|
||||
if (predict.Type == SPELL_HEAL_PREDICTION_TARGET_AND_BEACON)
|
||||
data << predict.BeaconGUID->WriteAsPacked();
|
||||
return data;
|
||||
}
|
||||
@@ -193,22 +193,22 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::TargetedHealPredi
|
||||
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Spells::ChannelStartInterruptImmunities const& immunity)
|
||||
{
|
||||
data << immunity.SchoolImmunities;
|
||||
data << immunity.Immunities;
|
||||
data << int32(immunity.SchoolImmunities);
|
||||
data << int32(immunity.Immunities);
|
||||
return data;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Spells::ChannelStart::Write()
|
||||
{
|
||||
_worldPacket << CasterGUID.WriteAsPacked();
|
||||
_worldPacket << uint32(SpellID);
|
||||
_worldPacket << int32(ChannelDuration);
|
||||
_worldPacket << int32(SpellID);
|
||||
_worldPacket << uint32(ChannelDuration);
|
||||
|
||||
_worldPacket << uint8(InterruptImmunities.has_value());
|
||||
_worldPacket << bool(InterruptImmunities.has_value());
|
||||
if (InterruptImmunities)
|
||||
_worldPacket << *InterruptImmunities;
|
||||
|
||||
_worldPacket << uint8(HealPrediction.has_value());
|
||||
_worldPacket << bool(HealPrediction.has_value());
|
||||
if (HealPrediction)
|
||||
_worldPacket << *HealPrediction;
|
||||
|
||||
|
||||
@@ -129,9 +129,6 @@ namespace WorldPackets
|
||||
|
||||
struct TargetedHealPrediction
|
||||
{
|
||||
TargetedHealPrediction() { }
|
||||
TargetedHealPrediction(ObjectGuid targetGuid, SpellHealPrediction prediction) : TargetGUID(targetGuid), Predict(prediction) { }
|
||||
|
||||
ObjectGuid TargetGUID;
|
||||
SpellHealPrediction Predict;
|
||||
};
|
||||
|
||||
@@ -483,7 +483,7 @@ int32 AuraEffect::CalculateAmount(Unit* caster)
|
||||
// default amount calculation
|
||||
int32 amount = 0;
|
||||
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR8_MASTERY_SPECIALIZATION) || G3D::fuzzyEq(m_spellInfo->Effects[m_effIndex].BonusMultiplier, 0.0f))
|
||||
if (!m_spellInfo->HasAttribute(SPELL_ATTR8_MASTERY_AFFECTS_POINTS) || G3D::fuzzyEq(m_spellInfo->Effects[m_effIndex].BonusMultiplier, 0.0f))
|
||||
amount = m_spellInfo->Effects[m_effIndex].CalcValue(caster, &m_baseAmount, GetBase()->GetOwner()->ToUnit());
|
||||
else if (caster && caster->GetTypeId() == TYPEID_PLAYER)
|
||||
amount = int32(caster->GetFloatValue(PLAYER_MASTERY) * m_spellInfo->Effects[m_effIndex].BonusMultiplier);
|
||||
@@ -770,7 +770,7 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply)
|
||||
HandleEffect(aurApp, handleMask, true);
|
||||
}
|
||||
|
||||
if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT) || Aura::EffectTypeNeedsSendingAmount(GetAuraType()))
|
||||
if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT) || Aura::EffectTypeNeedsSendingAmount(GetAuraType()))
|
||||
GetBase()->SetNeedClientUpdateForTargets();
|
||||
}
|
||||
|
||||
@@ -1318,7 +1318,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
|
||||
if (!spellInfo || !(spellInfo->IsPassive() || spellInfo->HasAttribute(SPELL_ATTR0_DO_NOT_DISPLAY_SPELLBOOK_AURA_ICON_COMBAT_LOG)))
|
||||
continue;
|
||||
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR8_MASTERY_SPECIALIZATION) && !plrTarget->IsCurrentSpecMasterySpell(spellInfo))
|
||||
if (spellInfo->HasAttribute(SPELL_ATTR8_MASTERY_AFFECTS_POINTS) && !plrTarget->IsCurrentSpecMasterySpell(spellInfo))
|
||||
continue;
|
||||
|
||||
if (spellInfo->Stances & (UI64LIT(1) << (GetMiscValue() - 1)))
|
||||
@@ -6245,6 +6245,8 @@ void AuraEffect::HandleProcTriggerSpellAuraProc(AuraApplication* aurApp, ProcEve
|
||||
{
|
||||
Unit* triggerCaster = aurApp->GetTarget();
|
||||
Unit* triggerTarget = eventInfo.GetProcTarget();
|
||||
if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_TARGET_PROCS_ON_CASTER) && eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK)
|
||||
triggerTarget = eventInfo.GetActor();
|
||||
|
||||
uint32 triggerSpellId = GetSpellInfo()->Effects[GetEffIndex()].TriggerSpell;
|
||||
if (SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(triggerSpellId))
|
||||
@@ -6260,6 +6262,9 @@ void AuraEffect::HandleProcTriggerSpellCopyAuraProc(AuraApplication* aurApp, Pro
|
||||
{
|
||||
Unit* triggerCaster = aurApp->GetTarget();
|
||||
Unit* triggerTarget = eventInfo.GetProcTarget();
|
||||
if (GetSpellInfo()->HasAttribute(SPELL_ATTR8_TARGET_PROCS_ON_CASTER) && eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK)
|
||||
triggerTarget = eventInfo.GetActor();
|
||||
|
||||
SpellInfo const* triggeredSpellInfo = eventInfo.GetSpellInfo();
|
||||
if (!triggeredSpellInfo)
|
||||
return;
|
||||
|
||||
@@ -173,7 +173,7 @@ void AuraApplication::_InitFlags(Unit* caster, uint8 effMask)
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT) || effectNeedsAmount)
|
||||
if (GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT) || effectNeedsAmount)
|
||||
_flags |= AFLAG_SCALABLE;
|
||||
}
|
||||
|
||||
|
||||
@@ -918,6 +918,22 @@ void Spell::SelectSpellTargets()
|
||||
}
|
||||
}
|
||||
|
||||
if (m_targets.HasDst())
|
||||
{
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_REQUIRES_LOCATION_TO_BE_ON_LIQUID_SURFACE))
|
||||
{
|
||||
ZLiquidStatus status = m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseShift(),
|
||||
m_targets.GetDstPos()->GetPositionX(), m_targets.GetDstPos()->GetPositionY(), m_targets.GetDstPos()->GetPositionZ(),
|
||||
map_liquidHeaderTypeFlags::AllLiquids);
|
||||
if (!(status & (LIQUID_MAP_WATER_WALK | LIQUID_MAP_IN_WATER)))
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_NO_LIQUID);
|
||||
finish(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uint64 dstDelay = CalculateDelayMomentForDst())
|
||||
m_delayMoment = dstDelay;
|
||||
}
|
||||
@@ -2583,7 +2599,7 @@ void Spell::TargetInfo::DoTargetSpellHit(Spell* spell, uint8 effIndex)
|
||||
if (unit->IsAlive() != IsAlive)
|
||||
return;
|
||||
|
||||
if (spell->getState() == SPELL_STATE_DELAYED && !spell->IsPositive() && (GameTime::GetGameTimeMS() - TimeDelay) <= unit->m_lastSanctuaryTime)
|
||||
if (!spell->m_spellInfo->HasAttribute(SPELL_ATTR8_IGNORE_SANCTUARY) && spell->getState() == SPELL_STATE_DELAYED && !spell->IsPositive() && (GameTime::GetGameTimeMS() - TimeDelay) <= unit->m_lastSanctuaryTime)
|
||||
return; // No missinfo in that case
|
||||
|
||||
if (_spellHitTarget)
|
||||
@@ -4476,9 +4492,8 @@ void Spell::SendSpellStart()
|
||||
if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNE)
|
||||
castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION))
|
||||
if (m_casttime || m_spellInfo->HasAura(SPELL_AURA_PERIODIC_HEAL))
|
||||
castFlags |= CAST_FLAG_HEAL_PREDICTION;
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION) && m_casttime && m_caster->IsUnit())
|
||||
castFlags |= CAST_FLAG_HEAL_PREDICTION;
|
||||
|
||||
WorldPackets::Spells::SpellStart packet;
|
||||
WorldPackets::Spells::SpellCastData& castData = packet.Cast;
|
||||
@@ -4541,7 +4556,7 @@ void Spell::SendSpellStart()
|
||||
}
|
||||
|
||||
if (castFlags & CAST_FLAG_HEAL_PREDICTION)
|
||||
UpdateSpellHealPrediction(castData.Predict.emplace());
|
||||
UpdateSpellHealPrediction(castData.Predict.emplace(), false);
|
||||
|
||||
m_caster->SendMessageToSet(packet.Write(), true);
|
||||
}
|
||||
@@ -4782,63 +4797,83 @@ void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo)
|
||||
ammo.InventoryType = ammoInventoryType;
|
||||
}
|
||||
|
||||
void Spell::UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& predict)
|
||||
static std::pair<int32, SpellHealPredictionType> CalcPredictedHealing(SpellInfo const* spellInfo, Unit const* unitCaster, Unit* target, Spell* spell, bool withPeriodic)
|
||||
{
|
||||
Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : m_caster->ToUnit();
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
predict.Type = 0;
|
||||
|
||||
/*
|
||||
* @todo: implement
|
||||
if (AuraEffect const* beaconOfLightEffect = m_caster->GetDummyAuraEffect(SPELLFAMILY_PALADIN, 3032, EFFECT_0))
|
||||
int32 points = 0;
|
||||
SpellHealPredictionType type = SPELL_HEAL_PREDICTION_TARGET;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
{
|
||||
if (beaconOfLightEffect->GetCasterGUID() == m_caster->GetGUID())
|
||||
SpellEffectInfo const& spellEffectInfo = spellInfo->Effects[i];
|
||||
switch (spellEffectInfo.Effect)
|
||||
{
|
||||
predict.Type = 2;
|
||||
predict.BeaconGUID = beaconOfLightEffect->GetBase()->GetUnitOwner()->GetGUID();
|
||||
case SPELL_EFFECT_HEAL:
|
||||
case SPELL_EFFECT_HEAL_PCT:
|
||||
points += unitCaster->SpellHealingBonusDone(target,
|
||||
spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target),
|
||||
DIRECT_DAMAGE, i, 1, spell);
|
||||
|
||||
if (target != unitCaster && (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER || spellEffectInfo.TargetB.GetTarget() == TARGET_UNIT_CASTER))
|
||||
type = SPELL_HEAL_PREDICTION_TARGET_AND_CASTER; // Binding Heal-like spells
|
||||
else if (spellEffectInfo.TargetA.GetCheckType() == TARGET_CHECK_PARTY || spellEffectInfo.TargetB.GetCheckType() == TARGET_CHECK_PARTY)
|
||||
type = SPELL_HEAL_PREDICTION_TARGET_PARTY; // Prayer of Healing (old party-wide targeting)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (Unit* unitCaster = m_caster->ToUnit())
|
||||
{
|
||||
for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex)
|
||||
|
||||
if (withPeriodic)
|
||||
{
|
||||
SpellEffectInfo const& effect = m_spellInfo->Effects[effIndex];
|
||||
if (!effect.IsEffect())
|
||||
continue;
|
||||
|
||||
switch (effect.Effect)
|
||||
switch (spellEffectInfo.ApplyAuraName)
|
||||
{
|
||||
case SPELL_EFFECT_HEAL:
|
||||
case SPELL_EFFECT_HEAL_PCT:
|
||||
predict.Points += unitCaster->SpellHealingBonusDone(target, m_spellInfo, effect.CalcValue(unitCaster, nullptr, target), HEAL, effIndex);
|
||||
case SPELL_AURA_PERIODIC_HEAL:
|
||||
case SPELL_AURA_OBS_MOD_HEALTH:
|
||||
points += unitCaster->SpellHealingBonusDone(target,
|
||||
spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target),
|
||||
DIRECT_DAMAGE, i, 1, spell) * spellInfo->GetMaxTicks();
|
||||
break;
|
||||
case SPELL_EFFECT_APPLY_AURA:
|
||||
{
|
||||
switch (effect.ApplyAuraName)
|
||||
{
|
||||
case SPELL_AURA_PERIODIC_HEAL:
|
||||
predict.Points += unitCaster->SpellHealingBonusDone(target, m_spellInfo, effect.CalcValue(unitCaster, nullptr, target), HEAL, effIndex) * m_spellInfo->GetMaxTicks();
|
||||
break;
|
||||
case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
|
||||
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(effect.TriggerSpell))
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (spell->Effects[i].Effect == SPELL_EFFECT_HEAL || spell->Effects[i].Effect == SPELL_EFFECT_HEAL_PCT)
|
||||
predict.Points += unitCaster->SpellHealingBonusDone(target, spell, spell->Effects[i].CalcValue(unitCaster, nullptr, target), HEAL, i) * m_spellInfo->GetMaxTicks();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
|
||||
if (SpellInfo const* triggered = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell))
|
||||
points += CalcPredictedHealing(triggered, unitCaster, target, nullptr, withPeriodic).first;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { points, type };
|
||||
}
|
||||
|
||||
void Spell::UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& healPrediction, bool withPeriodic)
|
||||
{
|
||||
healPrediction.BeaconGUID = ObjectGuid::Empty;
|
||||
healPrediction.Points = 0;
|
||||
healPrediction.Type = SPELL_HEAL_PREDICTION_TARGET;
|
||||
|
||||
Unit const* unitCaster = m_caster->ToUnit();
|
||||
|
||||
if (Unit* target = m_targets.GetUnitTarget())
|
||||
{
|
||||
auto [points, type] = CalcPredictedHealing(m_spellInfo, unitCaster, target, this, withPeriodic);
|
||||
healPrediction.Points = points;
|
||||
healPrediction.Type = type;
|
||||
}
|
||||
|
||||
static constexpr uint32 beaconSpellId = 53651;
|
||||
|
||||
if (healPrediction.Type == SPELL_HEAL_PREDICTION_TARGET && unitCaster->HasAura(beaconSpellId, unitCaster->GetGUID()))
|
||||
{
|
||||
auto beacon = std::find_if(unitCaster->GetSingleCastAuras().begin(), unitCaster->GetSingleCastAuras().end(), [](Aura const* aura)
|
||||
{
|
||||
return aura->GetSpellInfo()->Effects[EFFECT_1].IsEffect() && aura->GetSpellInfo()->Effects[EFFECT_1].TriggerSpell == beaconSpellId;
|
||||
});
|
||||
|
||||
if (beacon != unitCaster->GetSingleCastAuras().end())
|
||||
{
|
||||
healPrediction.BeaconGUID = (*beacon)->GetOwner()->GetGUID();
|
||||
healPrediction.Type = SPELL_HEAL_PREDICTION_TARGET_AND_BEACON;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::SendLogExecute()
|
||||
@@ -5024,26 +5059,7 @@ void Spell::SendChannelStart(uint32 duration)
|
||||
if (!unitCaster)
|
||||
return;
|
||||
|
||||
WorldPackets::Spells::ChannelStart packet;
|
||||
packet.CasterGUID = m_caster->GetGUID();
|
||||
packet.SpellID = m_spellInfo->Id;
|
||||
packet.ChannelDuration = duration;
|
||||
|
||||
uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
|
||||
uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
|
||||
uint32 mechanicImmunityMask = m_spellInfo->GetMechanicImmunityMask(unitCaster);
|
||||
|
||||
if (schoolImmunityMask || mechanicImmunityMask)
|
||||
castFlags |= CAST_FLAG_IMMUNITY;
|
||||
|
||||
if (castFlags & CAST_FLAG_IMMUNITY)
|
||||
{
|
||||
packet.InterruptImmunities.emplace();
|
||||
packet.InterruptImmunities->SchoolImmunities = schoolImmunityMask; // CastSchoolImmunities
|
||||
packet.InterruptImmunities->Immunities = mechanicImmunityMask; // CastImmunities
|
||||
}
|
||||
|
||||
m_timer = duration;
|
||||
m_timer = duration;
|
||||
|
||||
if (!m_targets.HasDst())
|
||||
{
|
||||
@@ -5086,22 +5102,37 @@ void Spell::SendChannelStart(uint32 duration)
|
||||
else if (m_spellInfo->HasAttribute(SPELL_ATTR1_IS_SELF_CHANNELLED))
|
||||
unitCaster->SetChannelObjectGuid(unitCaster->GetGUID());
|
||||
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION))
|
||||
{
|
||||
castFlags |= CAST_FLAG_HEAL_PREDICTION;
|
||||
|
||||
WorldPackets::Spells::SpellHealPrediction predict;
|
||||
UpdateSpellHealPrediction(predict);
|
||||
packet.HealPrediction.emplace(unitCaster->GetChannelObjectGuid(), predict);
|
||||
}
|
||||
|
||||
m_caster->SendMessageToSet(packet.Write(), true);
|
||||
m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, m_spellInfo->Id);
|
||||
|
||||
if (Creature* creatureCaster = m_caster->ToCreature())
|
||||
if (!creatureCaster->HasSpellFocus(this))
|
||||
creatureCaster->SetSpellFocus(this, nullptr);
|
||||
|
||||
WorldPackets::Spells::ChannelStart packet;
|
||||
packet.CasterGUID = m_caster->GetGUID();
|
||||
packet.SpellID = m_spellInfo->Id;
|
||||
packet.ChannelDuration = duration;
|
||||
|
||||
uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
|
||||
uint32 mechanicImmunityMask = m_spellInfo->GetMechanicImmunityMask(unitCaster);
|
||||
|
||||
if (schoolImmunityMask || mechanicImmunityMask)
|
||||
{
|
||||
packet.InterruptImmunities.emplace();
|
||||
packet.InterruptImmunities->SchoolImmunities = schoolImmunityMask; // CastSchoolImmunities
|
||||
packet.InterruptImmunities->Immunities = mechanicImmunityMask; // CastImmunities
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION) && m_caster->IsUnit())
|
||||
{
|
||||
WorldPackets::Spells::TargetedHealPrediction& healPrediction = packet.HealPrediction.emplace();
|
||||
if (!unitCaster->GetChannelObjectGuid().IsEmpty() && unitCaster->GetChannelObjectGuid().IsUnit())
|
||||
healPrediction.TargetGUID = unitCaster->GetChannelObjectGuid();
|
||||
|
||||
UpdateSpellHealPrediction(healPrediction.Predict, true);
|
||||
}
|
||||
|
||||
m_caster->SendMessageToSet(packet.Write(), true);
|
||||
}
|
||||
|
||||
void Spell::SendResurrectRequest(Player* target)
|
||||
@@ -5648,6 +5679,9 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
|
||||
return SPELL_FAILED_CUSTOM_ERROR;
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_ONLY_PLAYERS_CAN_CAST_THIS_SPELL) && !m_caster->IsPlayer())
|
||||
return SPELL_FAILED_CASTER_AURASTATE;
|
||||
|
||||
// Check global cooldown
|
||||
if (strict && !(_triggeredCastFlags & TRIGGERED_IGNORE_GCD) && HasGlobalCooldown())
|
||||
return !m_spellInfo->HasAttribute(SPELL_ATTR0_COOLDOWN_ON_EVENT) ? SPELL_FAILED_NOT_READY : SPELL_FAILED_DONT_REPORT;
|
||||
@@ -5669,7 +5703,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
|
||||
return SPELL_FAILED_ONLY_INDOORS;
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_BATTLE_RESURRECTION) && m_caster->GetMap()->IsRaid())
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_ENFORCE_IN_COMBAT_RESSURECTION_LIMIT) && m_caster->GetMap()->IsRaid())
|
||||
if (InstanceScript* instance = m_caster->GetInstanceScript())
|
||||
if (instance->IsEncounterInProgress())
|
||||
if (!instance->GetCombatResurrectionCharges())
|
||||
@@ -7851,7 +7885,7 @@ bool Spell::IsPositive() const
|
||||
bool Spell::IsNeedSendToClient() const
|
||||
{
|
||||
return m_spellInfo->SpellVisual[0] || m_spellInfo->SpellVisual[1] || m_spellInfo->IsChanneled() ||
|
||||
m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT) || m_spellInfo->Speed > 0.0f || (!m_triggeredByAuraSpell && !IsTriggered()) ||
|
||||
m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT) || m_spellInfo->Speed > 0.0f || (!m_triggeredByAuraSpell && !IsTriggered()) ||
|
||||
m_spellInfo->HasAttribute(SPELL_ATTR7_ALWAYS_CAST_LOG);
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,14 @@ enum SpellCastFlags
|
||||
CAST_FLAG_UNKNOWN_32 = 0x80000000
|
||||
};
|
||||
|
||||
enum SpellHealPredictionType : uint8
|
||||
{
|
||||
SPELL_HEAL_PREDICTION_TARGET = 0,
|
||||
SPELL_HEAL_PREDICTION_TARGET_AND_CASTER = 1,
|
||||
SPELL_HEAL_PREDICTION_TARGET_AND_BEACON = 2,
|
||||
SPELL_HEAL_PREDICTION_TARGET_PARTY = 3,
|
||||
};
|
||||
|
||||
enum SpellRangeFlag
|
||||
{
|
||||
SPELL_RANGE_DEFAULT = 0,
|
||||
@@ -807,7 +815,7 @@ class TC_GAME_API Spell
|
||||
void CalculateJumpSpeeds(uint8 i, float dist, float & speedxy, float & speedz);
|
||||
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellHitInfo& data);
|
||||
void UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& data);
|
||||
void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& predict);
|
||||
void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& predict, bool withPeriodic);
|
||||
|
||||
SpellCastResult CanOpenLock(uint32 effIndex, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
|
||||
// -------------------------------------------
|
||||
|
||||
@@ -190,6 +190,8 @@ enum TriggerCastFlags : uint32
|
||||
TRIGGERED_FULL_DEBUG_MASK = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
DEFINE_ENUM_FLAG(TriggerCastFlags);
|
||||
|
||||
struct TC_GAME_API CastSpellExtraArgs
|
||||
{
|
||||
CastSpellExtraArgs() {}
|
||||
|
||||
@@ -449,7 +449,7 @@ int32 SpellEffectInfo::CalcValue(WorldObject const* caster, int32 const* bp, Uni
|
||||
if (Scaling.Coefficient != 0.0f)
|
||||
{
|
||||
int32 level = _spellInfo->SpellLevel;
|
||||
if (target && _spellInfo->IsPositiveEffect(_effIndex) && (Effect == SPELL_EFFECT_APPLY_AURA || Effect == SPELL_EFFECT_APPLY_AURA_2))
|
||||
if (target && _spellInfo->HasAttribute(SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING))
|
||||
level = target->getLevel();
|
||||
else if (casterUnit)
|
||||
level = casterUnit->getLevel();
|
||||
@@ -492,7 +492,12 @@ int32 SpellEffectInfo::CalcValue(WorldObject const* caster, int32 const* bp, Uni
|
||||
{
|
||||
if (casterUnit && basePointsPerLevel != 0.0f)
|
||||
{
|
||||
int32 level = int32(casterUnit->getLevel());
|
||||
int32 level = 1;
|
||||
if (target && _spellInfo->HasAttribute(SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING))
|
||||
level = target->getLevel();
|
||||
else if (caster && caster->IsUnit())
|
||||
level = casterUnit->getLevel();
|
||||
|
||||
if (level > int32(_spellInfo->MaxLevel) && _spellInfo->MaxLevel > 0)
|
||||
level = int32(_spellInfo->MaxLevel);
|
||||
else if (level < int32(_spellInfo->BaseLevel))
|
||||
@@ -1320,11 +1325,6 @@ bool SpellInfo::IsPassive() const
|
||||
return HasAttribute(SPELL_ATTR0_PASSIVE);
|
||||
}
|
||||
|
||||
bool SpellInfo::IsRaidMarker() const
|
||||
{
|
||||
return AttributesEx8 & SPELL_ATTR8_RAID_MARKER;
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAutocastable() const
|
||||
{
|
||||
if (IsPassive())
|
||||
@@ -1769,6 +1769,20 @@ SpellCastResult SpellInfo::CheckLocation(uint32 map_id, uint32 zone_id, uint32 a
|
||||
return SPELL_FAILED_NOT_IN_RAID_INSTANCE;
|
||||
}
|
||||
|
||||
if (HasAttribute(SPELL_ATTR8_REMOVE_OUTSIDE_DUNGEONS_AND_RAIDS))
|
||||
{
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
|
||||
if (!mapEntry || !mapEntry->IsDungeon())
|
||||
return SPELL_FAILED_TARGET_NOT_IN_INSTANCE;
|
||||
}
|
||||
|
||||
if (HasAttribute(SPELL_ATTR8_NOT_IN_BATTLEGROUND))
|
||||
{
|
||||
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
|
||||
if (!mapEntry || mapEntry->IsBattleground())
|
||||
return SPELL_FAILED_NOT_IN_BATTLEGROUND;
|
||||
}
|
||||
|
||||
// DB base check (if non empty then must fit at least single for allow)
|
||||
SpellAreaMapBounds saBounds = sSpellMgr->GetSpellAreaMapBounds(Id);
|
||||
if (saBounds.first != saBounds.second)
|
||||
@@ -1888,6 +1902,13 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
|
||||
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
|
||||
/*
|
||||
* @todo: 4.x - old hold due to an upcoming tempsummon rework
|
||||
if (HasAttribute(SPELL_ATTR8_ONLY_TARGET_IF_SAME_CREATOR))
|
||||
if (caster != target && caster->GetGUID() != target->GetOwnerGUID())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
*/
|
||||
|
||||
// creature/player specific target checks
|
||||
if (unitTarget)
|
||||
{
|
||||
@@ -1938,6 +1959,10 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HasAttribute(SPELL_ATTR8_ONLY_TARGET_OWN_SUMMONS))
|
||||
if (!unitTarget->IsSummon() || unitTarget->ToTempSummon()->GetSummonerGUID() != caster->GetGUID())
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
}
|
||||
// corpse specific target checks
|
||||
else if (Corpse const* corpseTarget = target->ToCorpse())
|
||||
@@ -3390,6 +3415,17 @@ int32 SpellInfo::GetMaxDuration() const
|
||||
return (DurationEntry->MaxDuration == -1) ? -1 : abs(DurationEntry->MaxDuration);
|
||||
}
|
||||
|
||||
float SpellInfo::CalcPeriodicHasteMod(Unit const* caster) const
|
||||
{
|
||||
float hasteMod = 1.f;
|
||||
if (HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
|
||||
hasteMod = caster->GetFloatValue(UNIT_MOD_CAST_HASTE);
|
||||
else if (HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC) && caster->IsPlayer())
|
||||
hasteMod = caster->GetFloatValue(PLAYER_FIELD_MOD_HASTE);
|
||||
|
||||
return hasteMod;
|
||||
}
|
||||
|
||||
int32 SpellInfo::CalcDuration(WorldObject const* caster /*= nullptr*/) const
|
||||
{
|
||||
if (!DurationEntry)
|
||||
@@ -3443,13 +3479,14 @@ int32 SpellInfo::CalcDuration(WorldObject const* caster /*= nullptr*/) const
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (hasPeriodicEffect && HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) && !HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
|
||||
if (hasPeriodicEffect && !HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS) && (HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) || HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC)))
|
||||
{
|
||||
float hasteMod = unitCaster->GetFloatValue(UNIT_MOD_CAST_HASTE);
|
||||
float hasteMod = CalcPeriodicHasteMod(unitCaster);
|
||||
if (hasteMod > 0.001f)
|
||||
{
|
||||
if (HasAttribute(SPELL_ATTR8_HASTE_AFFECTS_DURATION))
|
||||
return int32(duration * hasteMod);
|
||||
|
||||
int32 period = CalcPeriod(caster, periodicEffectIndex);
|
||||
if (period > 0)
|
||||
duration = int32(period * (duration / (float)period));
|
||||
@@ -3480,9 +3517,9 @@ int32 SpellInfo::CalcPeriod(WorldObject const* caster, SpellEffIndex effIndex, O
|
||||
if (Player const* modOwner = unitCaster->GetSpellModOwner())
|
||||
modOwner->ApplySpellMod(Id, SpellModOp::Period, period);
|
||||
|
||||
if (HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) && !HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
|
||||
if (!HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS) && (HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC) || HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC)))
|
||||
{
|
||||
float hasteMod = unitCaster->GetFloatValue(UNIT_MOD_CAST_HASTE);
|
||||
float hasteMod = CalcPeriodicHasteMod(unitCaster);
|
||||
if (hasteMod > 0.001f)
|
||||
period = ((float)period * hasteMod);
|
||||
}
|
||||
|
||||
@@ -520,7 +520,6 @@ class TC_GAME_API SpellInfo
|
||||
bool IsSelfCast() const;
|
||||
|
||||
bool IsPassive() const;
|
||||
bool IsRaidMarker() const;
|
||||
bool IsAutocastable() const;
|
||||
bool IsStackableWithRanks() const;
|
||||
bool IsPassiveStackableWithRanks() const;
|
||||
@@ -583,6 +582,7 @@ class TC_GAME_API SpellInfo
|
||||
int32 GetDuration() const;
|
||||
int32 GetMaxDuration() const;
|
||||
|
||||
float CalcPeriodicHasteMod(Unit const* caster) const;
|
||||
int32 CalcDuration(WorldObject const* caster = nullptr) const;
|
||||
int32 CalcPeriod(WorldObject const* caster, SpellEffIndex effIndex, Optional<int32> periodOverride = {}) const;
|
||||
|
||||
|
||||
Reference in new issue
Block a user