Core/Creatures: Implement CREATURE_STATIC_FLAG_4_IGNORE_LOS_WHEN_CASTING_ON_ME

Port From (https://github.com/TrinityCore/TrinityCore/commit/815e158a3ec5f5e173376ff4273913990e9bce10)
This commit is contained in:
hondacrx
2023-07-01 09:09:57 -04:00
parent 6adc16c496
commit 74d8682426
4 changed files with 54 additions and 29 deletions
@@ -87,7 +87,7 @@ namespace Game.Collision
public bool IsInLineOfSight(uint mapId, float x1, float y1, float z1, float x2, float y2, float z2, ModelIgnoreFlags ignoreFlags)
{
if (!IsLineOfSightCalcEnabled() || Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapLOS))
if (!IsLineOfSightCalcEnabled() || Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapLOS))
return true;
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
@@ -104,7 +104,7 @@ namespace Game.Collision
public bool GetObjectHitPos(uint mapId, float x1, float y1, float z1, float x2, float y2, float z2, out float rx, out float ry, out float rz, float modifyDist)
{
if (IsLineOfSightCalcEnabled() && !Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapLOS))
if (IsLineOfSightCalcEnabled() && !Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapLOS))
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -130,7 +130,7 @@ namespace Game.Collision
public float GetHeight(uint mapId, float x, float y, float z, float maxSearchDist)
{
if (IsHeightCalcEnabled() && !Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapHeight))
if (IsHeightCalcEnabled() && !Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapHeight))
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -153,7 +153,7 @@ namespace Game.Collision
adtId = 0;
rootId = 0;
groupId = 0;
if (!Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapAreaFlag))
if (!Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapAreaFlag))
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -171,7 +171,7 @@ namespace Game.Collision
public bool GetLiquidLevel(uint mapId, float x, float y, float z, uint reqLiquidType, ref float level, ref float floor, ref uint type, ref uint mogpFlags)
{
if (!Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapLiquidStatus))
if (!Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapLiquidStatus))
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -198,7 +198,7 @@ namespace Game.Collision
{
var data = new AreaAndLiquidData();
if (Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapLiquidStatus))
if (Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapLiquidStatus))
{
data.floorZ = z;
int adtId, rootId, groupId;
@@ -221,7 +221,7 @@ namespace Game.Collision
if (info.hitInstance.GetLiquidLevel(pos, info, ref liquidLevel))
data.liquidInfo = new(liquidType, liquidLevel);
if (!Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapLiquidStatus))
if (!Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapLiquidStatus))
data.areaInfo = new(info.hitInstance.adtId, info.rootId, (int)info.hitModel.GetWmoID(), info.hitModel.GetMogpFlags());
}
}
+4 -4
View File
@@ -270,7 +270,7 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Checked {0} quest disables in {1} ms", m_DisableMap[DisableType.Quest].Count, Time.GetMSTimeDiffToNow(oldMSTime));
}
public bool IsDisabledFor(DisableType type, uint entry, WorldObject refe, ushort flags = 0)
public bool IsDisabledFor(DisableType type, uint entry, WorldObject refe, DisableFlags flags = 0)
{
Cypher.Assert(type < DisableType.Max);
if (!m_DisableMap.ContainsKey(type) || m_DisableMap[type].Empty())
@@ -331,7 +331,7 @@ namespace Game
}
else if (spellFlags.HasFlag(DisableFlags.SpellDeprecatedSpell)) // call not from spellcast
return true;
else if (flags.HasAnyFlag((byte)DisableFlags.SpellLOS))
else if (flags.HasAnyFlag(DisableFlags.SpellLOS))
return spellFlags.HasFlag(DisableFlags.SpellLOS);
break;
@@ -373,13 +373,13 @@ namespace Game
case DisableType.MMAP:
return true;
case DisableType.VMAP:
return flags.HasAnyFlag(data.flags);
return flags.HasAnyFlag((DisableFlags)data.flags);
}
return false;
}
public bool IsVMAPDisabledFor(uint entry, byte flags)
public bool IsVMAPDisabledFor(uint entry, DisableFlags flags)
{
return IsDisabledFor(DisableType.VMAP, entry, null, flags);
}
@@ -3289,6 +3289,8 @@ namespace Game.Entities
public bool CanMelee() { return !_staticFlags.HasFlag(CreatureStaticFlags.NoMelee); }
public void SetCanMelee(bool canMelee) { _staticFlags.ApplyFlag(CreatureStaticFlags.NoMelee, !canMelee); }
public bool CanIgnoreLineOfSightWhenCastingOnMe() { return _staticFlags.HasFlag(CreatureStaticFlags4.IgnoreLosWhenCastingOnMe); }
public sbyte GetOriginalEquipmentId() { return m_originalEquipmentId; }
public byte GetCurrentEquipmentId() { return m_equipmentId; }
+41 -18
View File
@@ -1771,7 +1771,7 @@ namespace Game.Spells
if (unitTarget != null)
{
uint deficit = (uint)(unitTarget.GetMaxHealth() - unitTarget.GetHealth());
if ((deficit > maxHPDeficit || found == null) && chainSource.IsWithinDist(unitTarget, jumpRadius) && chainSource.IsWithinLOSInMap(unitTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2))
if ((deficit > maxHPDeficit || found == null) && chainSource.IsWithinDist(unitTarget, jumpRadius) && IsWithinLOS(chainSource, unitTarget, false, ModelIgnoreFlags.M2))
{
found = obj;
maxHPDeficit = deficit;
@@ -1786,10 +1786,10 @@ namespace Game.Spells
{
if (found == null)
{
if (chainSource.IsWithinDist(obj, jumpRadius) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
if (chainSource.IsWithinDist(obj, jumpRadius) && IsWithinLOS(chainSource, obj, false, ModelIgnoreFlags.M2))
found = obj;
}
else if (chainSource.GetDistanceOrder(obj, found) && chainSource.IsWithinLOSInMap(obj, LineOfSightChecks.All, ModelIgnoreFlags.M2))
else if (chainSource.GetDistanceOrder(obj, found) && IsWithinLOS(chainSource, obj, false, ModelIgnoreFlags.M2))
found = obj;
}
}
@@ -2604,11 +2604,11 @@ namespace Game.Spells
Cast(true);
else
{
// commented out !m_spellInfo->StartRecoveryTime, it forces instant spells with global cooldown to be processed in spell::update
// commented out !m_spellInfo.StartRecoveryTime, it forces instant spells with global cooldown to be processed in spell::update
// as a result a spell that passed CheckCast and should be processed instantly may suffer from this delayed process
// the easiest bug to observe is LoS check in AddUnitTarget, even if spell passed the CheckCast LoS check the situation can change in spell::update
// because target could be relocated in the meantime, making the spell fly to the air (no targets can be registered, so no effects processed, nothing in combat log)
bool willCastDirectly = m_casttime == 0 && /*!m_spellInfo->StartRecoveryTime && */ GetCurrentContainer() == CurrentSpellTypes.Generic;
bool willCastDirectly = m_casttime == 0 && /*!m_spellInfo.StartRecoveryTime && */ GetCurrentContainer() == CurrentSpellTypes.Generic;
Unit unitCaster = m_caster.ToUnit();
if (unitCaster != null)
@@ -4919,7 +4919,7 @@ namespace Game.Spells
losTarget = dynObj;
}
if (!m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS) && !unitTarget.IsWithinLOSInMap(losTarget, LineOfSightChecks.All, ModelIgnoreFlags.M2))
if (!IsWithinLOS(losTarget, unitTarget, true, ModelIgnoreFlags.M2))
return SpellCastResult.LineOfSight;
}
}
@@ -4927,13 +4927,8 @@ namespace Game.Spells
// Check for line of sight for spells with dest
if (m_targets.HasDst())
{
float x, y, z;
m_targets.GetDstPos().GetPosition(out x, out y, out z);
if (!m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) && !Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS) && !m_caster.IsWithinLOS(x, y, z, LineOfSightChecks.All, ModelIgnoreFlags.M2))
if (!IsWithinLOS(m_caster, m_targets.GetDstPos(), ModelIgnoreFlags.M2))
return SpellCastResult.LineOfSight;
}
// check pet presence
if (unitCaster != null)
@@ -5218,7 +5213,7 @@ namespace Game.Spells
return SpellCastResult.DontReport;
// first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
if (!target.IsWithinLOSInMap(unitCaster)) //Do full LoS/Path check. Don't exclude m2
if (!IsWithinLOS(unitCaster, target, true, ModelIgnoreFlags.Nothing)) //Do full LoS/Path check. Don't exclude m2
return SpellCastResult.LineOfSight;
float objSize = target.GetCombatReach();
@@ -7097,7 +7092,7 @@ namespace Game.Spells
}
// check for ignore LOS on the effect itself
if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, (byte)DisableFlags.SpellLOS))
if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, DisableFlags.SpellLOS))
return true;
// check if gameobject ignores LOS
@@ -7107,7 +7102,7 @@ namespace Game.Spells
return true;
// if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
if (!m_spellInfo.HasAttribute(SpellAttr5.AlwaysLineOfSight) && IsTriggered() && m_triggeredByAuraSpell != null && (m_triggeredByAuraSpell.HasAttribute(SpellAttr2.IgnoreLineOfSight) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_triggeredByAuraSpell.Id, null, (byte)DisableFlags.SpellLOS)))
if (!m_spellInfo.HasAttribute(SpellAttr5.AlwaysLineOfSight) && IsTriggered() && m_triggeredByAuraSpell != null && (m_triggeredByAuraSpell.HasAttribute(SpellAttr2.IgnoreLineOfSight) || Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_triggeredByAuraSpell.Id, null, DisableFlags.SpellLOS)))
return true;
// @todo shit below shouldn't be here, but it's temporary
@@ -7118,7 +7113,7 @@ namespace Game.Spells
{
if (m_targets.GetCorpseTargetGUID().IsEmpty())
{
if (target.IsWithinLOSInMap(m_caster, LineOfSightChecks.All, ModelIgnoreFlags.M2) && target.HasUnitFlag(UnitFlags.Skinnable))
if (IsWithinLOS(m_caster, target, true, ModelIgnoreFlags.M2) && target.HasUnitFlag(UnitFlags.Skinnable))
return true;
return false;
@@ -7134,7 +7129,7 @@ namespace Game.Spells
if (!corpse.HasCorpseDynamicFlag(CorpseDynFlags.Lootable))
return false;
if (!corpse.IsWithinLOSInMap(m_caster, LineOfSightChecks.All, ModelIgnoreFlags.M2))
if (!IsWithinLOS(m_caster, corpse, true, ModelIgnoreFlags.M2))
return false;
break;
@@ -7149,7 +7144,8 @@ namespace Game.Spells
caster = m_caster.GetMap().GetGameObject(m_originalCasterGUID);
if (!caster)
caster = m_caster;
if (target != m_caster && !target.IsWithinLOSInMap(caster, LineOfSightChecks.All, ModelIgnoreFlags.M2))
if (target != m_caster && !IsWithinLOS(caster, target, true, ModelIgnoreFlags.M2))
return false;
}
@@ -7716,6 +7712,33 @@ namespace Game.Spells
}
}
bool IsWithinLOS(WorldObject source, WorldObject target, bool targetAsSourceLocation, ModelIgnoreFlags ignoreFlags)
{
if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight))
return true;
if (Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, DisableFlags.SpellLOS))
return true;
if (target.IsCreature() && target.ToCreature().CanIgnoreLineOfSightWhenCastingOnMe())
return true;
WorldObject src = targetAsSourceLocation ? target : source;
WorldObject dst = targetAsSourceLocation ? source : target;
return src.IsWithinLOSInMap(dst, LineOfSightChecks.All, ignoreFlags);
}
bool IsWithinLOS(WorldObject source, Position target, ModelIgnoreFlags ignoreFlags)
{
if (m_spellInfo.HasAttribute(SpellAttr2.IgnoreLineOfSight))
return true;
if (Global.DisableMgr.IsDisabledFor(DisableType.Spell, m_spellInfo.Id, null, DisableFlags.SpellLOS))
return true;
return source.IsWithinLOS(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), LineOfSightChecks.All, ignoreFlags);
}
bool CheckScriptEffectImplicitTargets(uint effIndex, uint effIndexToCheck)
{
// Skip if there are not any script