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) 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; return true;
var instanceTree = iInstanceMapTrees.LookupByKey(mapId); 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) 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); var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null) if (instanceTree != null)
@@ -130,7 +130,7 @@ namespace Game.Collision
public float GetHeight(uint mapId, float x, float y, float z, float maxSearchDist) 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); var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null) if (instanceTree != null)
@@ -153,7 +153,7 @@ namespace Game.Collision
adtId = 0; adtId = 0;
rootId = 0; rootId = 0;
groupId = 0; groupId = 0;
if (!Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapAreaFlag)) if (!Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapAreaFlag))
{ {
var instanceTree = iInstanceMapTrees.LookupByKey(mapId); var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null) 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) 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); var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null) if (instanceTree != null)
@@ -198,7 +198,7 @@ namespace Game.Collision
{ {
var data = new AreaAndLiquidData(); var data = new AreaAndLiquidData();
if (Global.DisableMgr.IsVMAPDisabledFor(mapId, (byte)DisableFlags.VmapLiquidStatus)) if (Global.DisableMgr.IsVMAPDisabledFor(mapId, DisableFlags.VmapLiquidStatus))
{ {
data.floorZ = z; data.floorZ = z;
int adtId, rootId, groupId; int adtId, rootId, groupId;
@@ -221,7 +221,7 @@ namespace Game.Collision
if (info.hitInstance.GetLiquidLevel(pos, info, ref liquidLevel)) if (info.hitInstance.GetLiquidLevel(pos, info, ref liquidLevel))
data.liquidInfo = new(liquidType, 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()); 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)); 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); Cypher.Assert(type < DisableType.Max);
if (!m_DisableMap.ContainsKey(type) || m_DisableMap[type].Empty()) 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 else if (spellFlags.HasFlag(DisableFlags.SpellDeprecatedSpell)) // call not from spellcast
return true; return true;
else if (flags.HasAnyFlag((byte)DisableFlags.SpellLOS)) else if (flags.HasAnyFlag(DisableFlags.SpellLOS))
return spellFlags.HasFlag(DisableFlags.SpellLOS); return spellFlags.HasFlag(DisableFlags.SpellLOS);
break; break;
@@ -373,13 +373,13 @@ namespace Game
case DisableType.MMAP: case DisableType.MMAP:
return true; return true;
case DisableType.VMAP: case DisableType.VMAP:
return flags.HasAnyFlag(data.flags); return flags.HasAnyFlag((DisableFlags)data.flags);
} }
return false; return false;
} }
public bool IsVMAPDisabledFor(uint entry, byte flags) public bool IsVMAPDisabledFor(uint entry, DisableFlags flags)
{ {
return IsDisabledFor(DisableType.VMAP, entry, null, flags); return IsDisabledFor(DisableType.VMAP, entry, null, flags);
} }
@@ -3289,6 +3289,8 @@ namespace Game.Entities
public bool CanMelee() { return !_staticFlags.HasFlag(CreatureStaticFlags.NoMelee); } public bool CanMelee() { return !_staticFlags.HasFlag(CreatureStaticFlags.NoMelee); }
public void SetCanMelee(bool canMelee) { _staticFlags.ApplyFlag(CreatureStaticFlags.NoMelee, !canMelee); } 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 sbyte GetOriginalEquipmentId() { return m_originalEquipmentId; }
public byte GetCurrentEquipmentId() { return m_equipmentId; } public byte GetCurrentEquipmentId() { return m_equipmentId; }
+41 -18
View File
@@ -1771,7 +1771,7 @@ namespace Game.Spells
if (unitTarget != null) if (unitTarget != null)
{ {
uint deficit = (uint)(unitTarget.GetMaxHealth() - unitTarget.GetHealth()); 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; found = obj;
maxHPDeficit = deficit; maxHPDeficit = deficit;
@@ -1786,10 +1786,10 @@ namespace Game.Spells
{ {
if (found == null) 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; 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; found = obj;
} }
} }
@@ -2604,11 +2604,11 @@ namespace Game.Spells
Cast(true); Cast(true);
else 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 // 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 // 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) // 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(); Unit unitCaster = m_caster.ToUnit();
if (unitCaster != null) if (unitCaster != null)
@@ -4919,7 +4919,7 @@ namespace Game.Spells
losTarget = dynObj; 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; return SpellCastResult.LineOfSight;
} }
} }
@@ -4927,13 +4927,8 @@ namespace Game.Spells
// Check for line of sight for spells with dest // Check for line of sight for spells with dest
if (m_targets.HasDst()) if (m_targets.HasDst())
{ if (!IsWithinLOS(m_caster, m_targets.GetDstPos(), ModelIgnoreFlags.M2))
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))
return SpellCastResult.LineOfSight; return SpellCastResult.LineOfSight;
}
// check pet presence // check pet presence
if (unitCaster != null) if (unitCaster != null)
@@ -5218,7 +5213,7 @@ namespace Game.Spells
return SpellCastResult.DontReport; 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 // 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; return SpellCastResult.LineOfSight;
float objSize = target.GetCombatReach(); float objSize = target.GetCombatReach();
@@ -7097,7 +7092,7 @@ namespace Game.Spells
} }
// check for ignore LOS on the effect itself // 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; return true;
// check if gameobject ignores LOS // check if gameobject ignores LOS
@@ -7107,7 +7102,7 @@ namespace Game.Spells
return true; return true;
// if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour // 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; return true;
// @todo shit below shouldn't be here, but it's temporary // @todo shit below shouldn't be here, but it's temporary
@@ -7118,7 +7113,7 @@ namespace Game.Spells
{ {
if (m_targets.GetCorpseTargetGUID().IsEmpty()) 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 true;
return false; return false;
@@ -7134,7 +7129,7 @@ namespace Game.Spells
if (!corpse.HasCorpseDynamicFlag(CorpseDynFlags.Lootable)) if (!corpse.HasCorpseDynamicFlag(CorpseDynFlags.Lootable))
return false; return false;
if (!corpse.IsWithinLOSInMap(m_caster, LineOfSightChecks.All, ModelIgnoreFlags.M2)) if (!IsWithinLOS(m_caster, corpse, true, ModelIgnoreFlags.M2))
return false; return false;
break; break;
@@ -7149,7 +7144,8 @@ namespace Game.Spells
caster = m_caster.GetMap().GetGameObject(m_originalCasterGUID); caster = m_caster.GetMap().GetGameObject(m_originalCasterGUID);
if (!caster) if (!caster)
caster = m_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; 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) bool CheckScriptEffectImplicitTargets(uint effIndex, uint effIndexToCheck)
{ {
// Skip if there are not any script // Skip if there are not any script