/// <summary> /// Checks whether the given target is valid for the given caster. /// Is called automatically when SpellCast selects Targets. /// Does not do maximum range check. /// </summary> public SpellFailedReason CheckValidTarget(WorldObject caster, WorldObject target) { if (target is Unit) { // AuraState if (RequiredTargetAuraState != 0 || ExcludeTargetAuraState != 0) { var state = ((Unit)target).AuraState; if ((RequiredTargetAuraState != 0 && !state.HasAnyFlag(RequiredTargetAuraState)) || (ExcludeTargetAuraState != 0 && state.HasAnyFlag(ExcludeTargetAuraState))) { return SpellFailedReason.TargetAurastate; } } // Required Auras if ((ExcludeTargetAuraId != 0 && ((Unit)target).Auras.Contains(ExcludeTargetAuraId)) || (RequiredTargetAuraId != 0 && !((Unit)target).Auras.Contains(RequiredTargetAuraId))) { return SpellFailedReason.TargetAurastate; } } // Make sure that we have a GameObject if the Spell requires one if (TargetFlags.HasAnyFlag(SpellTargetFlags.UnkUnit_0x100) && (!(target is GameObject) || !target.IsInWorld)) { return SpellFailedReason.BadTargets; } // CreatureTypes if (TargetCreatureTypes != TargetCreatureMask.None && (!(target is NPC) || !((NPC)target).CheckCreatureType(TargetCreatureTypes))) { return SpellFailedReason.BadImplicitTargets; } if (!CanCastOnPlayer && target is Character) { return SpellFailedReason.BadImplicitTargets; } // Corpse target if (ReqDeadTarget) { if (TargetFlags.HasAnyFlag(SpellTargetFlags.PvPCorpse | SpellTargetFlags.Corpse)) { if (!(target is Corpse) || (TargetFlags.HasAnyFlag(SpellTargetFlags.PvPCorpse) && !caster.IsHostileWith(target))) { return SpellFailedReason.BadImplicitTargets; } } else if (!(target is NPC) || ((NPC)target).IsAlive || target.Loot != null) { // need to be dead and looted empty return SpellFailedReason.TargetNotDead; } } else { if (target is Unit && !((Unit)target).IsAlive) { return SpellFailedReason.TargetsDead; } } // Rogues do it from behind if (AttributesExB.HasFlag(SpellAttributesExB.RequiresBehindTarget)) { if (!caster.IsBehind(target)) { return SpellFailedReason.NotBehind; } } if (AttributesExC.HasFlag(SpellAttributesExC.NoInitialAggro)) { if (target is Unit && ((Unit)target).IsInCombat) { return SpellFailedReason.TargetAffectingCombat; } } if (Range.MinDist > 0 && //caster.IsInRadius(target, caster.GetSpellMinRange(Range.MinDist, target))) caster.IsInRadius(target, Range.MinDist)) { return SpellFailedReason.TooClose; } return SpellFailedReason.Ok; }