Core/Spells: rework part 5: GameObject casting

Port From (https://github.com/TrinityCore/TrinityCore/commit/962f6d7988b9003e550f6745be7cff812e9d8efa)
This commit is contained in:
hondacrx
2021-08-29 18:27:08 -04:00
parent e97ffa304d
commit 949d4806c5
39 changed files with 5236 additions and 4781 deletions
-328
View File
@@ -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)