mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-18 22:19:54 -04:00
Core/Spells: Named and implemented most of SpellAttr8
This commit is contained in:
@@ -2479,7 +2479,9 @@ void WorldObject::ModSpellDurationTime(SpellInfo const* spellInfo, int32& durati
|
||||
if (!spellInfo || duration < 0)
|
||||
return;
|
||||
|
||||
if (spellInfo->IsChanneled() && !spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
|
||||
if (spellInfo->IsChanneled()
|
||||
&& !spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC)
|
||||
&& !spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC))
|
||||
return;
|
||||
|
||||
// called from caster
|
||||
@@ -3103,7 +3105,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->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && unitOrOwner && unitOrOwner->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED) && (unitTarget->IsInSanctuary() || unitOrOwner->IsInSanctuary()))
|
||||
if (unitTarget && unitTarget->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)
|
||||
&& unitOrOwner && unitOrOwner->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)
|
||||
&& (unitTarget->IsInSanctuary() || unitOrOwner->IsInSanctuary())
|
||||
&& (!bySpell || bySpell->HasAttribute(SPELL_ATTR8_IGNORE_SANCTUARY)))
|
||||
return false;
|
||||
|
||||
// additional checks - only PvP case
|
||||
@@ -3210,7 +3215,7 @@ 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 (unitTarget->IsPvP() && (!bySpell || bySpell->HasAttribute(SPELL_ATTR8_IGNORE_SANCTUARY)))
|
||||
if (unit->IsInSanctuary() && !unitTarget->IsInSanctuary())
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25138,7 +25138,7 @@ bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item cons
|
||||
}
|
||||
case ITEM_CLASS_ARMOR:
|
||||
{
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR8_ARMOR_SPECIALIZATION))
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR8_REQUIRES_EQUIPPED_INV_TYPES))
|
||||
{
|
||||
// most used check: shield only
|
||||
if (spellInfo->EquippedItemSubClassMask & (1 << ITEM_SUBCLASS_ARMOR_SHIELD))
|
||||
@@ -29301,15 +29301,15 @@ Difficulty Player::CheckLoadedLegacyRaidDifficultyID(Difficulty difficulty)
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
SpellInfo const* Player::GetCastSpellInfo(SpellInfo const* spellInfo) const
|
||||
SpellInfo const* Player::GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag) const
|
||||
{
|
||||
auto overrides = m_overrideSpells.find(spellInfo->Id);
|
||||
if (overrides != m_overrideSpells.end())
|
||||
for (uint32 spellId : overrides->second)
|
||||
if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()))
|
||||
return Unit::GetCastSpellInfo(newInfo);
|
||||
return Unit::GetCastSpellInfo(newInfo, triggerFlag);
|
||||
|
||||
return Unit::GetCastSpellInfo(spellInfo);
|
||||
return Unit::GetCastSpellInfo(spellInfo, triggerFlag);
|
||||
}
|
||||
|
||||
void Player::AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
|
||||
|
||||
@@ -1780,7 +1780,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void SendRemoveControlBar() const;
|
||||
bool HasSpell(uint32 spell) const override;
|
||||
bool HasActiveSpell(uint32 spell) const; // show in spellbook
|
||||
SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const override;
|
||||
SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag) const override;
|
||||
bool IsSpellFitByClassAndRace(uint32 spell_id) const;
|
||||
bool HandlePassiveSpellLearn(SpellInfo const* spellInfo);
|
||||
|
||||
|
||||
@@ -2469,7 +2469,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 = true; // all melee and ranged attacks can be blocked
|
||||
bool canBlock = !spellInfo->HasAttribute(SPELL_ATTR8_NO_ATTACK_BLOCK);
|
||||
|
||||
// if victim is casting or cc'd it can't avoid attacks
|
||||
if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
|
||||
@@ -13714,16 +13714,23 @@ void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/
|
||||
target->SendDirectMessage(packet.Write());
|
||||
}
|
||||
|
||||
SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const
|
||||
SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag) const
|
||||
{
|
||||
auto findMatchingAuraEffectIn = [this, spellInfo](AuraType type) -> SpellInfo const*
|
||||
auto findMatchingAuraEffectIn = [this, spellInfo, &triggerFlag](AuraType type) -> SpellInfo const*
|
||||
{
|
||||
for (AuraEffect const* auraEffect : GetAuraEffectsByType(type))
|
||||
{
|
||||
bool matches = auraEffect->GetMiscValue() ? uint32(auraEffect->GetMiscValue()) == spellInfo->Id : auraEffect->IsAffectingSpell(spellInfo);
|
||||
if (matches)
|
||||
{
|
||||
if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount(), GetMap()->GetDifficultyID()))
|
||||
{
|
||||
if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST))
|
||||
triggerFlag |= TRIGGERED_IGNORE_POWER_AND_REAGENT_COST;
|
||||
|
||||
return newInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
@@ -1550,7 +1550,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;
|
||||
virtual SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo) const;
|
||||
virtual SpellInfo const* GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag) const;
|
||||
uint32 GetCastSpellXSpellVisualId(SpellInfo const* spellInfo) const override;
|
||||
|
||||
virtual bool HasSpellFocus(Spell const* /*focusSpell*/ = nullptr) const { return false; }
|
||||
|
||||
@@ -328,7 +328,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast)
|
||||
SpellCastTargets targets(caster, cast.Cast);
|
||||
|
||||
// check known spell or raid marker spell (which not requires player to know it)
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->HasEffect(SPELL_EFFECT_CHANGE_RAID_MARKER) && !spellInfo->HasAttribute(SPELL_ATTR8_RAID_MARKER))
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->HasAttribute(SPELL_ATTR8_SKIP_IS_KNOWN_CHECK))
|
||||
{
|
||||
bool allow = false;
|
||||
|
||||
@@ -349,7 +349,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast)
|
||||
}
|
||||
|
||||
// Check possible spell cast overrides
|
||||
spellInfo = caster->GetCastSpellInfo(spellInfo);
|
||||
spellInfo = caster->GetCastSpellInfo(spellInfo, triggerFlag);
|
||||
|
||||
if (spellInfo->IsPassive())
|
||||
return;
|
||||
|
||||
@@ -722,38 +722,38 @@ enum SpellAttr7 : uint32
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
enum SpellAttr8 : uint32
|
||||
{
|
||||
SPELL_ATTR8_CANT_MISS = 0x00000001, // TITLE No Attack Block
|
||||
SPELL_ATTR8_UNK1 = 0x00000002, // TITLE Unknown attribute 1@Attr8
|
||||
SPELL_ATTR8_UNK2 = 0x00000004, // TITLE Unknown attribute 2@Attr8
|
||||
SPELL_ATTR8_UNK3 = 0x00000008, // TITLE Unknown attribute 3@Attr8
|
||||
SPELL_ATTR8_UNK4 = 0x00000010, // TITLE Unknown attribute 4@Attr8
|
||||
SPELL_ATTR8_UNK5 = 0x00000020, // TITLE Unknown attribute 5@Attr8
|
||||
SPELL_ATTR8_UNK6 = 0x00000040, // TITLE Unknown attribute 6@Attr8
|
||||
SPELL_ATTR8_UNK7 = 0x00000080, // TITLE Unknown attribute 7@Attr8
|
||||
SPELL_ATTR8_AFFECT_PARTY_AND_RAID = 0x00000100, // TITLE Use Target's Level for Spell Scaling
|
||||
SPELL_ATTR8_PERIODIC_CAN_CRIT = 0x00000200, // TITLE Periodic Can Crit
|
||||
SPELL_ATTR8_NAME_CHANGED_DURING_TRANSFORM = 0x00000400, // TITLE Mirror creature name
|
||||
SPELL_ATTR8_UNK11 = 0x00000800, // TITLE Unknown attribute 11@Attr8
|
||||
SPELL_ATTR8_AURA_SEND_AMOUNT = 0x00001000, // TITLE Aura Points On Client
|
||||
SPELL_ATTR8_UNK13 = 0x00002000, // TITLE Unknown attribute 13@Attr8
|
||||
SPELL_ATTR8_UNK14 = 0x00004000, // TITLE Unknown attribute 14@Attr8
|
||||
SPELL_ATTR8_WATER_MOUNT = 0x00008000, // TITLE Requires location to be on liquid surface
|
||||
SPELL_ATTR8_UNK16 = 0x00010000, // TITLE Unknown attribute 16@Attr8
|
||||
SPELL_ATTR8_HASTE_AFFECTS_DURATION = 0x00020000, // TITLE Haste Affects Duration
|
||||
SPELL_ATTR8_REMEMBER_SPELLS = 0x00040000, // TTILE Ignore Spellcast Override Cost
|
||||
SPELL_ATTR8_USE_COMBO_POINTS_ON_ANY_TARGET = 0x00080000, // TITLE Allow Targets Hidden by Spawn Tracking
|
||||
SPELL_ATTR8_ARMOR_SPECIALIZATION = 0x00100000, // TITLE Requires Equipped Inv Types
|
||||
SPELL_ATTR8_UNK21 = 0x00200000, // TITLE Unknown attribute 21@Attr8
|
||||
SPELL_ATTR8_UNK22 = 0x00400000, // TITLE Unknown attribute 22@Attr8
|
||||
SPELL_ATTR8_BATTLE_RESURRECTION = 0x00800000, // TITLE Enforce In Combat Ressurection Limit DESCRIPTION Used to limit the number of resurrections in boss encounters
|
||||
SPELL_ATTR8_HEALING_SPELL = 0x01000000, // TITLE Heal Prediction
|
||||
SPELL_ATTR8_UNK25 = 0x02000000, // TITLE Unknown attribute 25@Attr8
|
||||
SPELL_ATTR8_RAID_MARKER = 0x04000000, // TITLE Skip Is Known Check
|
||||
SPELL_ATTR8_UNK27 = 0x08000000, // TITLE Unknown attribute 27@Attr8
|
||||
SPELL_ATTR8_NOT_IN_BG_OR_ARENA = 0x10000000, // TITLE Not in Battleground
|
||||
SPELL_ATTR8_MASTERY_AFFECTS_POINTS = 0x20000000, // TITLE Mastery Affects Points
|
||||
SPELL_ATTR8_UNK30 = 0x40000000, // TITLE Unknown attribute 30@Attr8
|
||||
SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG = 0x80000000 // TITLE Can Attack ImmunePC DESCRIPTION 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
|
||||
};
|
||||
|
||||
// EnumUtils: DESCRIBE THIS
|
||||
|
||||
@@ -1306,37 +1306,37 @@ TC_API_EXPORT EnumText EnumUtils<SpellAttr8>::ToString(SpellAttr8 value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SPELL_ATTR8_CANT_MISS: return { "SPELL_ATTR8_CANT_MISS", "No Attack Block", "" };
|
||||
case SPELL_ATTR8_UNK1: return { "SPELL_ATTR8_UNK1", "Unknown attribute 1@Attr8", "" };
|
||||
case SPELL_ATTR8_UNK2: return { "SPELL_ATTR8_UNK2", "Unknown attribute 2@Attr8", "" };
|
||||
case SPELL_ATTR8_UNK3: return { "SPELL_ATTR8_UNK3", "Unknown attribute 3@Attr8", "" };
|
||||
case SPELL_ATTR8_UNK4: return { "SPELL_ATTR8_UNK4", "Unknown attribute 4@Attr8", "" };
|
||||
case SPELL_ATTR8_UNK5: return { "SPELL_ATTR8_UNK5", "Unknown attribute 5@Attr8", "" };
|
||||
case SPELL_ATTR8_UNK6: return { "SPELL_ATTR8_UNK6", "Unknown attribute 6@Attr8", "" };
|
||||
case SPELL_ATTR8_UNK7: return { "SPELL_ATTR8_UNK7", "Unknown attribute 7@Attr8", "" };
|
||||
case SPELL_ATTR8_AFFECT_PARTY_AND_RAID: return { "SPELL_ATTR8_AFFECT_PARTY_AND_RAID", "Use Target's Level for Spell Scaling", "" };
|
||||
case SPELL_ATTR8_NO_ATTACK_BLOCK: return { "SPELL_ATTR8_NO_ATTACK_BLOCK", "No Attack Block", "" };
|
||||
case SPELL_ATTR8_IGNORE_DYNAMIC_OBJECT_CASTER: return { "SPELL_ATTR8_IGNORE_DYNAMIC_OBJECT_CASTER", "Ignore Dynamic Object Caster", "" };
|
||||
case SPELL_ATTR8_REMOVE_OUTSIDE_DUNGEONS_AND_RAIDS: return { "SPELL_ATTR8_REMOVE_OUTSIDE_DUNGEONS_AND_RAIDS", "Remove Outside Dungeons and Raids", "" };
|
||||
case SPELL_ATTR8_ONLY_TARGET_IF_SAME_CREATOR: return { "SPELL_ATTR8_ONLY_TARGET_IF_SAME_CREATOR", "Only Target If Same Creator", "" };
|
||||
case SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE: return { "SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE", "Can Hit AOE Untargetable", "" };
|
||||
case SPELL_ATTR8_ALLOW_WHILE_CHARMED: return { "SPELL_ATTR8_ALLOW_WHILE_CHARMED", "Allow While Charmed", "" };
|
||||
case SPELL_ATTR8_AURA_REQUIRED_BY_CLIENT: return { "SPELL_ATTR8_AURA_REQUIRED_BY_CLIENT", "Aura Required by Client", "" };
|
||||
case SPELL_ATTR8_IGNORE_SANCTUARY: return { "SPELL_ATTR8_IGNORE_SANCTUARY", "Ignore Sanctuary", "" };
|
||||
case SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING: return { "SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING", "Use Target's Level for Spell Scaling", "" };
|
||||
case SPELL_ATTR8_PERIODIC_CAN_CRIT: return { "SPELL_ATTR8_PERIODIC_CAN_CRIT", "Periodic Can Crit", "" };
|
||||
case SPELL_ATTR8_NAME_CHANGED_DURING_TRANSFORM: return { "SPELL_ATTR8_NAME_CHANGED_DURING_TRANSFORM", "Mirror creature name", "" };
|
||||
case SPELL_ATTR8_UNK11: return { "SPELL_ATTR8_UNK11", "Unknown attribute 11@Attr8", "" };
|
||||
case SPELL_ATTR8_AURA_SEND_AMOUNT: return { "SPELL_ATTR8_AURA_SEND_AMOUNT", "Aura Points On Client", "" };
|
||||
case SPELL_ATTR8_UNK13: return { "SPELL_ATTR8_UNK13", "Unknown attribute 13@Attr8", "" };
|
||||
case SPELL_ATTR8_UNK14: return { "SPELL_ATTR8_UNK14", "Unknown attribute 14@Attr8", "" };
|
||||
case SPELL_ATTR8_WATER_MOUNT: return { "SPELL_ATTR8_WATER_MOUNT", "Requires location to be on liquid surface", "" };
|
||||
case SPELL_ATTR8_UNK16: return { "SPELL_ATTR8_UNK16", "Unknown attribute 16@Attr8", "" };
|
||||
case SPELL_ATTR8_MIRROR_CREATURE_NAME: return { "SPELL_ATTR8_MIRROR_CREATURE_NAME", "Mirror creature name", "Transform auras also override name (handled clientside)" };
|
||||
case SPELL_ATTR8_ONLY_PLAYERS_CAN_CAST_THIS_SPELL: return { "SPELL_ATTR8_ONLY_PLAYERS_CAN_CAST_THIS_SPELL", "Only Players Can Cast This Spell", "" };
|
||||
case SPELL_ATTR8_AURA_POINTS_ON_CLIENT: return { "SPELL_ATTR8_AURA_POINTS_ON_CLIENT", "Aura Points On Client", "" };
|
||||
case SPELL_ATTR8_NOT_IN_SPELLBOOK_UNTIL_LEARNED: return { "SPELL_ATTR8_NOT_IN_SPELLBOOK_UNTIL_LEARNED", "Not In Spellbook Until Learned", "Hides autolearned spell from spellbook before learning (handled clientside)" };
|
||||
case SPELL_ATTR8_TARGET_PROCS_ON_CASTER: return { "SPELL_ATTR8_TARGET_PROCS_ON_CASTER", "Target Procs On Caster", "Target (taken) procs happen on caster (actor) instead of aura target (action target)" };
|
||||
case SPELL_ATTR8_REQUIRES_LOCATION_TO_BE_ON_LIQUID_SURFACE: return { "SPELL_ATTR8_REQUIRES_LOCATION_TO_BE_ON_LIQUID_SURFACE", "Requires location to be on liquid surface", "" };
|
||||
case SPELL_ATTR8_ONLY_TARGET_OWN_SUMMONS: return { "SPELL_ATTR8_ONLY_TARGET_OWN_SUMMONS", "Only Target Own Summons", "" };
|
||||
case SPELL_ATTR8_HASTE_AFFECTS_DURATION: return { "SPELL_ATTR8_HASTE_AFFECTS_DURATION", "Haste Affects Duration", "" };
|
||||
case SPELL_ATTR8_REMEMBER_SPELLS: return { "SPELL_ATTR8_REMEMBER_SPELLS", "SPELL_ATTR8_REMEMBER_SPELLS", "TTILE Ignore Spellcast Override Cost" };
|
||||
case SPELL_ATTR8_USE_COMBO_POINTS_ON_ANY_TARGET: return { "SPELL_ATTR8_USE_COMBO_POINTS_ON_ANY_TARGET", "Allow Targets Hidden by Spawn Tracking", "" };
|
||||
case SPELL_ATTR8_ARMOR_SPECIALIZATION: return { "SPELL_ATTR8_ARMOR_SPECIALIZATION", "Requires Equipped Inv Types", "" };
|
||||
case SPELL_ATTR8_UNK21: return { "SPELL_ATTR8_UNK21", "Unknown attribute 21@Attr8", "" };
|
||||
case SPELL_ATTR8_UNK22: return { "SPELL_ATTR8_UNK22", "Unknown attribute 22@Attr8", "" };
|
||||
case SPELL_ATTR8_BATTLE_RESURRECTION: return { "SPELL_ATTR8_BATTLE_RESURRECTION", "Enforce In Combat Ressurection Limit", "Used to limit the number of resurrections in boss encounters" };
|
||||
case SPELL_ATTR8_HEALING_SPELL: return { "SPELL_ATTR8_HEALING_SPELL", "Heal Prediction", "" };
|
||||
case SPELL_ATTR8_UNK25: return { "SPELL_ATTR8_UNK25", "Unknown attribute 25@Attr8", "" };
|
||||
case SPELL_ATTR8_RAID_MARKER: return { "SPELL_ATTR8_RAID_MARKER", "Skip Is Known Check", "" };
|
||||
case SPELL_ATTR8_UNK27: return { "SPELL_ATTR8_UNK27", "Unknown attribute 27@Attr8", "" };
|
||||
case SPELL_ATTR8_NOT_IN_BG_OR_ARENA: return { "SPELL_ATTR8_NOT_IN_BG_OR_ARENA", "Not in Battleground", "" };
|
||||
case SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST: return { "SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST", "SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST", "TTILE Ignore Spellcast Override Cost" };
|
||||
case SPELL_ATTR8_ALLOW_TARGETS_HIDDEN_BY_SPAWN_TRACKING: return { "SPELL_ATTR8_ALLOW_TARGETS_HIDDEN_BY_SPAWN_TRACKING", "Allow Targets Hidden by Spawn Tracking", "" };
|
||||
case SPELL_ATTR8_REQUIRES_EQUIPPED_INV_TYPES: return { "SPELL_ATTR8_REQUIRES_EQUIPPED_INV_TYPES", "Requires Equipped Inv Types", "" };
|
||||
case SPELL_ATTR8_NO_SUMMON_DEST_FROM_CLIENT_TARGETING_PATHING_REQUIREMENT: return { "SPELL_ATTR8_NO_SUMMON_DEST_FROM_CLIENT_TARGETING_PATHING_REQUIREMENT", "No 'Summon + Dest from Client' Targeting Pathing Requirement", "" };
|
||||
case SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC: return { "SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC", "Melee Haste Affects Periodic", "" };
|
||||
case SPELL_ATTR8_ENFORCE_IN_COMBAT_RESSURECTION_LIMIT: return { "SPELL_ATTR8_ENFORCE_IN_COMBAT_RESSURECTION_LIMIT", "Enforce In Combat Ressurection Limit", "Used to limit the number of resurrections in boss encounters" };
|
||||
case SPELL_ATTR8_HEAL_PREDICTION: return { "SPELL_ATTR8_HEAL_PREDICTION", "Heal Prediction", "" };
|
||||
case SPELL_ATTR8_NO_LEVEL_UP_TOAST: return { "SPELL_ATTR8_NO_LEVEL_UP_TOAST", "No Level Up Toast", "" };
|
||||
case SPELL_ATTR8_SKIP_IS_KNOWN_CHECK: return { "SPELL_ATTR8_SKIP_IS_KNOWN_CHECK", "Skip Is Known Check", "" };
|
||||
case SPELL_ATTR8_AI_FACE_TARGET: return { "SPELL_ATTR8_AI_FACE_TARGET", "AI Face Target", "" };
|
||||
case SPELL_ATTR8_NOT_IN_BATTLEGROUND: return { "SPELL_ATTR8_NOT_IN_BATTLEGROUND", "Not in Battleground", "" };
|
||||
case SPELL_ATTR8_MASTERY_AFFECTS_POINTS: return { "SPELL_ATTR8_MASTERY_AFFECTS_POINTS", "Mastery Affects Points", "" };
|
||||
case SPELL_ATTR8_UNK30: return { "SPELL_ATTR8_UNK30", "Unknown attribute 30@Attr8", "" };
|
||||
case SPELL_ATTR8_DISPLAY_LARGE_AURA_ICON_ON_UNIT_FRAMES_BOSS_AURA: return { "SPELL_ATTR8_DISPLAY_LARGE_AURA_ICON_ON_UNIT_FRAMES_BOSS_AURA", "Display Large Aura Icon On Unit Frames (Boss Aura)", "" };
|
||||
case SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG: return { "SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG", "Can Attack ImmunePC", "Do not check UNIT_FLAG_IMMUNE_TO_PC in IsValidAttackTarget" };
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
@@ -1350,37 +1350,37 @@ TC_API_EXPORT SpellAttr8 EnumUtils<SpellAttr8>::FromIndex(size_t index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return SPELL_ATTR8_CANT_MISS;
|
||||
case 1: return SPELL_ATTR8_UNK1;
|
||||
case 2: return SPELL_ATTR8_UNK2;
|
||||
case 3: return SPELL_ATTR8_UNK3;
|
||||
case 4: return SPELL_ATTR8_UNK4;
|
||||
case 5: return SPELL_ATTR8_UNK5;
|
||||
case 6: return SPELL_ATTR8_UNK6;
|
||||
case 7: return SPELL_ATTR8_UNK7;
|
||||
case 8: return SPELL_ATTR8_AFFECT_PARTY_AND_RAID;
|
||||
case 0: return SPELL_ATTR8_NO_ATTACK_BLOCK;
|
||||
case 1: return SPELL_ATTR8_IGNORE_DYNAMIC_OBJECT_CASTER;
|
||||
case 2: return SPELL_ATTR8_REMOVE_OUTSIDE_DUNGEONS_AND_RAIDS;
|
||||
case 3: return SPELL_ATTR8_ONLY_TARGET_IF_SAME_CREATOR;
|
||||
case 4: return SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE;
|
||||
case 5: return SPELL_ATTR8_ALLOW_WHILE_CHARMED;
|
||||
case 6: return SPELL_ATTR8_AURA_REQUIRED_BY_CLIENT;
|
||||
case 7: return SPELL_ATTR8_IGNORE_SANCTUARY;
|
||||
case 8: return SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING;
|
||||
case 9: return SPELL_ATTR8_PERIODIC_CAN_CRIT;
|
||||
case 10: return SPELL_ATTR8_NAME_CHANGED_DURING_TRANSFORM;
|
||||
case 11: return SPELL_ATTR8_UNK11;
|
||||
case 12: return SPELL_ATTR8_AURA_SEND_AMOUNT;
|
||||
case 13: return SPELL_ATTR8_UNK13;
|
||||
case 14: return SPELL_ATTR8_UNK14;
|
||||
case 15: return SPELL_ATTR8_WATER_MOUNT;
|
||||
case 16: return SPELL_ATTR8_UNK16;
|
||||
case 10: return SPELL_ATTR8_MIRROR_CREATURE_NAME;
|
||||
case 11: return SPELL_ATTR8_ONLY_PLAYERS_CAN_CAST_THIS_SPELL;
|
||||
case 12: return SPELL_ATTR8_AURA_POINTS_ON_CLIENT;
|
||||
case 13: return SPELL_ATTR8_NOT_IN_SPELLBOOK_UNTIL_LEARNED;
|
||||
case 14: return SPELL_ATTR8_TARGET_PROCS_ON_CASTER;
|
||||
case 15: return SPELL_ATTR8_REQUIRES_LOCATION_TO_BE_ON_LIQUID_SURFACE;
|
||||
case 16: return SPELL_ATTR8_ONLY_TARGET_OWN_SUMMONS;
|
||||
case 17: return SPELL_ATTR8_HASTE_AFFECTS_DURATION;
|
||||
case 18: return SPELL_ATTR8_REMEMBER_SPELLS;
|
||||
case 19: return SPELL_ATTR8_USE_COMBO_POINTS_ON_ANY_TARGET;
|
||||
case 20: return SPELL_ATTR8_ARMOR_SPECIALIZATION;
|
||||
case 21: return SPELL_ATTR8_UNK21;
|
||||
case 22: return SPELL_ATTR8_UNK22;
|
||||
case 23: return SPELL_ATTR8_BATTLE_RESURRECTION;
|
||||
case 24: return SPELL_ATTR8_HEALING_SPELL;
|
||||
case 25: return SPELL_ATTR8_UNK25;
|
||||
case 26: return SPELL_ATTR8_RAID_MARKER;
|
||||
case 27: return SPELL_ATTR8_UNK27;
|
||||
case 28: return SPELL_ATTR8_NOT_IN_BG_OR_ARENA;
|
||||
case 18: return SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST;
|
||||
case 19: return SPELL_ATTR8_ALLOW_TARGETS_HIDDEN_BY_SPAWN_TRACKING;
|
||||
case 20: return SPELL_ATTR8_REQUIRES_EQUIPPED_INV_TYPES;
|
||||
case 21: return SPELL_ATTR8_NO_SUMMON_DEST_FROM_CLIENT_TARGETING_PATHING_REQUIREMENT;
|
||||
case 22: return SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC;
|
||||
case 23: return SPELL_ATTR8_ENFORCE_IN_COMBAT_RESSURECTION_LIMIT;
|
||||
case 24: return SPELL_ATTR8_HEAL_PREDICTION;
|
||||
case 25: return SPELL_ATTR8_NO_LEVEL_UP_TOAST;
|
||||
case 26: return SPELL_ATTR8_SKIP_IS_KNOWN_CHECK;
|
||||
case 27: return SPELL_ATTR8_AI_FACE_TARGET;
|
||||
case 28: return SPELL_ATTR8_NOT_IN_BATTLEGROUND;
|
||||
case 29: return SPELL_ATTR8_MASTERY_AFFECTS_POINTS;
|
||||
case 30: return SPELL_ATTR8_UNK30;
|
||||
case 30: return SPELL_ATTR8_DISPLAY_LARGE_AURA_ICON_ON_UNIT_FRAMES_BOSS_AURA;
|
||||
case 31: return SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG;
|
||||
default: throw std::out_of_range("index");
|
||||
}
|
||||
@@ -1391,37 +1391,37 @@ TC_API_EXPORT size_t EnumUtils<SpellAttr8>::ToIndex(SpellAttr8 value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case SPELL_ATTR8_CANT_MISS: return 0;
|
||||
case SPELL_ATTR8_UNK1: return 1;
|
||||
case SPELL_ATTR8_UNK2: return 2;
|
||||
case SPELL_ATTR8_UNK3: return 3;
|
||||
case SPELL_ATTR8_UNK4: return 4;
|
||||
case SPELL_ATTR8_UNK5: return 5;
|
||||
case SPELL_ATTR8_UNK6: return 6;
|
||||
case SPELL_ATTR8_UNK7: return 7;
|
||||
case SPELL_ATTR8_AFFECT_PARTY_AND_RAID: return 8;
|
||||
case SPELL_ATTR8_NO_ATTACK_BLOCK: return 0;
|
||||
case SPELL_ATTR8_IGNORE_DYNAMIC_OBJECT_CASTER: return 1;
|
||||
case SPELL_ATTR8_REMOVE_OUTSIDE_DUNGEONS_AND_RAIDS: return 2;
|
||||
case SPELL_ATTR8_ONLY_TARGET_IF_SAME_CREATOR: return 3;
|
||||
case SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE: return 4;
|
||||
case SPELL_ATTR8_ALLOW_WHILE_CHARMED: return 5;
|
||||
case SPELL_ATTR8_AURA_REQUIRED_BY_CLIENT: return 6;
|
||||
case SPELL_ATTR8_IGNORE_SANCTUARY: return 7;
|
||||
case SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING: return 8;
|
||||
case SPELL_ATTR8_PERIODIC_CAN_CRIT: return 9;
|
||||
case SPELL_ATTR8_NAME_CHANGED_DURING_TRANSFORM: return 10;
|
||||
case SPELL_ATTR8_UNK11: return 11;
|
||||
case SPELL_ATTR8_AURA_SEND_AMOUNT: return 12;
|
||||
case SPELL_ATTR8_UNK13: return 13;
|
||||
case SPELL_ATTR8_UNK14: return 14;
|
||||
case SPELL_ATTR8_WATER_MOUNT: return 15;
|
||||
case SPELL_ATTR8_UNK16: return 16;
|
||||
case SPELL_ATTR8_MIRROR_CREATURE_NAME: return 10;
|
||||
case SPELL_ATTR8_ONLY_PLAYERS_CAN_CAST_THIS_SPELL: return 11;
|
||||
case SPELL_ATTR8_AURA_POINTS_ON_CLIENT: return 12;
|
||||
case SPELL_ATTR8_NOT_IN_SPELLBOOK_UNTIL_LEARNED: return 13;
|
||||
case SPELL_ATTR8_TARGET_PROCS_ON_CASTER: return 14;
|
||||
case SPELL_ATTR8_REQUIRES_LOCATION_TO_BE_ON_LIQUID_SURFACE: return 15;
|
||||
case SPELL_ATTR8_ONLY_TARGET_OWN_SUMMONS: return 16;
|
||||
case SPELL_ATTR8_HASTE_AFFECTS_DURATION: return 17;
|
||||
case SPELL_ATTR8_REMEMBER_SPELLS: return 18;
|
||||
case SPELL_ATTR8_USE_COMBO_POINTS_ON_ANY_TARGET: return 19;
|
||||
case SPELL_ATTR8_ARMOR_SPECIALIZATION: return 20;
|
||||
case SPELL_ATTR8_UNK21: return 21;
|
||||
case SPELL_ATTR8_UNK22: return 22;
|
||||
case SPELL_ATTR8_BATTLE_RESURRECTION: return 23;
|
||||
case SPELL_ATTR8_HEALING_SPELL: return 24;
|
||||
case SPELL_ATTR8_UNK25: return 25;
|
||||
case SPELL_ATTR8_RAID_MARKER: return 26;
|
||||
case SPELL_ATTR8_UNK27: return 27;
|
||||
case SPELL_ATTR8_NOT_IN_BG_OR_ARENA: return 28;
|
||||
case SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST: return 18;
|
||||
case SPELL_ATTR8_ALLOW_TARGETS_HIDDEN_BY_SPAWN_TRACKING: return 19;
|
||||
case SPELL_ATTR8_REQUIRES_EQUIPPED_INV_TYPES: return 20;
|
||||
case SPELL_ATTR8_NO_SUMMON_DEST_FROM_CLIENT_TARGETING_PATHING_REQUIREMENT: return 21;
|
||||
case SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC: return 22;
|
||||
case SPELL_ATTR8_ENFORCE_IN_COMBAT_RESSURECTION_LIMIT: return 23;
|
||||
case SPELL_ATTR8_HEAL_PREDICTION: return 24;
|
||||
case SPELL_ATTR8_NO_LEVEL_UP_TOAST: return 25;
|
||||
case SPELL_ATTR8_SKIP_IS_KNOWN_CHECK: return 26;
|
||||
case SPELL_ATTR8_AI_FACE_TARGET: return 27;
|
||||
case SPELL_ATTR8_NOT_IN_BATTLEGROUND: return 28;
|
||||
case SPELL_ATTR8_MASTERY_AFFECTS_POINTS: return 29;
|
||||
case SPELL_ATTR8_UNK30: return 30;
|
||||
case SPELL_ATTR8_DISPLAY_LARGE_AURA_ICON_ON_UNIT_FRAMES_BOSS_AURA: return 30;
|
||||
case SPELL_ATTR8_ATTACK_IGNORE_IMMUNE_TO_PC_FLAG: return 31;
|
||||
default: throw std::out_of_range("value");
|
||||
}
|
||||
|
||||
@@ -768,6 +768,8 @@ float AuraEffect::CalculateEstimatedfTotalPeriodicAmount(Unit* caster, Unit* tar
|
||||
caster->ModSpellDurationTime(spellInfo, period);
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
|
||||
period = int32(period * caster->m_unitData->ModCastingSpeed);
|
||||
else if (spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC))
|
||||
period = int32(period * caster->m_unitData->ModHaste);
|
||||
|
||||
if (!period)
|
||||
return 0.0f;
|
||||
@@ -851,6 +853,8 @@ void AuraEffect::CalculatePeriodic(Unit* caster, bool resetPeriodicTimer /*= tru
|
||||
caster->ModSpellDurationTime(m_spellInfo, _period);
|
||||
else if (m_spellInfo->HasAttribute(SPELL_ATTR5_SPELL_HASTE_AFFECTS_PERIODIC))
|
||||
_period = int32(_period * caster->m_unitData->ModCastingSpeed);
|
||||
else if (m_spellInfo->HasAttribute(SPELL_ATTR8_MELEE_HASTE_AFFECTS_PERIODIC))
|
||||
_period = int32(_period * caster->m_unitData->ModHaste);
|
||||
}
|
||||
}
|
||||
else // prevent infinite loop on Update
|
||||
@@ -967,7 +971,7 @@ void AuraEffect::ChangeAmount(int32 newAmount, bool mark, bool onStackOrReapply,
|
||||
HandleEffect(aurApp, handleMask, true, triggeredBy);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -5905,6 +5909,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 = GetSpellEffectInfo().TriggerSpell;
|
||||
if (triggerSpellId == 0)
|
||||
@@ -5926,6 +5932,8 @@ void AuraEffect::HandleProcTriggerSpellWithValueAuraProc(AuraApplication* aurApp
|
||||
{
|
||||
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 = GetSpellEffectInfo().TriggerSpell;
|
||||
if (triggerSpellId == 0)
|
||||
|
||||
@@ -148,7 +148,7 @@ void AuraApplication::_InitFlags(Unit* caster, uint32 effMask)
|
||||
return effect && (GetEffectsToApply() & (1 << effect->GetEffIndex())) && Aura::EffectTypeNeedsSendingAmount(effect->GetAuraType());
|
||||
};
|
||||
|
||||
if (GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT)
|
||||
if (GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT)
|
||||
|| std::find_if(GetBase()->GetAuraEffects().begin(), GetBase()->GetAuraEffects().end(), std::cref(effectNeedsAmount)) != GetBase()->GetAuraEffects().end())
|
||||
_flags |= AFLAG_SCALABLE;
|
||||
}
|
||||
|
||||
@@ -824,6 +824,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(SPELL_FAILED_NO_LIQUID);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uint64 dstDelay = CalculateDelayMomentForDst(m_spellInfo->LaunchDelay))
|
||||
m_delayMoment = dstDelay;
|
||||
}
|
||||
@@ -2740,7 +2756,7 @@ void Spell::TargetInfo::DoTargetSpellHit(Spell* spell, SpellEffectInfo const& sp
|
||||
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)
|
||||
@@ -4672,6 +4688,9 @@ void Spell::SendSpellStart()
|
||||
if (HasPowerTypeCost(POWER_RUNES))
|
||||
castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
|
||||
|
||||
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;
|
||||
|
||||
@@ -4737,13 +4756,8 @@ void Spell::SendSpellStart()
|
||||
castData.Immunities.Value = mechanicImmunityMask;
|
||||
}
|
||||
|
||||
/** @todo implement heal prediction packet data
|
||||
if (castFlags & CAST_FLAG_HEAL_PREDICTION)
|
||||
{
|
||||
castData.Predict.BeconGUID = ??
|
||||
castData.Predict.Points = 0;
|
||||
castData.Predict.Type = 0;
|
||||
}**/
|
||||
UpdateSpellHealPrediction(castData.Predict, false);
|
||||
|
||||
m_caster->SendMessageToSet(packet.Write(), true);
|
||||
}
|
||||
@@ -4948,6 +4962,84 @@ int32 Spell::GetSpellCastDataAmmo()
|
||||
return ammoDisplayID;
|
||||
}
|
||||
|
||||
static std::pair<int32, SpellHealPredictionType> CalcPredictedHealing(SpellInfo const* spellInfo, Unit const* unitCaster, Unit* target, uint32 castItemEntry, int32 castItemLevel, Spell* spell, bool withPeriodic)
|
||||
{
|
||||
int32 points = 0;
|
||||
SpellHealPredictionType type = SPELL_HEAL_PREDICTION_TARGET;
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
{
|
||||
switch (spellEffectInfo.Effect)
|
||||
{
|
||||
case SPELL_EFFECT_HEAL:
|
||||
case SPELL_EFFECT_HEAL_PCT:
|
||||
points += unitCaster->SpellHealingBonusDone(target,
|
||||
spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
|
||||
DIRECT_DAMAGE, spellEffectInfo, 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 (withPeriodic)
|
||||
{
|
||||
switch (spellEffectInfo.ApplyAuraName)
|
||||
{
|
||||
case SPELL_AURA_PERIODIC_HEAL:
|
||||
case SPELL_AURA_OBS_MOD_HEALTH:
|
||||
points += unitCaster->SpellHealingBonusDone(target,
|
||||
spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
|
||||
DIRECT_DAMAGE, spellEffectInfo, 1, spell) * spellInfo->GetMaxTicks();
|
||||
break;
|
||||
case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
|
||||
if (SpellInfo const* triggered = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, spellInfo->Difficulty))
|
||||
points += CalcPredictedHealing(triggered, unitCaster, target, castItemEntry, castItemLevel, 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, m_castItemEntry, m_castItemLevel, 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()->GetEffects().size() > EFFECT_1 && aura->GetSpellInfo()->GetEffect(EFFECT_1).TriggerSpell == beaconSpellId;
|
||||
});
|
||||
|
||||
if (beacon != unitCaster->GetSingleCastAuras().end())
|
||||
{
|
||||
healPrediction.BeaconGUID = (*beacon)->GetOwner()->GetGUID();
|
||||
healPrediction.Type = SPELL_HEAL_PREDICTION_TARGET_AND_BEACON;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::SendSpellExecuteLog()
|
||||
{
|
||||
if (_executeLogEffects.empty())
|
||||
@@ -5112,23 +5204,6 @@ void Spell::SendChannelStart(uint32 duration)
|
||||
if (!unitCaster)
|
||||
return;
|
||||
|
||||
WorldPackets::Spells::SpellChannelStart spellChannelStart;
|
||||
spellChannelStart.CasterGUID = unitCaster->GetGUID();
|
||||
spellChannelStart.SpellID = m_spellInfo->Id;
|
||||
spellChannelStart.Visual = m_SpellVisual;
|
||||
spellChannelStart.ChannelDuration = duration;
|
||||
unitCaster->SendMessageToSet(spellChannelStart.Write(), true);
|
||||
|
||||
uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
|
||||
uint32 mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
|
||||
|
||||
if (schoolImmunityMask || mechanicImmunityMask)
|
||||
{
|
||||
spellChannelStart.InterruptImmunities.emplace();
|
||||
spellChannelStart.InterruptImmunities->SchoolImmunities = schoolImmunityMask;
|
||||
spellChannelStart.InterruptImmunities->Immunities = mechanicImmunityMask;
|
||||
}
|
||||
|
||||
m_timer = duration;
|
||||
|
||||
if (!m_targets.HasDst())
|
||||
@@ -5176,6 +5251,33 @@ void Spell::SendChannelStart(uint32 duration)
|
||||
|
||||
unitCaster->SetChannelSpellId(m_spellInfo->Id);
|
||||
unitCaster->SetChannelVisual(m_SpellVisual);
|
||||
|
||||
WorldPackets::Spells::SpellChannelStart spellChannelStart;
|
||||
spellChannelStart.CasterGUID = unitCaster->GetGUID();
|
||||
spellChannelStart.SpellID = m_spellInfo->Id;
|
||||
spellChannelStart.Visual = m_SpellVisual;
|
||||
spellChannelStart.ChannelDuration = duration;
|
||||
|
||||
uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
|
||||
uint32 mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
|
||||
|
||||
if (schoolImmunityMask || mechanicImmunityMask)
|
||||
{
|
||||
spellChannelStart.InterruptImmunities.emplace();
|
||||
spellChannelStart.InterruptImmunities->SchoolImmunities = schoolImmunityMask;
|
||||
spellChannelStart.InterruptImmunities->Immunities = mechanicImmunityMask;
|
||||
}
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION) && m_casttime && m_caster->IsUnit())
|
||||
{
|
||||
WorldPackets::Spells::SpellTargetedHealPrediction& healPrediction = spellChannelStart.HealPrediction.emplace();
|
||||
if (unitCaster->m_unitData->ChannelObjects.size() == 1 && unitCaster->m_unitData->ChannelObjects[0].IsUnit())
|
||||
healPrediction.TargetGUID = unitCaster->m_unitData->ChannelObjects[0];
|
||||
|
||||
UpdateSpellHealPrediction(healPrediction.Predict, true);
|
||||
}
|
||||
|
||||
unitCaster->SendMessageToSet(spellChannelStart.Write(), true);
|
||||
}
|
||||
|
||||
void Spell::SendResurrectRequest(Player* target)
|
||||
@@ -5594,6 +5696,9 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
|
||||
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;
|
||||
@@ -6920,7 +7025,7 @@ SpellCastResult Spell::CheckArenaAndRatedBattlegroundCastRules()
|
||||
return isArena ? SPELL_FAILED_NOT_IN_ARENA : SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND;
|
||||
|
||||
if (isArena && m_spellInfo->HasAttribute(SPELL_ATTR9_NOT_USABLE_IN_ARENA))
|
||||
return SPELL_FAILED_NOT_IN_ARENA;
|
||||
return SPELL_FAILED_NOT_IN_ARENA;
|
||||
|
||||
// check cooldowns
|
||||
uint32 spellCooldown = m_spellInfo->GetRecoveryTime();
|
||||
@@ -8075,7 +8180,7 @@ bool Spell::IsPositive() const
|
||||
bool Spell::IsNeedSendToClient() const
|
||||
{
|
||||
return m_SpellVisual.SpellXSpellVisualID || m_SpellVisual.ScriptVisualID || m_spellInfo->IsChanneled() ||
|
||||
(m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_SEND_AMOUNT)) || m_spellInfo->HasHitDelay() || (!m_triggeredByAuraSpell && !IsTriggered()) ||
|
||||
(m_spellInfo->HasAttribute(SPELL_ATTR8_AURA_POINTS_ON_CLIENT)) || m_spellInfo->HasHitDelay() || (!m_triggeredByAuraSpell && !IsTriggered()) ||
|
||||
m_spellInfo->HasAttribute(SPELL_ATTR7_ALWAYS_CAST_LOG);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,12 +28,10 @@
|
||||
#include "SpellDefines.h"
|
||||
#include <memory>
|
||||
|
||||
namespace WorldPackets
|
||||
namespace WorldPackets::Spells
|
||||
{
|
||||
namespace Spells
|
||||
{
|
||||
struct SpellCastData;
|
||||
}
|
||||
struct SpellCastData;
|
||||
struct SpellHealPrediction;
|
||||
}
|
||||
|
||||
class Aura;
|
||||
@@ -147,6 +145,14 @@ enum SpellCastSource : uint8
|
||||
SPELL_CAST_SOURCE_SPELL = 16,
|
||||
};
|
||||
|
||||
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,
|
||||
@@ -888,6 +894,7 @@ class TC_GAME_API Spell
|
||||
|
||||
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData& data);
|
||||
int32 GetSpellCastDataAmmo();
|
||||
void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& healPrediction, bool withPeriodic);
|
||||
|
||||
SpellCastResult CanOpenLock(SpellEffectInfo const& effect, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue);
|
||||
// -------------------------------------------
|
||||
|
||||
@@ -560,7 +560,7 @@ int32 SpellEffectInfo::CalcBaseValue(WorldObject const* caster, Unit const* targ
|
||||
if (Scaling.Coefficient != 0.0f)
|
||||
{
|
||||
uint32 level = _spellInfo->SpellLevel;
|
||||
if (target && _spellInfo->IsPositiveEffect(EffectIndex) && (Effect == SPELL_EFFECT_APPLY_AURA))
|
||||
if (target && _spellInfo->HasAttribute(SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING))
|
||||
level = target->GetLevel();
|
||||
else if (caster && caster->IsUnit())
|
||||
level = caster->ToUnit()->GetLevel();
|
||||
@@ -632,7 +632,12 @@ int32 SpellEffectInfo::CalcBaseValue(WorldObject const* caster, Unit const* targ
|
||||
if (ContentTuningEntry const* contentTuning = sContentTuningStore.LookupEntry(contentTuningId))
|
||||
expansion = contentTuning->ExpansionID;
|
||||
|
||||
int32 level = caster && caster->IsUnit() ? int32(caster->ToUnit()->GetLevel()) : 1;
|
||||
int32 level = 1;
|
||||
if (target && _spellInfo->HasAttribute(SPELL_ATTR8_USE_TARGETS_LEVEL_FOR_SPELL_SCALING))
|
||||
level = target->GetLevel();
|
||||
else if (caster && caster->IsUnit())
|
||||
level = caster->ToUnit()->GetLevel();
|
||||
|
||||
value = sDB2Manager.EvaluateExpectedStat(stat, level, expansion, 0, CLASS_NONE, 0) * BasePoints / 100.0f;
|
||||
}
|
||||
|
||||
@@ -2034,6 +2039,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)
|
||||
@@ -2153,6 +2172,10 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
|
||||
|
||||
Unit const* unitTarget = target->ToUnit();
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -2203,6 +2226,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())
|
||||
@@ -2294,7 +2321,7 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co
|
||||
if (HasEffect(SPELL_EFFECT_SELF_RESURRECT) || HasEffect(SPELL_EFFECT_RESURRECT))
|
||||
return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;
|
||||
|
||||
if (HasAttribute(SPELL_ATTR8_BATTLE_RESURRECTION))
|
||||
if (HasAttribute(SPELL_ATTR8_ENFORCE_IN_COMBAT_RESSURECTION_LIMIT))
|
||||
if (Map* map = caster->GetMap())
|
||||
if (InstanceMap* iMap = map->ToInstanceMap())
|
||||
if (InstanceScript* instance = iMap->GetInstanceScript())
|
||||
|
||||
Reference in New Issue
Block a user