diff --git a/Content.Client/GameObjects/EntitySystems/VerbSystem.cs b/Content.Client/GameObjects/EntitySystems/VerbSystem.cs index 9d73013321..f388263d65 100644 --- a/Content.Client/GameObjects/EntitySystems/VerbSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/VerbSystem.cs @@ -210,6 +210,9 @@ namespace Content.Client.GameObjects.EntitySystems if (verb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity)) continue; + if (verb.BlockedByContainers && !user.IsInSameOrNoContainer(entity)) + continue; + var verbData = verb.GetData(user, component); if (verbData.IsInvisible) @@ -232,6 +235,9 @@ namespace Content.Client.GameObjects.EntitySystems if (globalVerb.RequireInteractionRange && !VerbUtility.InVerbUseRange(user, entity)) continue; + if (globalVerb.BlockedByContainers && !user.IsInSameOrNoContainer(entity)) + continue; + var verbData = globalVerb.GetData(user, entity); if (verbData.IsInvisible) diff --git a/Content.Client/GlobalVerbs/ExamineVerb.cs b/Content.Client/GlobalVerbs/ExamineVerb.cs index 13e6198490..2116290796 100644 --- a/Content.Client/GlobalVerbs/ExamineVerb.cs +++ b/Content.Client/GlobalVerbs/ExamineVerb.cs @@ -11,6 +11,8 @@ namespace Content.Client.GlobalVerbs { public override bool RequireInteractionRange => false; + public override bool BlockedByContainers => false; + public override void GetData(IEntity user, IEntity target, VerbData data) { data.Visibility = VerbVisibility.Visible; diff --git a/Content.Server/GameObjects/EntitySystems/Click/ExamineSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/ExamineSystem.cs index 53fa77c516..1b83b0b3fe 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/ExamineSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/ExamineSystem.cs @@ -4,6 +4,7 @@ using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Localization; using Robust.Shared.Utility; namespace Content.Server.GameObjects.EntitySystems.Click @@ -19,7 +20,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click static ExamineSystem() { _entityNotFoundMessage = new FormattedMessage(); - _entityNotFoundMessage.AddText("That entity doesn't exist"); + _entityNotFoundMessage.AddText(Loc.GetString("That entity doesn't exist")); } public override void Initialize() diff --git a/Content.Server/GameObjects/EntitySystems/VerbSystem.cs b/Content.Server/GameObjects/EntitySystems/VerbSystem.cs index b0720ccfb3..6de086226a 100644 --- a/Content.Server/GameObjects/EntitySystems/VerbSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/VerbSystem.cs @@ -2,6 +2,7 @@ using System.Reflection; using Content.Shared.GameObjects.Verbs; using Robust.Server.Interfaces.Player; +using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; @@ -37,6 +38,12 @@ namespace Content.Server.GameObjects.EntitySystems var session = eventArgs.SenderSession; var userEntity = session.AttachedEntity; + if (userEntity == null) + { + Logger.Warning($"{nameof(UseVerb)} called by player {session} with no attached entity."); + return; + } + foreach (var (component, verb) in VerbUtility.GetVerbs(entity)) { if ($"{component.GetType()}:{verb.GetType()}" != use.VerbKey) @@ -44,14 +51,14 @@ namespace Content.Server.GameObjects.EntitySystems continue; } - if (verb.RequireInteractionRange) + if (verb.RequireInteractionRange && !VerbUtility.InVerbUseRange(userEntity, entity)) { - var distanceSquared = (userEntity.Transform.WorldPosition - entity.Transform.WorldPosition) - .LengthSquared; - if (distanceSquared > VerbUtility.InteractionRangeSquared) - { - break; - } + break; + } + + if (verb.BlockedByContainers && !userEntity.IsInSameOrNoContainer(entity)) + { + break; } verb.Activate(userEntity, component); @@ -65,14 +72,15 @@ namespace Content.Server.GameObjects.EntitySystems continue; } - if (globalVerb.RequireInteractionRange) + if (globalVerb.RequireInteractionRange && + !VerbUtility.InVerbUseRange(userEntity, entity)) { - var distanceSquared = (userEntity.Transform.WorldPosition - entity.Transform.WorldPosition) - .LengthSquared; - if (distanceSquared > VerbUtility.InteractionRangeSquared) - { - break; - } + break; + } + + if (globalVerb.BlockedByContainers && !userEntity.IsInSameOrNoContainer(entity)) + { + break; } globalVerb.Activate(userEntity, entity); @@ -92,6 +100,12 @@ namespace Content.Server.GameObjects.EntitySystems var userEntity = player.AttachedEntity; + if (userEntity == null) + { + Logger.Warning($"{nameof(UseVerb)} called by player {player} with no attached entity."); + return; + } + var data = new List(); //Get verbs, component dependent. foreach (var (component, verb) in VerbUtility.GetVerbs(entity)) @@ -99,6 +113,9 @@ namespace Content.Server.GameObjects.EntitySystems if (verb.RequireInteractionRange && !VerbUtility.InVerbUseRange(userEntity, entity)) continue; + if (verb.BlockedByContainers && !userEntity.IsInSameOrNoContainer(entity)) + continue; + var verbData = verb.GetData(userEntity, component); if (verbData.IsInvisible) continue; @@ -113,6 +130,9 @@ namespace Content.Server.GameObjects.EntitySystems if (globalVerb.RequireInteractionRange && !VerbUtility.InVerbUseRange(userEntity, entity)) continue; + if (globalVerb.BlockedByContainers && !userEntity.IsInSameOrNoContainer(entity)) + continue; + var verbData = globalVerb.GetData(userEntity, entity); if (verbData.IsInvisible) continue; diff --git a/Content.Shared/GameObjects/EntitySystems/ExamineSystemShared.cs b/Content.Shared/GameObjects/EntitySystems/ExamineSystemShared.cs index 0e09c98af2..71e0190d8d 100644 --- a/Content.Shared/GameObjects/EntitySystems/ExamineSystemShared.cs +++ b/Content.Shared/GameObjects/EntitySystems/ExamineSystemShared.cs @@ -1,5 +1,7 @@ -using Content.Shared.GameObjects.Components.Mobs; +using System; +using Content.Shared.GameObjects.Components.Mobs; using JetBrains.Annotations; +using Robust.Shared.Containers; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Maths; @@ -22,6 +24,15 @@ namespace Content.Shared.GameObjects.EntitySystems public const float ExamineRangeSquared = ExamineRange * ExamineRange; protected const float ExamineDetailsRange = 3f; + private static bool IsInDetailsRange(IEntity examiner, IEntity entity) + { + return Get() + .InRangeUnobstructed(examiner.Transform.MapPosition, entity.Transform.MapPosition, + ExamineDetailsRange, predicate: entity0 => entity0 == examiner || entity0 == entity, + ignoreInsideBlocker: true) && + examiner.IsInSameOrNoContainer(entity); + } + [Pure] protected static bool CanExamine(IEntity examiner, IEntity examined) { @@ -40,9 +51,16 @@ namespace Content.Shared.GameObjects.EntitySystems return false; } + Func predicate = entity => entity == examiner || entity == examined; + + if (ContainerHelpers.TryGetContainer(examiner, out var container)) + { + predicate += entity => entity == container.Owner; + } + return Get() .InRangeUnobstructed(examiner.Transform.MapPosition, examined.Transform.MapPosition, - ExamineRange, predicate: entity => entity == examiner || entity == examined, ignoreInsideBlocker:true); + ExamineRange, predicate: predicate, ignoreInsideBlocker:true); } public static FormattedMessage GetExamineText(IEntity entity, IEntity examiner) @@ -60,15 +78,11 @@ namespace Content.Shared.GameObjects.EntitySystems message.PushColor(Color.DarkGray); - var inDetailsRange = Get() - .InRangeUnobstructed(examiner.Transform.MapPosition, entity.Transform.MapPosition, - ExamineDetailsRange, predicate: entity0 => entity0 == examiner || entity0 == entity, ignoreInsideBlocker: true); - //Add component statuses from components that report one foreach (var examineComponent in entity.GetAllComponents()) { var subMessage = new FormattedMessage(); - examineComponent.Examine(subMessage, inDetailsRange); + examineComponent.Examine(subMessage, IsInDetailsRange(examiner, entity)); if (subMessage.Tags.Count == 0) continue; diff --git a/Content.Shared/GameObjects/Verbs/GlobalVerb.cs b/Content.Shared/GameObjects/Verbs/GlobalVerb.cs index ad5ebed628..e14830fab3 100644 --- a/Content.Shared/GameObjects/Verbs/GlobalVerb.cs +++ b/Content.Shared/GameObjects/Verbs/GlobalVerb.cs @@ -20,6 +20,12 @@ namespace Content.Shared.GameObjects.Verbs /// public virtual bool RequireInteractionRange => true; + /// + /// If true, this verb requires both the user and the entity on which + /// this verb resides to be in the same container or no container. + /// + public virtual bool BlockedByContainers => true; + /// /// Gets the visible verb data for the user. /// diff --git a/Content.Shared/GameObjects/Verbs/Verb.cs b/Content.Shared/GameObjects/Verbs/Verb.cs index b4b1f27751..99cf50b24d 100644 --- a/Content.Shared/GameObjects/Verbs/Verb.cs +++ b/Content.Shared/GameObjects/Verbs/Verb.cs @@ -20,6 +20,12 @@ namespace Content.Shared.GameObjects.Verbs /// public virtual bool RequireInteractionRange => true; + /// + /// If true, this verb requires both the user and the entity on which + /// this verb resides to be in the same container or no container. + /// + public virtual bool BlockedByContainers => true; + /// /// Gets the visible verb data for the user. ///