diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-01-15 00:52:55 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-01-15 00:52:55 +0100 |
commit | 72286dc5e4fa5db2aff012d9cd496a8a6fc514c3 (patch) | |
tree | a4835eda486b5796dc702c49430ff1438e6aa646 | |
parent | ccccf8a2b551ee1a998c3050ff7d600f69542b79 (diff) |
Core/Conditions: Initial support for UnitCondition.db2
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.cpp | 272 | ||||
-rw-r--r-- | src/server/game/Conditions/ConditionMgr.h | 2 | ||||
-rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 10 | ||||
-rw-r--r-- | src/server/game/DataStores/DBCEnums.h | 118 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 18 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 4 |
6 files changed, 413 insertions, 11 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index ed23050f57c..4f68ce82535 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -3562,3 +3562,275 @@ bool ConditionMgr::IsPlayerMeetingExpression(Player const* player, WorldStateExp return finalResult; } + +int32 GetUnitConditionVariable(Unit const* unit, Unit const* otherUnit, UnitConditionVariable variable, int32 value) +{ + switch (variable) + { + case UnitConditionVariable::Race: + return unit->GetRace(); + case UnitConditionVariable::Class: + return unit->GetClass(); + case UnitConditionVariable::Level: + return unit->GetLevel(); + case UnitConditionVariable::IsSelf: + return unit == otherUnit; + case UnitConditionVariable::IsMyPet: + return otherUnit && unit->GetCharmerOrOwnerGUID() == otherUnit->GetGUID(); + case UnitConditionVariable::IsMaster: + return otherUnit && otherUnit->GetCharmerOrOwnerGUID() == unit->GetGUID(); + case UnitConditionVariable::IsTarget: + return otherUnit && otherUnit->GetTarget() == unit->GetGUID(); + case UnitConditionVariable::CanAssist: + return otherUnit && unit->IsValidAssistTarget(otherUnit); + case UnitConditionVariable::CanAttack: + return otherUnit && unit->IsValidAttackTarget(otherUnit); + case UnitConditionVariable::HasPet: + return !unit->GetCharmedGUID().IsEmpty() || !unit->GetMinionGUID().IsEmpty(); + case UnitConditionVariable::HasWeapon: + if (Player const* player = unit->ToPlayer()) + return player->GetWeaponForAttack(BASE_ATTACK) || player->GetWeaponForAttack(OFF_ATTACK); + return unit->GetVirtualItemId(0) || unit->GetVirtualItemId(1); + case UnitConditionVariable::HealthPct: + return unit->GetHealthPct(); + case UnitConditionVariable::ManaPct: + return unit->GetPowerPct(POWER_MANA); + case UnitConditionVariable::RagePct: + return unit->GetPowerPct(POWER_RAGE); + case UnitConditionVariable::EnergyPct: + return unit->GetPowerPct(POWER_ENERGY); + case UnitConditionVariable::ComboPoints: + return unit->GetPower(POWER_COMBO_POINTS); + case UnitConditionVariable::HasHelpfulAuraSpell: + return unit->GetAuraApplication(value, [](AuraApplication const* aurApp) + { + return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0; + }) != nullptr ? value : 0; + case UnitConditionVariable::HasHelpfulAuraDispelType: + return unit->GetAuraApplication([value](AuraApplication const* aurApp) + { + return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && int32(aurApp->GetBase()->GetSpellInfo()->Dispel) == value; + }) != nullptr ? value : 0; + case UnitConditionVariable::HasHelpfulAuraMechanic: + return unit->GetAuraApplication([value](AuraApplication const* aurApp) + { + return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && (aurApp->GetBase()->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask()) & (1 << value)) != 0; + }) != nullptr ? value : 0; + case UnitConditionVariable::HasHarmfulAuraSpell: + return unit->GetAuraApplication(value, [](AuraApplication const* aurApp) + { + return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0; + }) != nullptr ? value : 0; + case UnitConditionVariable::HasHarmfulAuraDispelType: + return unit->GetAuraApplication([value](AuraApplication const* aurApp) + { + return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && int32(aurApp->GetBase()->GetSpellInfo()->Dispel) == value; + }) != nullptr ? value : 0; + case UnitConditionVariable::HasHarmfulAuraMechanic: + return unit->GetAuraApplication([value](AuraApplication const* aurApp) + { + return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && (aurApp->GetBase()->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask()) & (1 << value)) != 0; + }) != nullptr ? value : 0; + case UnitConditionVariable::HasHarmfulAuraSchool: + return unit->GetAuraApplication([value](AuraApplication const* aurApp) + { + return (aurApp->GetFlags() & AFLAG_NEGATIVE) != 0 && (aurApp->GetBase()->GetSpellInfo()->GetSchoolMask() & (1 << value)) != 0; + }) != nullptr ? value : 0; + case UnitConditionVariable::DamagePhysicalPct: + break; + case UnitConditionVariable::DamageHolyPct: + break; + case UnitConditionVariable::DamageFirePct: + break; + case UnitConditionVariable::DamageNaturePct: + break; + case UnitConditionVariable::DamageFrostPct: + break; + case UnitConditionVariable::DamageShadowPct: + break; + case UnitConditionVariable::DamageArcanePct: + break; + case UnitConditionVariable::InCombat: + break; + case UnitConditionVariable::IsMoving: + break; + case UnitConditionVariable::IsCasting: + break; + case UnitConditionVariable::IsCastingSpell: + break; + case UnitConditionVariable::IsChanneling: + break; + case UnitConditionVariable::IsChannelingSpell: + break; + case UnitConditionVariable::NumberOfMeleeAttackers: + break; + case UnitConditionVariable::IsAttackingMe: + break; + case UnitConditionVariable::Range: + break; + case UnitConditionVariable::InMeleeRange: + break; + case UnitConditionVariable::PursuitTime: + break; + case UnitConditionVariable::HasHarmfulAuraCanceledByDamage: + break; + case UnitConditionVariable::HasHarmfulAuraWithPeriodicDamage: + break; + case UnitConditionVariable::NumberOfEnemies: + break; + case UnitConditionVariable::NumberOfFriends: + break; + case UnitConditionVariable::ThreatPhysicalPct: + break; + case UnitConditionVariable::ThreatHolyPct: + break; + case UnitConditionVariable::ThreatFirePct: + break; + case UnitConditionVariable::ThreatNaturePct: + break; + case UnitConditionVariable::ThreatFrostPct: + break; + case UnitConditionVariable::ThreatShadowPct: + break; + case UnitConditionVariable::ThreatArcanePct: + break; + case UnitConditionVariable::IsInterruptible: + break; + case UnitConditionVariable::NumberOfAttackers: + break; + case UnitConditionVariable::NumberOfRangedAttackers: + break; + case UnitConditionVariable::CreatureType: + break; + case UnitConditionVariable::IsMeleeAttacking: + break; + case UnitConditionVariable::IsRangedAttacking: + break; + case UnitConditionVariable::Health: + break; + case UnitConditionVariable::SpellKnown: + break; + case UnitConditionVariable::HasHarmfulAuraEffect: + break; + case UnitConditionVariable::IsImmuneToAreaOfEffect: + break; + case UnitConditionVariable::IsPlayer: + break; + case UnitConditionVariable::DamageMagicPct: + break; + case UnitConditionVariable::DamageTotalPct: + break; + case UnitConditionVariable::ThreatMagicPct: + break; + case UnitConditionVariable::ThreatTotalPct: + break; + case UnitConditionVariable::HasCritter: + return !unit->GetCritterGUID().IsEmpty(); + case UnitConditionVariable::HasTotemInSlot1: + break; + case UnitConditionVariable::HasTotemInSlot2: + break; + case UnitConditionVariable::HasTotemInSlot3: + break; + case UnitConditionVariable::HasTotemInSlot4: + break; + case UnitConditionVariable::HasTotemInSlot5: + break; + case UnitConditionVariable::Creature: + break; + case UnitConditionVariable::StringID: + break; + case UnitConditionVariable::HasAura: + break; + case UnitConditionVariable::IsEnemy: + break; + case UnitConditionVariable::IsSpecMelee: + break; + case UnitConditionVariable::IsSpecTank: + break; + case UnitConditionVariable::IsSpecRanged: + break; + case UnitConditionVariable::IsSpecHealer: + break; + case UnitConditionVariable::IsPlayerControlledNPC: + break; + case UnitConditionVariable::IsDying: + break; + case UnitConditionVariable::PathFailCount: + break; + case UnitConditionVariable::IsMounted: + break; + case UnitConditionVariable::Label: + break; + case UnitConditionVariable::IsMySummon: + break; + case UnitConditionVariable::IsSummoner: + break; + case UnitConditionVariable::IsMyTarget: + break; + case UnitConditionVariable::Sex: + break; + case UnitConditionVariable::LevelWithinContentTuning: + break; + case UnitConditionVariable::IsFlying: + break; + case UnitConditionVariable::IsHovering: + break; + case UnitConditionVariable::HasHelpfulAuraEffect: + break; + case UnitConditionVariable::HasHelpfulAuraSchool: + return unit->GetAuraApplication([value](AuraApplication const* aurApp) + { + return (aurApp->GetFlags() & AFLAG_NEGATIVE) == 0 && (aurApp->GetBase()->GetSpellInfo()->GetSchoolMask() & (1 << value)) != 0; + }) != nullptr ? value : 0; + default: + break; + } + + return 0; +} + +bool ConditionMgr::IsUnitMeetingCondition(Unit const* unit, Unit const* otherUnit, UnitConditionEntry const* condition) +{ + for (size_t i = 0; i < MAX_UNIT_CONDITION_VALUES; ++i) + { + if (!condition->Variable[i]) + break; + + int32 unitValue = GetUnitConditionVariable(unit, otherUnit, UnitConditionVariable(condition->Variable[i]), condition->Value[i]); + bool meets = false; + switch (UnitConditionOp(condition->Op[i])) + { + case UnitConditionOp::EqualTo: + meets = unitValue == condition->Value[i]; + break; + case UnitConditionOp::NotEqualTo: + meets = unitValue != condition->Value[i]; + break; + case UnitConditionOp::LessThan: + meets = unitValue < condition->Value[i]; + break; + case UnitConditionOp::LessThanOrEqualTo: + meets = unitValue <= condition->Value[i]; + break; + case UnitConditionOp::GreaterThan: + meets = unitValue > condition->Value[i]; + break; + case UnitConditionOp::GreaterThanOrEqualTo: + meets = unitValue >= condition->Value[i]; + break; + default: + break; + } + + if (condition->GetFlags().HasFlag(UnitConditionFlags::LogicOr)) + { + if (meets) + return true; + } + else if (!meets) + return false; + } + + return !condition->GetFlags().HasFlag(UnitConditionFlags::LogicOr); +} diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index b2783cfc5f8..0daa1305e60 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -33,6 +33,7 @@ class WorldObject; class LootTemplate; struct Condition; struct PlayerConditionEntry; +struct UnitConditionEntry; struct WorldStateExpressionEntry; enum class PlayerConditionLfgStatus : uint8; @@ -304,6 +305,7 @@ class TC_GAME_API ConditionMgr static uint32 GetPlayerConditionLfgValue(Player const* player, PlayerConditionLfgStatus status); static bool IsPlayerMeetingCondition(Player const* player, PlayerConditionEntry const* condition); static bool IsPlayerMeetingExpression(Player const* player, WorldStateExpressionEntry const* expression); + static bool IsUnitMeetingCondition(Unit const* unit, Unit const* otherUnit, UnitConditionEntry const* condition); struct ConditionTypeInfo { diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 96da65fd463..10ce3fdfa7a 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -3871,13 +3871,17 @@ struct UISplashScreenEntry int32 RequiredTimeEventPassed; // serverside TimeEvent table, see ModifierTreeType::HasTimeEventPassed }; +#define MAX_UNIT_CONDITION_VALUES 8 + struct UnitConditionEntry { uint32 ID; uint8 Flags; - uint8 Variable[8]; - int8 Op[8]; - int32 Value[8]; + uint8 Variable[MAX_UNIT_CONDITION_VALUES]; + int8 Op[MAX_UNIT_CONDITION_VALUES]; + int32 Value[MAX_UNIT_CONDITION_VALUES]; + + EnumFlag<UnitConditionFlags> GetFlags() const { return static_cast<UnitConditionFlags>(Flags); } }; struct UnitPowerBarEntry diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 295eb89f451..c6dd8266cd6 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -1694,6 +1694,124 @@ enum UiMapType : int8 UI_MAP_TYPE_ORPHAN = 6, }; +enum class UnitConditionFlags : uint8 +{ + LogicOr = 0x1 +}; + +DEFINE_ENUM_FLAG(UnitConditionFlags); + +enum class UnitConditionOp : int8 +{ + EqualTo = 1, + NotEqualTo = 2, + LessThan = 3, + LessThanOrEqualTo = 4, + GreaterThan = 5, + GreaterThanOrEqualTo = 6 +}; + +enum class UnitConditionVariable : uint8 +{ + None = 0, // - NONE - + Race = 1, // Race {$Is/Is Not} "{ChrRaces}" + Class = 2, // Class {$Is/Is Not} "{ChrClasses}" + Level = 3, // Level {$Relative Op} "{#Level}" + IsSelf = 4, // Is self? {$Yes/No}{=1} + IsMyPet = 5, // Is my pet? {$Yes/No}{=1} + IsMaster = 6, // Is master? {$Yes/No}{=1} + IsTarget = 7, // Is target? {$Yes/No}{=1} + CanAssist = 8, // Can assist? {$Yes/No}{=1} + CanAttack = 9, // Can attack? {$Yes/No}{=1} + HasPet = 10, // Has pet? {$Yes/No}{=1} + HasWeapon = 11, // Has weapon? {$Yes/No}{=1} + HealthPct = 12, // Health {$Relative Op} {#Health %}% + ManaPct = 13, // Mana {$Relative Op} {#Mana %}% + RagePct = 14, // Rage {$Relative Op} {#Rage %}% + EnergyPct = 15, // Energy {$Relative Op} {#Energy %}% + ComboPoints = 16, // Combo Points {$Relative Op} {#Points} + HasHelpfulAuraSpell = 17, // Has helpful aura spell? {$Yes/No} "{Spell}" + HasHelpfulAuraDispelType = 18, // Has helpful aura dispel type? {$Yes/No} "{SpellDispelType}" + HasHelpfulAuraMechanic = 19, // Has helpful aura mechanic? {$Yes/No} "{SpellMechanic}" + HasHarmfulAuraSpell = 20, // Has harmful aura spell? {$Yes/No} "{Spell}" + HasHarmfulAuraDispelType = 21, // Has harmful aura dispel type? {$Yes/No} "{SpellDispelType}" + HasHarmfulAuraMechanic = 22, // Has harmful aura mechanic? {$Yes/No} "{SpellMechanic}" + HasHarmfulAuraSchool = 23, // Has harmful aura school? {$Yes/No} "{Resistances}" + DamagePhysicalPct = 24, // NYI Damage (Physical) {$Relative Op} {#Physical Damage %}% + DamageHolyPct = 25, // NYI Damage (Holy) {$Relative Op} {#Holy Damage %}% + DamageFirePct = 26, // NYI Damage (Fire) {$Relative Op} {#Fire Damage %}% + DamageNaturePct = 27, // NYI Damage (Nature) {$Relative Op} {#Nature Damage %}% + DamageFrostPct = 28, // NYI Damage (Frost) {$Relative Op} {#Frost Damage %}% + DamageShadowPct = 29, // NYI Damage (Shadow) {$Relative Op} {#Shadow Damage %}% + DamageArcanePct = 30, // NYI Damage (Arcane) {$Relative Op} {#Arcane Damage %}% + InCombat = 31, // NYI In combat? {$Yes/No}{=1} + IsMoving = 32, // NYI Is moving? {$Yes/No}{=1} + IsCasting = 33, // NYI Is casting? {$Yes/No}{=1} + IsCastingSpell = 34, // NYI Is casting spell? {$Yes/No}{=1} + IsChanneling = 35, // NYI Is channeling? {$Yes/No}{=1} + IsChannelingSpell = 36, // NYI Is channeling spell? {$Yes/No}{=1} + NumberOfMeleeAttackers = 37, // NYI Number of melee attackers {$Relative Op} {#Attackers} + IsAttackingMe = 38, // NYI Is attacking me? {$Yes/No}{=1} + Range = 39, // NYI Range {$Relative Op} {#Yards} + InMeleeRange = 40, // NYI In melee range? {$Yes/No}{=1} + PursuitTime = 41, // NYI Pursuit time {$Relative Op} {#Seconds} + HasHarmfulAuraCanceledByDamage = 42, // NYI Has harmful aura canceled by damage? {$Yes/No}{=1} + HasHarmfulAuraWithPeriodicDamage = 43, // NYI Has harmful aura with periodic damage? {$Yes/No}{=1} + NumberOfEnemies = 44, // NYI Number of enemies {$Relative Op} {#Enemies} + NumberOfFriends = 45, // NYI Number of friends {$Relative Op} {#Friends} + ThreatPhysicalPct = 46, // NYI Threat (Physical) {$Relative Op} {#Physical Threat %}% + ThreatHolyPct = 47, // NYI Threat (Holy) {$Relative Op} {#Holy Threat %}% + ThreatFirePct = 48, // NYI Threat (Fire) {$Relative Op} {#Fire Threat %}% + ThreatNaturePct = 49, // NYI Threat (Nature) {$Relative Op} {#Nature Threat %}% + ThreatFrostPct = 50, // NYI Threat (Frost) {$Relative Op} {#Frost Threat %}% + ThreatShadowPct = 51, // NYI Threat (Shadow) {$Relative Op} {#Shadow Threat %}% + ThreatArcanePct = 52, // NYI Threat (Arcane) {$Relative Op} {#Arcane Threat %}% + IsInterruptible = 53, // NYI Is interruptible? {$Yes/No}{=1} + NumberOfAttackers = 54, // NYI Number of attackers {$Relative Op} {#Attackers} + NumberOfRangedAttackers = 55, // NYI Number of ranged attackers {$Relative Op} {#Ranged Attackers} + CreatureType = 56, // NYI Creature type {$Is/Is Not} "{CreatureType}" + IsMeleeAttacking = 57, // NYI Is melee-attacking? {$Yes/No}{=1} + IsRangedAttacking = 58, // NYI Is ranged-attacking? {$Yes/No}{=1} + Health = 59, // NYI Health {$Relative Op} {#HP} HP + SpellKnown = 60, // NYI Spell known? {$Yes/No} "{Spell}" + HasHarmfulAuraEffect = 61, // NYI Has harmful aura effect? {$Yes/No} "{#Spell Aura}" + IsImmuneToAreaOfEffect = 62, // NYI Is immune to area-of-effect? {$Yes/No}{=1} + IsPlayer = 63, // NYI Is player? {$Yes/No}{=1} + DamageMagicPct = 64, // NYI Damage (Magic) {$Relative Op} {#Magic Damage %}% + DamageTotalPct = 65, // NYI Damage (Total) {$Relative Op} {#Damage %}% + ThreatMagicPct = 66, // NYI Threat (Magic) {$Relative Op} {#Magic Threat %}% + ThreatTotalPct = 67, // NYI Threat (Total) {$Relative Op} {#Threat %}% + HasCritter = 68, // NYI Has critter? {$Yes/No}{=1} + HasTotemInSlot1 = 69, // NYI Has totem in slot 1? {$Yes/No}{=1} + HasTotemInSlot2 = 70, // NYI Has totem in slot 2? {$Yes/No}{=1} + HasTotemInSlot3 = 71, // NYI Has totem in slot 3? {$Yes/No}{=1} + HasTotemInSlot4 = 72, // NYI Has totem in slot 4? {$Yes/No}{=1} + HasTotemInSlot5 = 73, // NYI Has totem in slot 5? {$Yes/No}{=1} + Creature = 74, // NYI Creature {$Is/Is Not} "{Creature}" + StringID = 75, // NYI String ID {$Is/Is Not} "{StringID}" + HasAura = 76, // NYI Has aura? {$Yes/No} {Spell} + IsEnemy = 77, // NYI Is enemy? {$Yes/No}{=1} + IsSpecMelee = 78, // NYI Is spec - melee? {$Yes/No}{=1} + IsSpecTank = 79, // NYI Is spec - tank? {$Yes/No}{=1} + IsSpecRanged = 80, // NYI Is spec - ranged? {$Yes/No}{=1} + IsSpecHealer = 81, // NYI Is spec - healer? {$Yes/No}{=1} + IsPlayerControlledNPC = 82, // NYI Is player controlled NPC? {$Yes/No}{=1} + IsDying = 83, // NYI Is dying? {$Yes/No}{=1} + PathFailCount = 84, // NYI Path fail count {$Relative Op} {#Path Fail Count} + IsMounted = 85, // NYI Is mounted? {$Yes/No}{=1} + Label = 86, // NYI Label {$Is/Is Not} "{Label}" + IsMySummon = 87, // NYI + IsSummoner = 88, // NYI + IsMyTarget = 89, // NYI + Sex = 90, // NYI Sex {$Is/Is Not} "{UnitSex}" + LevelWithinContentTuning = 91, // NYI Level is within {$Is/Is Not} {ContentTuning} + + IsFlying = 93, // NYI Is flying? {$Yes/No}{=1} + IsHovering = 94, // NYI Is hovering? {$Yes/No}{=1} + HasHelpfulAuraEffect = 95, // NYI Has helpful aura effect? {$Yes/No} "{#Spell Aura}" + HasHelpfulAuraSchool = 96, // Has helpful aura school? {$Yes/No} "{Resistances}" +}; + enum VehicleSeatFlags { VEHICLE_SEAT_FLAG_HAS_LOWER_ANIM_FOR_ENTER = 0x00000001, diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index a8726bc1595..7044d665667 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -4285,21 +4285,27 @@ bool SpellInfo::IsHighRankOf(SpellInfo const* spellInfo) const return false; } -uint32 SpellInfo::GetSpellXSpellVisualId(WorldObject const* caster /*= nullptr*/) const +uint32 SpellInfo::GetSpellXSpellVisualId(WorldObject const* caster /*= nullptr*/, WorldObject const* viewer /*= nullptr*/) const { for (SpellXSpellVisualEntry const* visual : _visuals) { - PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(visual->CasterPlayerConditionID); - if (!playerCondition || (caster && caster->GetTypeId() == TYPEID_PLAYER && sConditionMgr->IsPlayerMeetingCondition(caster->ToPlayer(), playerCondition))) - return visual->ID; + if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(visual->CasterPlayerConditionID)) + if (!caster || !caster->IsPlayer() || !ConditionMgr::IsPlayerMeetingCondition(caster->ToPlayer(), playerCondition)) + continue; + + if (UnitConditionEntry const* unitCondition = sUnitConditionStore.LookupEntry(visual->CasterUnitConditionID)) + if (!caster || !caster->IsUnit() || !ConditionMgr::IsUnitMeetingCondition(caster->ToUnit(), viewer->ToUnit(), unitCondition)) + continue; + + return visual->ID; } return 0; } -uint32 SpellInfo::GetSpellVisual(WorldObject const* caster /*= nullptr*/) const +uint32 SpellInfo::GetSpellVisual(WorldObject const* caster /*= nullptr*/, WorldObject const* viewer /*= nullptr*/) const { - if (SpellXSpellVisualEntry const* visual = sSpellXSpellVisualStore.LookupEntry(GetSpellXSpellVisualId(caster))) + if (SpellXSpellVisualEntry const* visual = sSpellXSpellVisualStore.LookupEntry(GetSpellXSpellVisualId(caster, viewer))) { //if (visual->LowViolenceSpellVisualID && forPlayer->GetViolenceLevel() operator 2) // return visual->LowViolenceSpellVisualID; diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 7e29f202a73..420155343e0 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -573,8 +573,8 @@ class TC_GAME_API SpellInfo bool IsDifferentRankOf(SpellInfo const* spellInfo) const; bool IsHighRankOf(SpellInfo const* spellInfo) const; - uint32 GetSpellXSpellVisualId(WorldObject const* caster = nullptr) const; - uint32 GetSpellVisual(WorldObject const* caster = nullptr) const; + uint32 GetSpellXSpellVisualId(WorldObject const* caster = nullptr, WorldObject const* viewer = nullptr) const; + uint32 GetSpellVisual(WorldObject const* caster = nullptr, WorldObject const* viewer = nullptr) const; std::vector<SpellEffectInfo> const& GetEffects() const { return _effects; } SpellEffectInfo const& GetEffect(SpellEffIndex index) const { ASSERT(index < _effects.size()); return _effects[index]; } |