using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.Examine; using Content.Shared.Interaction.Helpers; using Content.Shared.Tag; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; namespace Content.Shared.Verbs { public class SharedVerbSystem : EntitySystem { [Dependency] private readonly IEntityLookup _lookup = default!; /// /// Get all of the entities in an area for displaying on the context menu. /// /// Whether we should slightly extend the entity search area. public bool TryGetContextEntities(IEntity player, MapCoordinates targetPos, [NotNullWhen(true)] out List? contextEntities, bool buffer = false, bool ignoreVisibility = false) { contextEntities = null; // Check if we have LOS to the clicked-location. if (!ignoreVisibility && !player.InRangeUnOccluded(targetPos, range: ExamineSystemShared.ExamineRange)) return false; // Get entities var length = buffer ? 1.0f : 0.5f; var entities = _lookup.GetEntitiesIntersecting( targetPos.MapId, Box2.CenteredAround(targetPos.Position, (length, length))) .ToList(); if (entities.Count == 0) return false; if (ignoreVisibility) { contextEntities = entities; return true; } // perform visibility checks var playerPos = player.Transform.MapPosition; foreach (var entity in entities.ToList()) { if (entity.HasTag("HideContextMenu")) { entities.Remove(entity); continue; } if (!ExamineSystemShared.InRangeUnOccluded( playerPos, entity.Transform.MapPosition, ExamineSystemShared.ExamineRange, null) ) { entities.Remove(entity); } } if (entities.Count == 0) return false; contextEntities = entities; return true; } /// /// Raises a number of events in order to get all verbs of the given type(s) /// public Dictionary> GetVerbs(IEntity target, IEntity user, VerbType verbTypes) { Dictionary> verbs = new(); if ((verbTypes & VerbType.Interaction) == VerbType.Interaction) { GetInteractionVerbsEvent getVerbEvent = new(user, target); RaiseLocalEvent(target.Uid, getVerbEvent); verbs.Add(VerbType.Interaction, getVerbEvent.Verbs); } if ((verbTypes & VerbType.Activation) == VerbType.Activation) { GetActivationVerbsEvent getVerbEvent = new(user, target); RaiseLocalEvent(target.Uid, getVerbEvent); verbs.Add(VerbType.Activation, getVerbEvent.Verbs); } if ((verbTypes & VerbType.Alternative) == VerbType.Alternative) { GetAlternativeVerbsEvent getVerbEvent = new(user, target); RaiseLocalEvent(target.Uid, getVerbEvent); verbs.Add(VerbType.Alternative, getVerbEvent.Verbs); } if ((verbTypes & VerbType.Other) == VerbType.Other) { GetOtherVerbsEvent getVerbEvent = new(user, target); RaiseLocalEvent(target.Uid, getVerbEvent); verbs.Add(VerbType.Other, getVerbEvent.Verbs); } return verbs; } /// /// Execute actions associated with the given verb. /// /// /// This will try to call delegates and raise any events for the given verb. /// public bool TryExecuteVerb(Verb verb) { var executed = false; // Maybe run a delegate if (verb.Act != null) { executed = true; verb.Act.Invoke(); } // Maybe raise a local event if (verb.LocalVerbEventArgs != null) { executed = true; if (verb.LocalEventTarget.IsValid()) RaiseLocalEvent(verb.LocalEventTarget, verb.LocalVerbEventArgs); else RaiseLocalEvent(verb.LocalVerbEventArgs); } // maybe raise a network event if (verb.NetworkVerbEventArgs != null) { executed = true; RaiseNetworkEvent(verb.NetworkVerbEventArgs); } // return false if all of these were null return executed; } } }