Core/Spells: rework part 5: GameObject casting
Port From (https://github.com/TrinityCore/TrinityCore/commit/962f6d7988b9003e550f6745be7cff812e9d8efa)
This commit is contained in:
@@ -631,43 +631,6 @@ namespace Game.Entities
|
||||
|
||||
public void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value) { m_weaponDamage[(int)attType][(int)damageRange] = value; }
|
||||
|
||||
public Unit GetMagicHitRedirectTarget(Unit victim, SpellInfo spellInfo)
|
||||
{
|
||||
// Patch 1.2 notes: Spell Reflection no longer reflects abilities
|
||||
if (spellInfo.HasAttribute(SpellAttr0.Ability) || spellInfo.HasAttribute(SpellAttr1.CantBeRedirected) || spellInfo.HasAttribute(SpellAttr0.UnaffectedByInvulnerability))
|
||||
return victim;
|
||||
|
||||
var magnetAuras = victim.GetAuraEffectsByType(AuraType.SpellMagnet);
|
||||
foreach (var eff in magnetAuras)
|
||||
{
|
||||
Unit magnet = eff.GetBase().GetCaster();
|
||||
if (magnet != null)
|
||||
{
|
||||
if (spellInfo.CheckExplicitTarget(this, magnet) == SpellCastResult.SpellCastOk && IsValidAttackTarget(magnet, spellInfo))
|
||||
{
|
||||
// @todo handle this charge drop by proc in cast phase on explicit target
|
||||
if (spellInfo.HasHitDelay())
|
||||
{
|
||||
// Set up missile speed based delay
|
||||
float hitDelay = spellInfo.LaunchDelay;
|
||||
if (spellInfo.HasAttribute(SpellAttr9.SpecialDelayCalculation))
|
||||
hitDelay += spellInfo.Speed;
|
||||
else if (spellInfo.Speed > 0.0f)
|
||||
hitDelay += Math.Max(victim.GetDistance(this), 5.0f) / spellInfo.Speed;
|
||||
|
||||
uint delay = (uint)Math.Floor(hitDelay * 1000.0f);
|
||||
// Schedule charge drop
|
||||
eff.GetBase().DropChargeDelayed(delay, AuraRemoveMode.Expire);
|
||||
}
|
||||
else
|
||||
eff.GetBase().DropCharge(AuraRemoveMode.Expire);
|
||||
return magnet;
|
||||
}
|
||||
}
|
||||
}
|
||||
return victim;
|
||||
}
|
||||
|
||||
public Unit GetMeleeHitRedirectTarget(Unit victim, SpellInfo spellInfo = null)
|
||||
{
|
||||
var interceptAuras = victim.GetAuraEffectsByType(AuraType.InterceptMeleeRangedAttacks);
|
||||
@@ -753,17 +716,6 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
internal void SendCombatLogMessage(CombatLogServerPacket combatLog)
|
||||
{
|
||||
CombatLogSender combatLogSender = new(combatLog);
|
||||
|
||||
if (IsPlayer())
|
||||
combatLogSender.Invoke(ToPlayer());
|
||||
|
||||
var notifier = new MessageDistDeliverer<CombatLogSender>(this, combatLogSender, GetVisibilityRange());
|
||||
Cell.VisitWorldObjects(this, notifier, GetVisibilityRange());
|
||||
}
|
||||
|
||||
bool IsThreatened()
|
||||
{
|
||||
return !m_threatManager.IsThreatListEmpty();
|
||||
@@ -1562,286 +1514,6 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
// function based on function Unit::CanAttack from 13850 client
|
||||
public bool IsValidAttackTarget(WorldObject target, SpellInfo bySpell = null, bool spellCheck = true)
|
||||
{
|
||||
Cypher.Assert(target != null);
|
||||
|
||||
// can't attack self
|
||||
if (this == target)
|
||||
return false;
|
||||
|
||||
// can't attack GMs
|
||||
if (target.IsPlayer() && target.ToPlayer().IsGameMaster())
|
||||
return false;
|
||||
|
||||
Unit unit = ToUnit();
|
||||
Unit targetUnit = target.ToUnit();
|
||||
|
||||
// CvC case - can attack each other only when one of them is hostile
|
||||
if (unit && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && targetUnit && !targetUnit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
return IsHostileTo(target) || target.IsHostileTo(this);
|
||||
|
||||
// PvP, PvC, CvP case
|
||||
// can't attack friendly targets
|
||||
if (IsFriendlyTo(target) || target.IsFriendlyTo(this))
|
||||
return false;
|
||||
|
||||
Player playerAffectingAttacker = unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
|
||||
Player playerAffectingTarget = targetUnit && targetUnit.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
|
||||
|
||||
// Not all neutral creatures can be attacked (even some unfriendly faction does not react aggresive to you, like Sporaggar)
|
||||
if ((playerAffectingAttacker && !playerAffectingTarget) || (!playerAffectingAttacker && playerAffectingTarget))
|
||||
{
|
||||
Player player = playerAffectingAttacker ? playerAffectingAttacker : playerAffectingTarget;
|
||||
Unit creature = playerAffectingAttacker ? targetUnit : unit;
|
||||
if (creature != null)
|
||||
{
|
||||
if (creature.IsContestedGuard() && player.HasPlayerFlag(PlayerFlags.ContestedPVP))
|
||||
return true;
|
||||
|
||||
var factionTemplate = creature.GetFactionTemplateEntry();
|
||||
if (factionTemplate != null)
|
||||
{
|
||||
if (player.GetReputationMgr().GetForcedRankIfAny(factionTemplate) == 0)
|
||||
{
|
||||
var factionEntry = CliDB.FactionStorage.LookupByKey(factionTemplate.Faction);
|
||||
if (factionEntry != null)
|
||||
{
|
||||
var repState = player.GetReputationMgr().GetState(factionEntry);
|
||||
if (repState != null)
|
||||
if (!repState.Flags.HasFlag(ReputationFlags.AtWar))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Creature creatureAttacker = ToCreature();
|
||||
if (creatureAttacker && creatureAttacker.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit))
|
||||
return false;
|
||||
|
||||
if (bySpell == null)
|
||||
spellCheck = false;
|
||||
|
||||
if (spellCheck && !IsValidSpellAttackTarget(target, bySpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsValidSpellAttackTarget(WorldObject target, SpellInfo bySpell)
|
||||
{
|
||||
Cypher.Assert(target != null);
|
||||
Cypher.Assert(bySpell != null);
|
||||
|
||||
// can't attack unattackable units
|
||||
Unit unitTarget = target.ToUnit();
|
||||
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
|
||||
return false;
|
||||
|
||||
Unit unit = ToUnit();
|
||||
// visibility checks (only units)
|
||||
if (unit)
|
||||
{
|
||||
// can't attack invisible
|
||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetInvisible))
|
||||
{
|
||||
if (!unit.CanSeeOrDetect(target, bySpell.IsAffectingArea()))
|
||||
return false;
|
||||
|
||||
/*
|
||||
else if (!obj)
|
||||
{
|
||||
// ignore stealth for aoe spells. Ignore stealth if target is player and unit in combat with same player
|
||||
bool const ignoreStealthCheck = (bySpell && bySpell.IsAffectingArea()) ||
|
||||
(target.GetTypeId() == TYPEID_PLAYER && target.HasStealthAura() && IsInCombatWith(target));
|
||||
|
||||
if (!CanSeeOrDetect(target, ignoreStealthCheck))
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// can't attack dead
|
||||
if (!bySpell.IsAllowingDeadTarget() && unitTarget && !unitTarget.IsAlive())
|
||||
return false;
|
||||
|
||||
// can't attack untargetable
|
||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
|
||||
return false;
|
||||
|
||||
Player playerAttacker = ToPlayer();
|
||||
if (playerAttacker != null)
|
||||
{
|
||||
if (playerAttacker.HasPlayerFlag(PlayerFlags.Uber))
|
||||
return false;
|
||||
}
|
||||
|
||||
// check flags
|
||||
if (unitTarget != null && unitTarget.HasUnitFlag(UnitFlags.NonAttackable | UnitFlags.TaxiFlight | UnitFlags.NotAttackable1 | UnitFlags.Unk16))
|
||||
return false;
|
||||
|
||||
if (unit != null && !unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (unitTarget != null && !unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToNPC())
|
||||
return false;
|
||||
|
||||
if (!bySpell.HasAttribute(SpellAttr8.AttackIgnoreImmuneToPCFlag))
|
||||
{
|
||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) && unitTarget && unitTarget.IsImmuneToPC())
|
||||
return false;
|
||||
|
||||
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) && unit && unit.IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
|
||||
// check duel - before sanctuary checks
|
||||
Player playerAffectingAttacker = unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) ? GetAffectingPlayer() : null;
|
||||
Player playerAffectingTarget = unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable) ? target.GetAffectingPlayer() : null;
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
if (playerAffectingAttacker.duel != null && playerAffectingAttacker.duel.opponent == playerAffectingTarget && playerAffectingAttacker.duel.startTime != 0)
|
||||
return true;
|
||||
|
||||
// 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(UnitFlags.PvpAttackable) && unit && unit.HasUnitFlag(UnitFlags.PvpAttackable) && (unitTarget.IsInSanctuary() || unit.IsInSanctuary()))
|
||||
return false;
|
||||
|
||||
// additional checks - only PvP case
|
||||
if (playerAffectingAttacker && playerAffectingTarget)
|
||||
{
|
||||
if (unitTarget.IsPvP())
|
||||
return true;
|
||||
|
||||
if (unit.IsFFAPvP() && unitTarget.IsFFAPvP())
|
||||
return true;
|
||||
|
||||
return unit.HasPvpFlag(UnitPVPStateFlags.Unk1) ||
|
||||
unitTarget.HasPvpFlag(UnitPVPStateFlags.Unk1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// function based on function Unit::CanAssist from 13850 client
|
||||
public bool IsValidAssistTarget(WorldObject target, SpellInfo bySpell = null, bool spellCheck = true)
|
||||
{
|
||||
Cypher.Assert(target != null);
|
||||
|
||||
// can assist to self
|
||||
if (this == target)
|
||||
return true;
|
||||
|
||||
// can't assist GMs
|
||||
if (target.IsPlayer() && target.ToPlayer().IsGameMaster())
|
||||
return false;
|
||||
|
||||
// can't assist non-friendly targets
|
||||
if (GetReactionTo(target) < ReputationRank.Neutral && target.GetReactionTo(this) < ReputationRank.Neutral && (!ToCreature() || !ToCreature().GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit)))
|
||||
return false;
|
||||
|
||||
if (bySpell == null)
|
||||
spellCheck = false;
|
||||
|
||||
if (spellCheck && !IsValidSpellAssistTarget(target, bySpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsValidSpellAssistTarget(WorldObject target, SpellInfo bySpell)
|
||||
{
|
||||
Cypher.Assert(target != null);
|
||||
Cypher.Assert(bySpell != null);
|
||||
|
||||
// can't assist unattackable units
|
||||
Unit unitTarget = target.ToUnit();
|
||||
if (unitTarget && unitTarget.HasUnitState(UnitState.Unattackable))
|
||||
return false;
|
||||
|
||||
// can't assist own vehicle or passenger
|
||||
Unit unit = ToUnit();
|
||||
if (unit && unitTarget && unit.GetVehicle())
|
||||
{
|
||||
if (unit.IsOnVehicle(unitTarget))
|
||||
return false;
|
||||
|
||||
if (unit.GetVehicleBase().IsOnVehicle(unitTarget))
|
||||
return false;
|
||||
}
|
||||
|
||||
// can't assist invisible
|
||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetInvisible) && !CanSeeOrDetect(target, bySpell.IsAffectingArea()))
|
||||
return false;
|
||||
|
||||
// can't assist dead
|
||||
if (!bySpell.IsAllowingDeadTarget() && unitTarget && !unitTarget.IsAlive())
|
||||
return false;
|
||||
|
||||
// can't assist untargetable
|
||||
if (!bySpell.HasAttribute(SpellAttr6.CanTargetUntargetable) && unitTarget && unitTarget.HasUnitFlag(UnitFlags.NotSelectable))
|
||||
return false;
|
||||
|
||||
if (!bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
||||
{
|
||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
if (unitTarget && unitTarget.IsImmuneToPC())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unitTarget && unitTarget.IsImmuneToNPC())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// PvP case
|
||||
if (unitTarget && unitTarget.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
Player targetPlayerOwner = target.GetAffectingPlayer();
|
||||
if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
Player selfPlayerOwner = GetAffectingPlayer();
|
||||
if (selfPlayerOwner && targetPlayerOwner)
|
||||
{
|
||||
// can't assist player which is dueling someone
|
||||
if (selfPlayerOwner != targetPlayerOwner && targetPlayerOwner.duel != null)
|
||||
return false;
|
||||
}
|
||||
// can't assist player in ffa_pvp zone from outside
|
||||
if (unitTarget.IsFFAPvP() && unit && !unit.IsFFAPvP())
|
||||
return false;
|
||||
|
||||
// can't assist player out of sanctuary from sanctuary if has pvp enabled
|
||||
if (unitTarget.IsPvP())
|
||||
if (unit && unit.IsInSanctuary() && !unitTarget.IsInSanctuary())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// PvC case - player can assist creature only if has specific type flags
|
||||
// !target.HasFlag(UNIT_FIELD_FLAGS, UnitFlags.PvpAttackable) &&
|
||||
else if (unit && unit.HasUnitFlag(UnitFlags.PvpAttackable))
|
||||
{
|
||||
if (!bySpell.HasAttribute(SpellAttr6.AssistIgnoreImmuneFlag))
|
||||
{
|
||||
if (unitTarget && !unitTarget.IsPvP())
|
||||
{
|
||||
Creature creatureTarget = target.ToCreature();
|
||||
if (creatureTarget != null)
|
||||
return creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.TreatAsRaidUnit) || creatureTarget.GetCreatureTemplate().TypeFlags.HasFlag(CreatureTypeFlags.CanAssist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect aurEff) { return true; }
|
||||
|
||||
public void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
|
||||
|
||||
Reference in New Issue
Block a user