using Content.Shared.NPC.Components; using System.Linq; namespace Content.Shared.NPC.Systems; /// /// Prevents an NPC from attacking some entities from an enemy faction. /// Also makes it attack some entities even if they are in neutral factions (retaliation). /// public sealed partial class NpcFactionSystem { private EntityQuery _exceptionQuery; private EntityQuery _trackerQuery; public void InitializeException() { _exceptionQuery = GetEntityQuery(); _trackerQuery = GetEntityQuery(); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnTrackerShutdown); } private void OnShutdown(Entity ent, ref ComponentShutdown args) { foreach (var uid in ent.Comp.Hostiles) { if (_trackerQuery.TryGetComponent(uid, out var tracker)) tracker.Entities.Remove(ent); } foreach (var uid in ent.Comp.Ignored) { if (_trackerQuery.TryGetComponent(uid, out var tracker)) tracker.Entities.Remove(ent); } } private void OnTrackerShutdown(Entity ent, ref ComponentShutdown args) { foreach (var uid in ent.Comp.Entities) { if (!_exceptionQuery.TryGetComponent(uid, out var exception)) continue; exception.Ignored.Remove(ent); exception.Hostiles.Remove(ent); } } /// /// Returns whether the entity from an enemy faction won't be attacked /// public bool IsIgnored(Entity ent, EntityUid target) { if (!Resolve(ent, ref ent.Comp, false)) return false; return ent.Comp.Ignored.Contains(target); } /// /// Returns the specific hostile entities for a given entity. /// public IEnumerable GetHostiles(Entity ent) { if (!Resolve(ent, ref ent.Comp, false)) return Array.Empty(); // evil c# return ent.Comp!.Hostiles; } /// /// Prevents an entity from an enemy faction from being attacked /// public void IgnoreEntity(Entity ent, Entity target) { ent.Comp ??= EnsureComp(ent); ent.Comp.Ignored.Add(target); target.Comp ??= EnsureComp(target); target.Comp.Entities.Add(ent); } /// /// Prevents a list of entities from an enemy faction from being attacked /// public void IgnoreEntities(Entity ent, IEnumerable ignored) { ent.Comp ??= EnsureComp(ent); foreach (var ignore in ignored) { IgnoreEntity(ent, ignore); } } /// /// Makes an entity always be considered hostile. /// public void AggroEntity(Entity ent, Entity target) { ent.Comp ??= EnsureComp(ent); ent.Comp.Hostiles.Add(target); target.Comp ??= EnsureComp(target); target.Comp.Entities.Add(ent); } /// /// Makes an entity no longer be considered hostile, if it was. /// Doesn't apply to regular faction hostilities. /// public void DeAggroEntity(Entity ent, EntityUid target) { if (!Resolve(ent, ref ent.Comp, false)) return; if (!ent.Comp.Hostiles.Remove(target) || !_trackerQuery.TryGetComponent(target, out var tracker)) return; tracker.Entities.Remove(ent); } /// /// Makes a list of entities no longer be considered hostile, if it was. /// Doesn't apply to regular faction hostilities. /// public void AggroEntities(Entity ent, IEnumerable entities) { ent.Comp ??= EnsureComp(ent); foreach (var uid in entities) { AggroEntity(ent, uid); } } }