diff --git a/Source/Framework/Constants/ConditionConst.cs b/Source/Framework/Constants/ConditionConst.cs index e02af6b49..0ead1d562 100644 --- a/Source/Framework/Constants/ConditionConst.cs +++ b/Source/Framework/Constants/ConditionConst.cs @@ -109,6 +109,7 @@ namespace Framework.Constants ConversationLine = 29, AreatriggerClientTriggered = 30, TrainerSpell = 31, + ObjectIdVisibility = 32, Max } diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index 7259c7610..ac7eb1475 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -141,7 +141,7 @@ namespace Game public bool CanHaveSourceGroupSet(ConditionSourceType sourceType) { - return (sourceType == ConditionSourceType.CreatureLootTemplate || + return sourceType == ConditionSourceType.CreatureLootTemplate || sourceType == ConditionSourceType.DisenchantLootTemplate || sourceType == ConditionSourceType.FishingLootTemplate || sourceType == ConditionSourceType.GameobjectLootTemplate || @@ -162,7 +162,8 @@ namespace Game sourceType == ConditionSourceType.NpcVendor || sourceType == ConditionSourceType.Phase || sourceType == ConditionSourceType.AreaTrigger || - sourceType == ConditionSourceType.TrainerSpell); + sourceType == ConditionSourceType.TrainerSpell || + sourceType == ConditionSourceType.ObjectIdVisibility; } public bool CanHaveSourceIdSet(ConditionSourceType sourceType) @@ -303,6 +304,17 @@ namespace Game } return true; } + + public bool IsObjectMeetingVisibilityByObjectIdConditions(uint objectType, uint entry, WorldObject seer) + { + var conditions = objectVisibilityConditionStorage.LookupByKey((objectType, entry)); + if (conditions != null) + { + Log.outDebug(LogFilter.Condition, $"IsObjectMeetingVisibilityByObjectIdConditions: found conditions for objectType {objectType} entry {entry}"); + return IsObjectMeetToConditions(seer, conditions); + } + return true; + } public void LoadConditions(bool isReload = false) { @@ -544,6 +556,13 @@ namespace Game ++count; continue; } + case ConditionSourceType.ObjectIdVisibility: + { + objectVisibilityConditionStorage.Add((cond.SourceGroup, (uint)cond.SourceEntry), cond); + valid = true; + ++count; + continue; + } default: break; } @@ -1167,6 +1186,37 @@ namespace Game } break; } + case ConditionSourceType.ObjectIdVisibility: + { + if (cond.SourceGroup <= 0 || cond.SourceGroup >= (uint)TypeId.Max) + { + Log.outError(LogFilter.Sql, $"{cond.ToString()} SourceGroup in `condition` table, is no valid object type, ignoring."); + return false; + } + + if (cond.SourceGroup == (uint)TypeId.Unit) + { + if (Global.ObjectMgr.GetCreatureTemplate((uint)cond.SourceEntry) == null) + { + Log.outError(LogFilter.Sql, $"{cond.ToString()} SourceEntry in `condition` table, does not exist in `creature_template`, ignoring."); + return false; + } + } + else if (cond.SourceGroup == (uint)TypeId.GameObject) + { + if (Global.ObjectMgr.GetGameObjectTemplate((uint)cond.SourceEntry) == null) + { + Log.outError(LogFilter.Sql, $"{cond.ToString()} SourceEntry in `condition` table, does not exist in `gameobject_template`, ignoring."); + return false; + } + } + else + { + Log.outError(LogFilter.Sql, $"{cond.ToString()} SourceGroup in `condition` table, uses unchecked type id, ignoring."); + return false; + } + break; + } default: Log.outError(LogFilter.Sql, $"{cond.ToString()} Invalid ConditionSourceType in `condition` table, ignoring."); return false; @@ -1720,6 +1770,8 @@ namespace Game areaTriggerConditionContainerStorage.Clear(); trainerSpellConditionContainerStorage.Clear(); + + objectVisibilityConditionStorage.Clear(); } static bool PlayerConditionCompare(int comparisonType, int value1, int value2) @@ -2504,6 +2556,7 @@ namespace Game Dictionary, MultiMap> smartEventConditionStorage = new(); MultiMap, Condition> areaTriggerConditionContainerStorage = new(); Dictionary> trainerSpellConditionContainerStorage = new(); + MultiMap<(uint objectType, uint objectId), Condition> objectVisibilityConditionStorage = new(); public string[] StaticSourceTypeData = { @@ -2538,7 +2591,8 @@ namespace Game "AreaTrigger", "ConversationLine", "AreaTrigger Client Triggered", - "Trainer Spell" + "Trainer Spell", + "Object Visibility (by ID)" }; public ConditionTypeInfo[] StaticConditionTypeData = diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 801e23ed3..681a5931d 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1091,6 +1091,9 @@ namespace Game.Entities if (!obj.CheckPrivateObjectOwnerVisibility(this)) return false; + if (!Global.ConditionMgr.IsObjectMeetingVisibilityByObjectIdConditions((uint)obj.GetTypeId(), obj.GetEntry(), this)) + return false; + bool corpseVisibility = false; if (distanceCheck) {