diff options
Diffstat (limited to 'src/server')
22 files changed, 248 insertions, 189 deletions
diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 318c7c29583..ccdb4097323 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -154,7 +154,7 @@ void UnitAI::DoCast(uint32 spellId) float range = spellInfo->GetMaxRange(false); DefaultTargetSelector targetSelector(me, range, playerOnly, true, -(int32)spellId); - if (!spellInfo->HasAuraInterruptFlag(AURA_INTERRUPT_FLAG_NOT_VICTIM) && targetSelector(me->GetVictim())) + if (!spellInfo->HasAuraInterruptFlag(SpellAuraInterruptFlags::NOT_VICTIM) && targetSelector(me->GetVictim())) target = me->GetVictim(); else target = SelectTarget(SELECT_TARGET_RANDOM, 0, targetSelector); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp index 508fd47ed8d..4e3600b069b 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.cpp @@ -431,7 +431,7 @@ void BattlegroundAB::EventPlayerClickedOnFlag(Player* source, GameObject* /*targ if (!(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2)) return; - source->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + source->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive); uint32 sound = 0; // If node is neutral, change to contested if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL) diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index c42350756d5..e440e7ef912 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -684,7 +684,7 @@ void BattlegroundEY::EventPlayerClickedOnFlag(Player* player, GameObject* target SetFlagPicker(player->GetGUID()); //get flag aura on player player->CastSpell(player, BG_EY_NETHERSTORM_FLAG_SPELL, true); - player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive); if (player->GetTeam() == ALLIANCE) SendBroadcastText(BG_EY_TEXT_TAKEN_FLAG, CHAT_MSG_BG_SYSTEM_ALLIANCE, player); @@ -811,7 +811,7 @@ void BattlegroundEY::EventPlayerCapturedFlag(Player* player, uint32 BgObjectType m_FlagState = BG_EY_FLAG_STATE_WAIT_RESPAWN; player->RemoveAurasDueToSpell(BG_EY_NETHERSTORM_FLAG_SPELL); - player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive); if (player->GetTeam() == ALLIANCE) { diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp index fbdaa647090..68a064a7395 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.cpp @@ -287,7 +287,7 @@ void BattlegroundWS::EventPlayerCapturedFlag(Player* player) uint32 winner = 0; - player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive); if (player->GetTeam() == ALLIANCE) { if (!IsHordeFlagPickedup()) @@ -563,7 +563,7 @@ void BattlegroundWS::EventPlayerClickedOnFlag(Player* player, GameObject* target //target_obj->Delete(); } - player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive); } void BattlegroundWS::RemovePlayer(Player* player, ObjectGuid guid, uint32 /*team*/) diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp index 0e9b871c8e5..5aaa063a0d8 100644 --- a/src/server/game/Combat/ThreatManager.cpp +++ b/src/server/game/Combat/ThreatManager.cpp @@ -334,7 +334,7 @@ HostileReference* ThreatContainer::selectNextVictim(Creature* attacker, HostileR ASSERT(target); // if the ref has status online the target must be there ! // some units are prefered in comparison to others - if (!noPriorityTargetFound && (target->IsImmunedToDamage(attacker->GetMeleeDamageSchoolMask()) || target->HasNegativeAuraWithInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE))) + if (!noPriorityTargetFound && (target->IsImmunedToDamage(attacker->GetMeleeDamageSchoolMask()) || target->HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags::Damage))) { if (iter != lastRef) { diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 6dd5de7275f..e2f970031da 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1070,7 +1070,7 @@ void Player::Update(uint32 p_time) if (u->IsPvP() && (!duel || duel->opponent != u)) { UpdatePvP(true); - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive); }*/ } } @@ -1494,7 +1494,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati InterruptNonMeleeSpells(true); //remove auras before removing from map... - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING)); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Moving | SpellAuraInterruptFlags::Turning); if (!GetSession()->PlayerLogout() && !(options & TELE_TO_SEAMLESS)) { @@ -4215,6 +4215,8 @@ void Player::BuildPlayerRepop() CastSpell(this, 20584, true); CastSpell(this, 8326, true); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Release); + // there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_SET_WATER_WALK // there must be SMSG.STOP_MIRROR_TIMER @@ -6046,9 +6048,9 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation, bool t return false; //if (movementInfo.flags & MOVEMENTFLAG_MOVING) - // mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOVE); + // mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Moving); //if (movementInfo.flags & MOVEMENTFLAG_TURNING) - // mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); + // mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Turning); // group update if (GetGroup()) @@ -22864,7 +22866,7 @@ bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc UpdateCriteria(CRITERIA_TYPE_FLIGHT_PATHS_TAKEN, 1); // prevent stealth flight - //RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); + //RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting); if (sWorld->getBoolConfig(CONFIG_INSTANT_TAXI)) { @@ -25359,6 +25361,7 @@ void Player::SummonIfPossible(bool agree) m_summon_expire = 0; UpdateCriteria(CRITERIA_TYPE_ACCEPTED_SUMMONINGS, 1); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Summon); TeleportTo(m_summon_location); } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d28da5afd8d..759a111136a 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -298,7 +298,8 @@ Unit::Unit(bool isWorldObject) : IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(), m_ControlledByPlayer(false), movespline(new Movement::MoveSpline()), i_AI(nullptr), i_disabledAI(nullptr), m_AutoRepeatFirstCast(false), m_procDeep(0), - m_removedAurasCount(0), i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_ThreatManager(this), + m_removedAurasCount(0), m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None), + i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_ThreatManager(this), m_vehicle(nullptr), m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_HostileRefManager(this), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0), _spellHistory(new SpellHistory(this)) @@ -334,7 +335,6 @@ Unit::Unit(bool isWorldObject) : m_auraUpdateIterator = m_ownedAuras.end(); - m_interruptMask.fill(0); m_transform = 0; m_canModifyStats = false; @@ -664,15 +664,22 @@ void Unit::RemoveVisibleAura(AuraApplication* aurApp) void Unit::UpdateInterruptMask() { - m_interruptMask.fill(0); + m_interruptMask = SpellAuraInterruptFlags::None; + m_interruptMask2 = SpellAuraInterruptFlags2::None; for (AuraApplication const* aurApp : m_interruptableAuras) - for (std::size_t i = 0; i < m_interruptMask.size(); ++i) - m_interruptMask[i] |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags[i]; + { + m_interruptMask |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags; + m_interruptMask2 |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags2; + } if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL]) + { if (spell->getState() == SPELL_STATE_CASTING) - for (std::size_t i = 0; i < m_interruptMask.size(); ++i) - m_interruptMask[i] |= spell->m_spellInfo->ChannelInterruptFlags[i]; + { + m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags; + m_interruptMask2 |= spell->m_spellInfo->ChannelInterruptFlags2; + } + } } bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const @@ -688,7 +695,7 @@ bool Unit::HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura) const AuraEffectList const& auras = GetAuraEffectsByType(type); for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) if ((!excludeAura || excludeAura != (*itr)->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction - (*itr)->GetSpellInfo()->HasAuraInterruptFlag(AURA_INTERRUPT_FLAG_TAKE_DAMAGE)) + (*itr)->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Damage)) return true; return false; } @@ -748,14 +755,14 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam if (damagetype != NODAMAGE) { - // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras) + // interrupting auras with SpellAuraInterruptFlags::Damage before checking !damage (absorbed damage breaks that type of auras) if (spellProto) { if (!spellProto->HasAttribute(SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS)) - victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, spellProto->Id); + victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage, spellProto->Id); } else - victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, 0); + victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage, 0); // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots) if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage) @@ -883,7 +890,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam victim->ModifyHealth(-(int32)damage); if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE) - victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0); + victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::NonPeriodicDamage, spellProto ? spellProto->Id : 0); if (victim->GetTypeId() != TYPEID_PLAYER) { @@ -930,7 +937,7 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam } if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL]) - if (spell->getState() == SPELL_STATE_CASTING && spell->m_spellInfo->HasChannelInterruptFlag(CHANNEL_FLAG_DELAY) && damagetype != DOT) + if (spell->getState() == SPELL_STATE_CASTING && spell->m_spellInfo->HasChannelInterruptFlag(SpellAuraInterruptFlags::DamageChannelDuration) && damagetype != DOT) spell->DelayedChannel(); } } @@ -2014,7 +2021,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr return; CombatStart(victim); - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Attacking); if (attType != BASE_ATTACK && attType != OFF_ATTACK) return; // ignore ranged case @@ -2095,7 +2102,7 @@ void Unit::FakeAttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BA return; CombatStart(victim); - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MELEE_ATTACK); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Attacking); if (attType != BASE_ATTACK && attType != OFF_ATTACK) return; // ignore ranged case @@ -3180,9 +3187,9 @@ void Unit::SetInWater(bool inWater) { // remove appropriate auras if we are swimming/not swimming respectively if (inWater) - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::UnderWater); else - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::AboveWater); } void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional<LiquidData> const& liquidData) @@ -3354,7 +3361,7 @@ AuraApplication * Unit::_CreateAuraApplication(Aura* aura, uint32 effMask) if (aurSpellInfo->HasAnyAuraInterruptFlag()) { m_interruptableAuras.push_back(aurApp); - AddInterruptMask(aurSpellInfo->AuraInterruptFlags); + AddInterruptMask(aurSpellInfo->AuraInterruptFlags, aurSpellInfo->AuraInterruptFlags2); } if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState()) @@ -3402,7 +3409,7 @@ void Unit::_ApplyAura(AuraApplication * aurApp, uint32 effMask) return; // Sitdown on apply aura req seated - if (aura->GetSpellInfo()->HasAuraInterruptFlag(AURA_INTERRUPT_FLAG_NOT_SEATED) && !IsSitState()) + if (aura->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing) && !IsSitState()) SetStandState(UNIT_STAND_STATE_SIT); Unit* caster = aura->GetCaster(); @@ -4031,10 +4038,22 @@ void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/) } } +template<typename InterruptFlag> +bool IsInterruptFlagIgnoredForSpell(InterruptFlag /*flag*/, Unit const* /*unit*/, SpellInfo const* /*spellInfo*/) +{ + return false; +} + +template<> +bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit const* unit, SpellInfo const* spellInfo) +{ + return flag == SpellAuraInterruptFlags::Moving && unit->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, spellInfo); +} + template <typename InterruptFlags> void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except) { - if (!(m_interruptMask[AuraInterruptFlagIndex<InterruptFlags>::value] & flag)) + if (!HasInterruptFlag(flag)) return; // interrupt auras @@ -4042,8 +4061,9 @@ void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except) { Aura* aura = (*iter)->GetBase(); ++iter; - if (aura->GetSpellInfo()->AuraInterruptFlags[AuraInterruptFlagIndex<InterruptFlags>::value] & flag && (!except || aura->GetId() != except) - && !(flag & AURA_INTERRUPT_FLAG_MOVE && HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, aura->GetSpellInfo()))) + if (aura->GetSpellInfo()->HasAuraInterruptFlag(flag) + && (!except || aura->GetId() != except) + && !IsInterruptFlagIgnoredForSpell(flag, this, aura->GetSpellInfo())) { uint32 removedAuras = m_removedAurasCount; RemoveAura(aura, AURA_REMOVE_BY_INTERRUPT); @@ -4055,9 +4075,9 @@ void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, uint32 except) // interrupt channeled spell if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL]) if (spell->getState() == SPELL_STATE_CASTING - && (spell->GetSpellInfo()->ChannelInterruptFlags[AuraInterruptFlagIndex<InterruptFlags>::value] & flag) + && spell->GetSpellInfo()->HasChannelInterruptFlag(flag) && spell->GetSpellInfo()->Id != except - && !(flag & AURA_INTERRUPT_FLAG_MOVE && HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, spell->GetSpellInfo()))) + && !IsInterruptFlagIgnoredForSpell(flag, this, spell->GetSpellInfo())) InterruptNonMeleeSpells(false); UpdateInterruptMask(); @@ -4553,11 +4573,11 @@ bool Unit::HasAuraTypeWithValue(AuraType auratype, int32 value) const template <typename InterruptFlags> bool Unit::HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid) const { - if (!(m_interruptMask[AuraInterruptFlagIndex<InterruptFlags>::value] & flag)) + if (!HasInterruptFlag(flag)) return false; for (AuraApplicationList::const_iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter) - if (!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellInfo()->AuraInterruptFlags[AuraInterruptFlagIndex<InterruptFlags>::value] & flag && + if (!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellInfo()->HasAuraInterruptFlag(flag) && (!guid || (*iter)->GetBase()->GetCasterGUID() == guid)) return true; @@ -5441,6 +5461,13 @@ void Unit::UpdateDisplayPower() SetPowerType(displayPower); } +void Unit::SetSheath(SheathState sheathed) +{ + SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::SheatheState), sheathed); + if (sheathed == SHEATH_STATE_UNARMED) + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Sheathing); +} + FactionTemplateEntry const* Unit::GetFactionTemplateEntry() const { FactionTemplateEntry const* entry = sFactionTemplateStore.LookupEntry(GetFaction()); @@ -7907,7 +7934,7 @@ void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry) player->SendMovementSetCollisionHeight(player->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount); } - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOUNT); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Mount); } void Unit::Dismount() @@ -7928,7 +7955,7 @@ void Unit::Dismount() RemoveVehicleKit(); } - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_MOUNTED); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Dismount); // only resummon old pet if the player is already added to a map // this prevents adding a pet to a not created map which would otherwise cause a crash @@ -8120,7 +8147,7 @@ void Unit::CombatStart(Unit* target, bool initialAggro) || !me->duel || me->duel->opponent != who)) { me->UpdatePvP(true); - me->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); + me->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive); } } @@ -8178,6 +8205,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy) controlled->SetInCombatState(PvP, enemy); } + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::EnteringCombat); ProcSkillsAndAuras(enemy, PROC_FLAG_ENTER_COMBAT, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); } @@ -8206,7 +8234,7 @@ void Unit::ClearInCombat() else ToPlayer()->OnCombatExit(); - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_LEAVE_COMBAT); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::LeavingCombat); } void Unit::ClearInPetCombat() @@ -10078,6 +10106,13 @@ int32 Unit::GetCreatePowers(Powers power) const return 0; } +void Unit::AddToWorld() +{ + WorldObject::AddToWorld(); + + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::EnterWorld); +} + void Unit::RemoveFromWorld() { // cleanup @@ -10092,6 +10127,7 @@ void Unit::RemoveFromWorld() RemoveCharmAuras(); RemoveBindSightAuras(); RemoveNotOwnSingleTargetAuras(); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::LeaveWorld); RemoveAllGameObjects(); RemoveAllDynObjects(); @@ -10875,7 +10911,7 @@ void Unit::SetStandState(UnitStandStateType state, uint32 animKitID /* = 0*/) SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::StandState), state); if (IsStandState()) - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_SEATED); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Standing); if (GetTypeId() == TYPEID_PLAYER) { @@ -13162,12 +13198,12 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel // TODO: Check if orientation transport offset changed instead of only global orientation if (turn) - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Turning); if (relocated) { if (!GetVehicle()) - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_MOVE); + RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Moving); // move and update visible state if need if (GetTypeId() == TYPEID_PLAYER) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index ec46f67fcb4..2b8122c6125 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -25,6 +25,7 @@ #include "HostileRefManager.h" #include "OptionalFwd.h" #include "SpellAuraDefines.h" +#include "SpellDefines.h" #include "ThreatManager.h" #include "Timer.h" #include "UnitDefines.h" @@ -943,6 +944,7 @@ class TC_GAME_API Unit : public WorldObject UnitAI* GetAI() { return i_AI; } void SetAI(UnitAI* newAI) { i_AI = newAI; } + void AddToWorld() override; void RemoveFromWorld() override; void CleanupBeforeRemoveFromMap(bool finalCleanup); @@ -1122,7 +1124,7 @@ class TC_GAME_API Unit : public WorldObject void SetEmoteState(Emote emote) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::EmoteState), emote); } SheathState GetSheath() const { return SheathState(*m_unitData->SheatheState); } - void SetSheath(SheathState sheathed) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::SheatheState), sheathed); } + void SetSheath(SheathState sheathed); // faction template id uint32 GetFaction() const { return m_unitData->FactionTemplate; } @@ -1797,10 +1799,12 @@ class TC_GAME_API Unit : public WorldObject void SetVisibleAuraUpdate(AuraApplication* aurApp) { m_visibleAurasToUpdate.insert(aurApp); } void RemoveVisibleAura(AuraApplication* aurApp); - void AddInterruptMask(std::array<uint32, 2> const& mask) + bool HasInterruptFlag(SpellAuraInterruptFlags flags) const { return m_interruptMask.HasFlag(flags); } + bool HasInterruptFlag(SpellAuraInterruptFlags2 flags) const { return m_interruptMask2.HasFlag(flags); } + void AddInterruptMask(SpellAuraInterruptFlags flags, SpellAuraInterruptFlags2 flags2) { - for (std::size_t i = 0; i < m_interruptMask.size(); ++i) - m_interruptMask[i] |= mask[i]; + m_interruptMask |= flags; + m_interruptMask2 |= flags2; } void UpdateInterruptMask(); @@ -2102,7 +2106,8 @@ class TC_GAME_API Unit : public WorldObject AuraList m_scAuras; // cast singlecast auras AuraApplicationList m_interruptableAuras; // auras which have interrupt mask applied on unit AuraStateAurasMap m_auraStateAuras; // Used for improve performance of aura state checks on aura apply/remove - std::array<uint32, 2> m_interruptMask; + EnumFlag<SpellAuraInterruptFlags> m_interruptMask; + EnumFlag<SpellAuraInterruptFlags2> m_interruptMask2; float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]; float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 4e589db6d47..c49fcbac361 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1153,6 +1153,8 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) } } + pCurrChar->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Login); + pCurrChar->SendInitialPacketsAfterAddToMap(); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ONLINE); diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index cbbb0942341..f685cfb2c1e 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -636,6 +636,9 @@ void WorldSession::HandleTextEmoteOpcode(WorldPackets::Chat::CTextEmote& packet) if (unit) if (Creature* creature = unit->ToCreature()) creature->AI()->ReceiveEmote(_player, packet.EmoteID); + + if (emoteAnim != EMOTE_ONESHOT_NONE) + _player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Anim); } void WorldSession::HandleChatIgnoredOpcode(WorldPackets::Chat::ChatReportIgnored& chatReportIgnored) diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 80158c10fad..111cfd892a8 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -295,6 +295,8 @@ void WorldSession::HandleLootOpcode(WorldPackets::Loot::LootUnit& packet) // interrupt cast if (GetPlayer()->IsNonMeleeSpellCast(false)) GetPlayer()->InterruptNonMeleeSpells(false); + + GetPlayer()->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Looting); } void WorldSession::HandleLootReleaseOpcode(WorldPackets::Loot::LootRelease& packet) diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 15d65c9a6d8..1e77f518357 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -385,8 +385,8 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem plrMover->HandleFall(movementInfo); // interrupt parachutes upon falling or landing in water - if (opcode == CMSG_MOVE_FALL_LAND || opcode == CMSG_MOVE_START_SWIM) - mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_LANDING); // Parachutes + if (opcode == CMSG_MOVE_FALL_LAND || opcode == CMSG_MOVE_START_SWIM || opcode == CMSG_MOVE_SET_FLY) + mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::LandingOrFlight); // Parachutes uint32 mstime = GameTime::GetGameTimeMS(); /*----------------------*/ @@ -409,7 +409,7 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem if (movementInfo.pos.GetOrientation() != mover->GetOrientation()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); - mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING); + mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Turning); } } } @@ -453,7 +453,7 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem if (opcode == CMSG_MOVE_JUMP) { - plrMover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_JUMP, 605); // Mind Control + plrMover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2::Jump); plrMover->ProcSkillsAndAuras(nullptr, PROC_FLAG_JUMP, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr); } } diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 4ef08588c07..b3522d1a18d 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -163,10 +163,7 @@ void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet) if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->GetFaction())) _player->GetReputationMgr().SetVisible(factionTemplateEntry); - GetPlayer()->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); - // remove fake death - //if (GetPlayer()->HasUnitState(UNIT_STATE_DIED)) - // GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + GetPlayer()->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting); // Stop the npc if moving unit->PauseMovement(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)); diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 94c3c73147e..11db09e1013 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -120,6 +120,8 @@ void WorldSession::HandleUseItemOpcode(WorldPackets::Spells::UseItem& packet) } } + user->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::ItemUse); + SpellCastTargets targets(user, packet.Cast); // Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state. diff --git a/src/server/game/Server/Packets/SpellPackets.h b/src/server/game/Server/Packets/SpellPackets.h index fa043ec305f..97775684a08 100644 --- a/src/server/game/Server/Packets/SpellPackets.h +++ b/src/server/game/Server/Packets/SpellPackets.h @@ -59,7 +59,7 @@ namespace WorldPackets void Read() override; int32 ChannelSpell = 0; - int32 Reason = 0; // 40 = /run SpellStopCasting(), 16 = movement/AURA_INTERRUPT_FLAG_MOVE, 41 = turning/AURA_INTERRUPT_FLAG_TURNING + int32 Reason = 0; // 40 = /run SpellStopCasting(), 16 = movement/SpellAuraInterruptFlags::Moving, 41 = turning/SpellAuraInterruptFlags::Turning // does not match SpellCastResult enum }; diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index e8b49494813..7f42e771a00 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1389,7 +1389,7 @@ void AuraEffect::HandleModInvisibility(AuraApplication const* aurApp, uint8 mode if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) { // drop flag at invisibiliy in bg - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); } target->UpdateObjectVisibility(); } @@ -1454,7 +1454,7 @@ void AuraEffect::HandleModStealth(AuraApplication const* aurApp, uint8 mode, boo if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) { // drop flag at stealth in bg - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); } target->UpdateObjectVisibility(); } @@ -1574,14 +1574,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app Unit* target = aurApp->GetTarget(); if (apply) - { PhasingHandler::AddPhase(target, uint32(GetMiscValueB()), true); - - // call functions which may have additional effects after chainging state of unit - // phase auras normally not expected at BG but anyway better check - // drop flag at invisibiliy in bg - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); - } else PhasingHandler::RemovePhase(target, uint32(GetMiscValueB()), true); } @@ -1594,14 +1587,7 @@ void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, boo Unit* target = aurApp->GetTarget(); if (apply) - { PhasingHandler::AddPhaseGroup(target, uint32(GetMiscValueB()), true); - - // call functions which may have additional effects after chainging state of unit - // phase auras normally not expected at BG but anyway better check - // drop flag at invisibiliy in bg - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); - } else PhasingHandler::RemovePhaseGroup(target, uint32(GetMiscValueB()), true); } @@ -1686,6 +1672,9 @@ void AuraEffect::HandleAuraModShapeshift(AuraApplication const* aurApp, uint8 mo if (!transformSpellInfo || !GetSpellInfo()->IsPositive()) target->SetDisplayId(modelid); } + + if (!shapeInfo->GetFlags().HasFlag(SpellShapeshiftFormFlags::Stance)) + target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Shapeshifting, GetId()); } else { @@ -2053,7 +2042,6 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo } } target->CombatStop(); - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); // prevent interrupt message if (GetCasterGUID() == target->GetGUID() && target->GetCurrentSpell(CURRENT_GENERIC_SPELL)) @@ -2103,10 +2091,7 @@ void AuraEffect::HandleModUnattackable(AuraApplication const* aurApp, uint8 mode // call functions which may have additional effects after chainging state of unit if (apply && (mode & AURA_EFFECT_HANDLE_REAL)) - { target->CombatStop(); - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); - } } void AuraEffect::HandleAuraModDisarm(AuraApplication const* aurApp, uint8 mode, bool apply) const @@ -3084,8 +3069,9 @@ void AuraEffect::HandleAuraModEffectImmunity(AuraApplication const* aurApp, uint m_spellInfo->ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply); // when removing flag aura, handle flag drop + // TODO: this should be handled in aura script for flag spells using AfterEffectRemove hook Player* player = target->ToPlayer(); - if (!apply && player && GetSpellInfo()->HasAuraInterruptFlag(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION)) + if (!apply && player && GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::StealthOrInvis)) { if (player->InBattleground()) { @@ -3136,13 +3122,16 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint } } - if (apply && GetMiscValue() == SPELL_SCHOOL_MASK_NORMAL) - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + // TODO: should be changed to a proc script on flag spell (they have "Taken positive" proc flags in db2) + { + if (apply && GetMiscValue() == SPELL_SCHOOL_MASK_NORMAL) + target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); - // remove all flag auras (they are positive, but they must be removed when you are immune) - if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) - && GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD)) - target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION); + // remove all flag auras (they are positive, but they must be removed when you are immune) + if (GetSpellInfo()->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY) + && GetSpellInfo()->HasAttribute(SPELL_ATTR2_DAMAGE_REDUCED_SHIELD)) + target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::StealthOrInvis); + } } void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 2458f505fde..281b603d931 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2524,7 +2524,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) // Failed Pickpocket, reveal rogue if (missInfo == SPELL_MISS_RESIST && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && unitTarget->GetTypeId() == TYPEID_UNIT) { - m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK); + m_caster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting); unitTarget->ToCreature()->EngageWithTarget(m_caster); } } @@ -2609,7 +2609,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask) return SPELL_MISS_EVADE; if (m_caster->_IsValidAttackTarget(unit, m_spellInfo)) - unit->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_HITBYSPELL); + unit->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::HostileActionReceived); else if (m_caster->IsFriendlyTo(unit)) { // for delayed spells ignore negative spells (after duel end) for friendly targets @@ -3057,15 +3057,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered // stealth must be removed at cast starting (at show channel bar) // skip triggered spell (item equip spell casting and other not explicit character casts/item uses) if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && m_spellInfo->IsBreakingStealth()) - { - m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST); - for (SpellEffectInfo const* effect : m_spellInfo->GetEffects()) - if (effect && effect->GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT) - { - m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_SPELL_ATTACK); - break; - } - } + m_caster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action); m_caster->SetCurrentCastSpell(this); SendSpellStart(); @@ -3387,6 +3379,7 @@ void Spell::_cast(bool skipCheck) if (!(hitMask & PROC_HIT_CRITICAL)) hitMask |= PROC_HIT_NORMAL; + m_originalCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::ActionDelayed); m_originalCaster->ProcSkillsAndAuras(nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); // Call CreatureAI hook OnSuccessfulSpellCast @@ -3412,14 +3405,14 @@ void Spell::handle_immediate() m_caster->ModSpellDurationTime(m_spellInfo, duration, this); m_spellState = SPELL_STATE_CASTING; - m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags); + m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags, m_spellInfo->ChannelInterruptFlags2); m_channeledDuration = duration; SendChannelStart(duration); } else if (duration == -1) { m_spellState = SPELL_STATE_CASTING; - m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags); + m_caster->AddInterruptMask(m_spellInfo->ChannelInterruptFlags, m_spellInfo->ChannelInterruptFlags2); SendChannelStart(duration); } } @@ -5031,7 +5024,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint // skip stuck spell to allow use it in falling case and apply spell limitations at movement SpellEffectInfo const* effect = m_spellInfo->GetEffect(EFFECT_0); if ((!m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || (effect && effect->Effect != SPELL_EFFECT_STUCK)) && - (IsAutoRepeat() || m_spellInfo->HasAuraInterruptFlag(AURA_INTERRUPT_FLAG_NOT_SEATED))) + (IsAutoRepeat() || m_spellInfo->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing))) return SPELL_FAILED_MOVING; } diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index 30eb419f53f..cf26e4a7c05 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -19,6 +19,7 @@ #define TRINITY_SPELLDEFINES_H #include "Define.h" +#include "EnumFlag.h" namespace UF { @@ -33,6 +34,86 @@ namespace WorldPackets } } +enum SpellInterruptFlags : uint32 +{ + SPELL_INTERRUPT_FLAG_MOVEMENT = 0x01, // why need this for instant? + SPELL_INTERRUPT_FLAG_PUSH_BACK = 0x02, // push back + SPELL_INTERRUPT_FLAG_UNK3 = 0x04, // any info? + SPELL_INTERRUPT_FLAG_INTERRUPT = 0x08, // interrupt + SPELL_INTERRUPT_FLAG_ABORT_ON_DMG = 0x10 // _complete_ interrupt on direct damage + //SPELL_INTERRUPT_UNK = 0x20 // unk, 564 of 727 spells having this spell start with "Glyph" +}; + +enum class SpellAuraInterruptFlags : uint32 +{ + None = 0, + HostileActionReceived = 0x00000001, + Damage = 0x00000002, + Action = 0x00000004, + Moving = 0x00000008, + Turning = 0x00000010, + Anim = 0x00000020, + Dismount = 0x00000040, + UnderWater = 0x00000080, // TODO: disallow casting when swimming (SPELL_FAILED_ONLY_ABOVEWATER) + AboveWater = 0x00000100, // TODO: disallow casting when not swimming (SPELL_FAILED_ONLY_UNDERWATER) + Sheathing = 0x00000200, + Interacting = 0x00000400, // TODO: more than gossip, replace all the feign death removals by aura type + Looting = 0x00000800, + Attacking = 0x00001000, + ItemUse = 0x00002000, + DamageChannelDuration = 0x00004000, + Shapeshifting = 0x00008000, + ActionDelayed = 0x00010000, + Mount = 0x00020000, + Standing = 0x00040000, + LeaveWorld = 0x00080000, + StealthOrInvis = 0x00100000, + InvulnerabilityBuff = 0x00200000, + EnterWorld = 0x00400000, + PvPActive = 0x00800000, + NonPeriodicDamage = 0x01000000, + LandingOrFlight = 0x02000000, + Release = 0x04000000, + DamageCancelsScript = 0x08000000, // NYI dedicated aura script hook + EnteringCombat = 0x10000000, + Login = 0x20000000, + Summon = 0x40000000, + LeavingCombat = 0x80000000, + + NOT_VICTIM = (HostileActionReceived | Damage | NonPeriodicDamage) +}; + +DEFINE_ENUM_FLAG(SpellAuraInterruptFlags); + +enum class SpellAuraInterruptFlags2 : uint32 +{ + None = 0, + Falling = 0x00000001, // NYI + Swimming = 0x00000002, // NYI + NotMoving = 0x00000004, // NYI + Ground = 0x00000008, // NYI + Transform = 0x00000010, // NYI + Jump = 0x00000020, + ChangeSpec = 0x00000040, // NYI + AbandonVehicle = 0x00000080, // NYI + StartOfEncounter = 0x00000100, // NYI + EndOfEncounter = 0x00000200, // NYI + Disconnect = 0x00000400, // NYI + EnteringInstance = 0x00000800, // NYI + DuelEnd = 0x00001000, // NYI + LeaveArenaOrBattleground = 0x00002000, // NYI + ChangeTalent = 0x00004000, // NYI + ChangeGlyph = 0x00008000, // NYI + SeamlessTransfer = 0x00010000, // NYI + WarModeLeave = 0x00020000, // NYI + TouchingGround = 0x00040000, // NYI + ChromieTime = 0x00080000, // NYI + SplineFlightOrFreeFlight = 0x00100000, // NYI + ProcOrPeriodicAttacking = 0x00200000 // NYI +}; + +DEFINE_ENUM_FLAG(SpellAuraInterruptFlags2); + struct SpellCastVisual { uint32 SpellXSpellVisualID = 0; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index a27ff470485..bc784f91830 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -2969,7 +2969,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex) || (spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f)) && (curSpellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE) && ((i == CURRENT_GENERIC_SPELL && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT) - || (i == CURRENT_CHANNELED_SPELL && curSpellInfo->HasChannelInterruptFlag(CHANNEL_INTERRUPT_FLAG_INTERRUPT)))) + || (i == CURRENT_CHANNELED_SPELL))) { if (m_originalCaster) { diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index aa8d5f513ea..f8cabac4d00 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1213,8 +1213,10 @@ SpellInfo::SpellInfo(SpellNameEntry const* spellName, ::Difficulty difficulty, S if (SpellInterruptsEntry const* _interrupt = data.Interrupts) { InterruptFlags = _interrupt->InterruptFlags; - std::copy(std::begin(_interrupt->AuraInterruptFlags), std::end(_interrupt->AuraInterruptFlags), AuraInterruptFlags.begin()); - std::copy(std::begin(_interrupt->ChannelInterruptFlags), std::end(_interrupt->ChannelInterruptFlags), ChannelInterruptFlags.begin()); + AuraInterruptFlags = SpellAuraInterruptFlags(_interrupt->AuraInterruptFlags[0]); + AuraInterruptFlags2 = SpellAuraInterruptFlags2(_interrupt->AuraInterruptFlags[1]); + ChannelInterruptFlags = SpellAuraInterruptFlags(_interrupt->ChannelInterruptFlags[0]); + ChannelInterruptFlags2 = SpellAuraInterruptFlags2(_interrupt->ChannelInterruptFlags[1]); } // SpellLevelsEntry @@ -1360,7 +1362,7 @@ bool SpellInfo::HasTargetType(::Targets target) const bool SpellInfo::HasAnyAuraInterruptFlag() const { - return std::find_if(AuraInterruptFlags.begin(), AuraInterruptFlags.end(), [](uint32 flag) { return flag != 0; }) != AuraInterruptFlags.end(); + return AuraInterruptFlags != SpellAuraInterruptFlags::None || AuraInterruptFlags2 != SpellAuraInterruptFlags2::None; } bool SpellInfo::IsExplicitDiscovery() const @@ -1633,7 +1635,7 @@ bool SpellInfo::IsChanneled() const bool SpellInfo::IsMoveAllowedChannel() const { - return IsChanneled() && (HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) || (!(ChannelInterruptFlags[0] & (AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING)))); + return IsChanneled() && (HasAttribute(SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING) || !ChannelInterruptFlags.HasFlag(SpellAuraInterruptFlags::Moving | SpellAuraInterruptFlags::Turning)); } bool SpellInfo::NeedsComboPoints() const @@ -2513,7 +2515,7 @@ void SpellInfo::_LoadSpellSpecific() case SPELLFAMILY_GENERIC: { // Food / Drinks (mostly) - if (HasAuraInterruptFlag(AURA_INTERRUPT_FLAG_NOT_SEATED)) + if (HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing)) { bool food = false; bool drink = false; @@ -3486,6 +3488,9 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, SpellEffectInfo const* e auraSpellInfo->Id != Id); // Don't remove self }); } + + if (apply && schoolImmunity & SPELL_SCHOOL_MASK_NORMAL) + target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::InvulnerabilityBuff); } if (uint32 mechanicImmunity = immuneInfo->MechanicImmuneMask) @@ -3516,8 +3521,13 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, SpellEffectInfo const* e } if (uint32 damageImmunity = immuneInfo->DamageSchoolMask) + { target->ApplySpellImmune(Id, IMMUNITY_DAMAGE, damageImmunity, apply); + if (apply && damageImmunity & SPELL_SCHOOL_MASK_NORMAL) + target->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::InvulnerabilityBuff); + } + for (AuraType auraType : immuneInfo->AuraTypeImmune) { target->ApplySpellImmune(Id, IMMUNITY_STATE, auraType, apply); diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 5b129755826..f453b11cb76 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -23,6 +23,7 @@ #include "Util.h" #include "Object.h" #include "SpellAuraDefines.h" +#include "SpellDefines.h" #include <boost/container/flat_set.hpp> #include <bitset> @@ -208,75 +209,6 @@ enum SpellCustomAttributes SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED = 0x01000000, }; -enum SpellInterruptFlags : uint32 -{ - SPELL_INTERRUPT_FLAG_MOVEMENT = 0x01, // why need this for instant? - SPELL_INTERRUPT_FLAG_PUSH_BACK = 0x02, // push back - SPELL_INTERRUPT_FLAG_UNK3 = 0x04, // any info? - SPELL_INTERRUPT_FLAG_INTERRUPT = 0x08, // interrupt - SPELL_INTERRUPT_FLAG_ABORT_ON_DMG = 0x10 // _complete_ interrupt on direct damage - //SPELL_INTERRUPT_UNK = 0x20 // unk, 564 of 727 spells having this spell start with "Glyph" -}; - -// See SpellAuraInterruptFlags for other values definitions -enum SpellChannelInterruptFlags : uint32 -{ - CHANNEL_INTERRUPT_FLAG_INTERRUPT = 0x08, // interrupt - CHANNEL_FLAG_DELAY = 0x4000 -}; - -enum SpellAuraInterruptFlags : uint32 -{ - AURA_INTERRUPT_FLAG_HITBYSPELL = 0x00000001, // 0 removed when getting hit by a negative spell? - AURA_INTERRUPT_FLAG_TAKE_DAMAGE = 0x00000002, // 1 removed by any damage - AURA_INTERRUPT_FLAG_CAST = 0x00000004, // 2 cast any spells - AURA_INTERRUPT_FLAG_MOVE = 0x00000008, // 3 removed by any movement - AURA_INTERRUPT_FLAG_TURNING = 0x00000010, // 4 removed by any turning - AURA_INTERRUPT_FLAG_JUMP = 0x00000020, // 5 removed by jumping - AURA_INTERRUPT_FLAG_NOT_MOUNTED = 0x00000040, // 6 removed by dismounting - AURA_INTERRUPT_FLAG_NOT_ABOVEWATER = 0x00000080, // 7 removed by entering water - AURA_INTERRUPT_FLAG_NOT_UNDERWATER = 0x00000100, // 8 removed by leaving water - AURA_INTERRUPT_FLAG_NOT_SHEATHED = 0x00000200, // 9 removed by unsheathing - AURA_INTERRUPT_FLAG_TALK = 0x00000400, // 10 talk to npc / loot? action on creature - AURA_INTERRUPT_FLAG_USE = 0x00000800, // 11 mine/use/open action on gameobject - AURA_INTERRUPT_FLAG_MELEE_ATTACK = 0x00001000, // 12 removed by attacking - AURA_INTERRUPT_FLAG_SPELL_ATTACK = 0x00002000, // 13 ??? - AURA_INTERRUPT_FLAG_UNK14 = 0x00004000, // 14 - AURA_INTERRUPT_FLAG_TRANSFORM = 0x00008000, // 15 removed by transform? - AURA_INTERRUPT_FLAG_UNK16 = 0x00010000, // 16 - AURA_INTERRUPT_FLAG_MOUNT = 0x00020000, // 17 misdirect, aspect, swim speed - AURA_INTERRUPT_FLAG_NOT_SEATED = 0x00040000, // 18 removed by standing up (used by food and drink mostly and sleep/Fake Death like) - AURA_INTERRUPT_FLAG_CHANGE_MAP = 0x00080000, // 19 leaving map/getting teleported - AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION = 0x00100000, // 20 removed by auras that make you invulnerable, or make other to lose selection on you - AURA_INTERRUPT_FLAG_UNK21 = 0x00200000, // 21 - AURA_INTERRUPT_FLAG_TELEPORTED = 0x00400000, // 22 - AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT = 0x00800000, // 23 removed by entering pvp combat - AURA_INTERRUPT_FLAG_DIRECT_DAMAGE = 0x01000000, // 24 removed by any direct damage - AURA_INTERRUPT_FLAG_LANDING = 0x02000000, // 25 removed by hitting the ground - AURA_INTERRUPT_FLAG_LEAVE_COMBAT = 0x80000000, // 31 removed by leaving combat - - AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE) -}; - -enum SpellAuraInterruptFlags2 : uint32 -{ -}; - -template <typename InterruptFlag> -struct AuraInterruptFlagIndex {}; - -template <> -struct AuraInterruptFlagIndex<SpellAuraInterruptFlags> -{ - static std::size_t constexpr value = 0; -}; - -template <> -struct AuraInterruptFlagIndex<SpellAuraInterruptFlags2> -{ - static std::size_t constexpr value = 1; -}; - uint32 GetTargetFlagMask(SpellTargetObjectTypes objType); class TC_GAME_API SpellImplicitTargetInfo @@ -483,8 +415,10 @@ class TC_GAME_API SpellInfo uint32 StartRecoveryCategory = 0; uint32 StartRecoveryTime = 0; uint32 InterruptFlags = 0; - std::array<uint32, MAX_SPELL_AURA_INTERRUPT_FLAGS> AuraInterruptFlags = {}; - std::array<uint32, MAX_SPELL_AURA_INTERRUPT_FLAGS> ChannelInterruptFlags = {}; + EnumFlag<SpellAuraInterruptFlags> AuraInterruptFlags = SpellAuraInterruptFlags::None; + EnumFlag<SpellAuraInterruptFlags2> AuraInterruptFlags2 = SpellAuraInterruptFlags2::None; + EnumFlag<SpellAuraInterruptFlags> ChannelInterruptFlags = SpellAuraInterruptFlags::None; + EnumFlag<SpellAuraInterruptFlags2> ChannelInterruptFlags2 = SpellAuraInterruptFlags2::None; uint32 ProcFlags = 0; uint32 ProcChance = 0; uint32 ProcCharges = 0; @@ -565,10 +499,11 @@ class TC_GAME_API SpellInfo bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); } bool HasAnyAuraInterruptFlag() const; - bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) const { return (AuraInterruptFlags[AuraInterruptFlagIndex<SpellAuraInterruptFlags>::value] & flag) != 0; } - bool HasAuraInterruptFlag(SpellAuraInterruptFlags2 flag) const { return (AuraInterruptFlags[AuraInterruptFlagIndex<SpellAuraInterruptFlags2>::value] & flag) != 0; } + bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) const { return AuraInterruptFlags.HasFlag(flag); } + bool HasAuraInterruptFlag(SpellAuraInterruptFlags2 flag) const { return AuraInterruptFlags2.HasFlag(flag); } - bool HasChannelInterruptFlag(SpellChannelInterruptFlags flag) const { return (ChannelInterruptFlags[AuraInterruptFlagIndex<SpellAuraInterruptFlags>::value] & flag) != 0; } + bool HasChannelInterruptFlag(SpellAuraInterruptFlags flag) const { return ChannelInterruptFlags.HasFlag(flag); } + bool HasChannelInterruptFlag(SpellAuraInterruptFlags2 flag) const { return ChannelInterruptFlags2.HasFlag(flag); } bool IsExplicitDiscovery() const; bool IsLootCrafting() const; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 3b1d3a1f91b..78459cbf0d3 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2828,10 +2828,10 @@ void SpellMgr::LoadSpellInfoServerside() spellInfo.StartRecoveryCategory = fields[37].GetUInt32(); spellInfo.StartRecoveryTime = fields[38].GetUInt32(); spellInfo.InterruptFlags = fields[39].GetUInt32(); - spellInfo.AuraInterruptFlags[0] = fields[40].GetUInt32(); - spellInfo.AuraInterruptFlags[1] = fields[41].GetUInt32(); - spellInfo.ChannelInterruptFlags[0] = fields[42].GetUInt32(); - spellInfo.ChannelInterruptFlags[1] = fields[43].GetUInt32(); + spellInfo.AuraInterruptFlags = SpellAuraInterruptFlags(fields[40].GetUInt32()); + spellInfo.AuraInterruptFlags2 = SpellAuraInterruptFlags2(fields[41].GetUInt32()); + spellInfo.ChannelInterruptFlags = SpellAuraInterruptFlags(fields[42].GetUInt32()); + spellInfo.ChannelInterruptFlags2 = SpellAuraInterruptFlags2(fields[43].GetUInt32()); spellInfo.ProcFlags = fields[44].GetUInt32(); spellInfo.ProcChance = fields[45].GetUInt32(); spellInfo.ProcCharges = fields[46].GetUInt32(); @@ -3652,7 +3652,7 @@ void SpellMgr::LoadSpellInfoCorrections() // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with ApplySpellFix({ 61719 }, [](SpellInfo* spellInfo) { - spellInfo->AuraInterruptFlags[0] = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE; + spellInfo->AuraInterruptFlags = SpellAuraInterruptFlags::HostileActionReceived | SpellAuraInterruptFlags::Damage; }); ApplySpellFix({ @@ -3727,7 +3727,7 @@ void SpellMgr::LoadSpellInfoCorrections() // Test Ribbon Pole Channel ApplySpellFix({ 29726 }, [](SpellInfo* spellInfo) { - spellInfo->InterruptFlags &= ~AURA_INTERRUPT_FLAG_CAST; + spellInfo->ChannelInterruptFlags &= ~SpellAuraInterruptFlags::Action; }); // Sic'em @@ -3870,7 +3870,8 @@ void SpellMgr::LoadSpellInfoCorrections() // Spinning Up (Mimiron) ApplySpellFix({ 63414 }, [](SpellInfo* spellInfo) { - spellInfo->ChannelInterruptFlags.fill(0); + spellInfo->ChannelInterruptFlags = SpellAuraInterruptFlags::None; + spellInfo->ChannelInterruptFlags2 = SpellAuraInterruptFlags2::None; ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo) { spellEffectInfo->TargetB = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); @@ -4318,7 +4319,7 @@ void SpellMgr::LoadSpellInfoCorrections() // Threatening Gaze ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo) { - spellInfo->AuraInterruptFlags[0] |= AURA_INTERRUPT_FLAG_CAST | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_JUMP; + spellInfo->AuraInterruptFlags |= SpellAuraInterruptFlags::Action | SpellAuraInterruptFlags::Moving | SpellAuraInterruptFlags::Anim; }); // Travel Form (dummy) - cannot be cast indoors. @@ -4391,7 +4392,7 @@ void SpellMgr::LoadSpellInfoCorrections() // Blaze of Glory ApplySpellFix({ 99252 }, [](SpellInfo* spellInfo) { - spellInfo->AuraInterruptFlags[0] |= AURA_INTERRUPT_FLAG_CHANGE_MAP; + spellInfo->AuraInterruptFlags |= SpellAuraInterruptFlags::LeaveWorld; }); // ENDOF FIRELANDS SPELLS |