diff --git a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs index 1035ec5949..d3bea49db2 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs @@ -2,11 +2,14 @@ using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Items; +using Content.Shared.Physics; using Robust.Server.GameObjects; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.Interfaces.Physics; using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; using Robust.Shared.Maths; @@ -24,6 +27,9 @@ namespace Content.Server.GameObjects #pragma warning disable 649 [Dependency] private readonly IRobustRandom _robustRandom; + [Dependency] private readonly IPhysicsManager _physicsManager; + [Dependency] private readonly IMapManager _mapManager; + [Dependency] private readonly IEntitySystemManager _entitySystemManager; #pragma warning restore 649 private string _equippedPrefix; @@ -64,8 +70,19 @@ namespace Content.Server.GameObjects serializer.DataField(ref _equippedPrefix, "HeldPrefix", null); } + public bool CanPickup(IEntity user) + { + var coords = Owner.Transform.GridPosition; + + if (!ActionBlockerSystem.CanPickup(user)) return false; + return _entitySystemManager.GetEntitySystem() + .InRangeUnobstructed(coords, user.Transform.GridPosition, ignoredEnt:Owner); + } + public bool AttackHand(AttackHandEventArgs eventArgs) { + if (!CanPickup(eventArgs.User)) return false; + var hands = eventArgs.User.GetComponent(); hands.PutInHand(this, hands.ActiveIndex, fallback: false); return true; @@ -85,7 +102,7 @@ namespace Content.Server.GameObjects protected override VerbVisibility GetVisibility(IEntity user, ItemComponent component) { - if (ContainerHelpers.IsInContainer(component.Owner)) + if (ContainerHelpers.IsInContainer(component.Owner) || !component.CanPickup(user)) { return VerbVisibility.Invisible; } diff --git a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs index 9ecb7d4525..ed17681720 100644 --- a/Content.Server/GameObjects/Components/Mobs/DamageStates.cs +++ b/Content.Server/GameObjects/Components/Mobs/DamageStates.cs @@ -62,7 +62,12 @@ namespace Content.Server.GameObjects { return true; } - + + bool IActionBlocker.CanPickup() + { + return true; + } + bool IActionBlocker.CanEmote() { return true; @@ -113,7 +118,12 @@ namespace Content.Server.GameObjects { return false; } - + + bool IActionBlocker.CanPickup() + { + return false; + } + bool IActionBlocker.CanEmote() { return false; @@ -184,7 +194,12 @@ namespace Content.Server.GameObjects { return false; } - + + bool IActionBlocker.CanPickup() + { + return false; + } + bool IActionBlocker.CanEmote() { return false; diff --git a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs index 6d68d59881..bf9bdfc413 100644 --- a/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/SpeciesComponent.cs @@ -107,6 +107,11 @@ namespace Content.Server.GameObjects return CurrentDamageState.CanDrop(); } + bool IActionBlocker.CanPickup() + { + return CurrentDamageState.CanPickup(); + } + bool IActionBlocker.CanEmote() { return CurrentDamageState.CanEmote(); diff --git a/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs b/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs index fa2c4f200d..d653568e5a 100644 --- a/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ActionBlockerSystem.cs @@ -17,6 +17,8 @@ namespace Content.Server.GameObjects.EntitySystems bool CanDrop(); + bool CanPickup(); + bool CanEmote(); } @@ -81,7 +83,17 @@ namespace Content.Server.GameObjects.EntitySystems } return candrop; } - + + public static bool CanPickup(IEntity entity) + { + bool canpickup = true; + foreach (var actionblockercomponents in entity.GetAllComponents()) + { + canpickup &= actionblockercomponents.CanPickup(); + } + return canpickup; + } + public static bool CanEmote(IEntity entity) { bool canemote = true; diff --git a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs index df7f6ea42a..0b3ead0a58 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs @@ -4,6 +4,7 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Timing; using Content.Server.Interfaces.GameObjects; using Content.Shared.Input; +using Content.Shared.Physics; using JetBrains.Annotations; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.Player; @@ -14,6 +15,7 @@ using Robust.Shared.Input; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.Map; +using Robust.Shared.Interfaces.Physics; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Map; @@ -248,6 +250,7 @@ namespace Content.Server.GameObjects.EntitySystems { #pragma warning disable 649 [Dependency] private readonly IMapManager _mapManager; + [Dependency] private readonly IPhysicsManager _physicsManager; #pragma warning restore 649 public const float InteractionRange = 2; @@ -264,6 +267,34 @@ namespace Content.Server.GameObjects.EntitySystems new PointerInputCmdHandler(HandleActivateItemInWorld)); } + /// + /// Checks that these coordinates are within a certain distance without any + /// entity that matches the collision mask obstructing them. + /// If the is zero or negative, + /// this method will only check if nothing obstructs the two sets of coordinates.. + /// + /// Map manager containing the two GridIds. + /// Set of coordinates to use. + /// Other set of coordinates to use. + /// maximum distance between the two sets of coordinates. + /// the mask to check for collisions + /// the entity to be ignored when checking for collisions. + /// True if the two points are within a given range without being obstructed. + public bool InRangeUnobstructed(GridCoordinates coords, GridCoordinates otherCoords, float range = InteractionRange, int collisionMask = (int)CollisionGroup.Impassable, IEntity ignoredEnt = null) + { + if (range > 0f && !coords.InRange(_mapManager, otherCoords, range)) + { + return false; + } + + var dir = (otherCoords.Position - coords.Position); + if (!(dir.Length > 0f)) return true; + var ray = new CollisionRay(coords.Position, dir.Normalized, collisionMask); + var rayResults = _physicsManager.IntersectRay(_mapManager.GetGrid(coords.GridID).ParentMapId, ray, dir.Length, ignoredEnt); + + return !rayResults.DidHitObject; + } + private bool HandleActivateItemInWorld(ICommonSession session, GridCoordinates coords, EntityUid uid) { if (!EntityManager.TryGetEntity(uid, out var used)) diff --git a/Content.Server/GameObjects/EntitySystems/HandsSystem.cs b/Content.Server/GameObjects/EntitySystems/HandsSystem.cs index 3c21da0487..617047cbed 100644 --- a/Content.Server/GameObjects/EntitySystems/HandsSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/HandsSystem.cs @@ -31,6 +31,7 @@ namespace Content.Server.GameObjects.EntitySystems { #pragma warning disable 649 [Dependency] private readonly IMapManager _mapManager; + [Dependency] private readonly IEntitySystemManager _entitySystemManager; #pragma warning restore 649 private const float ThrowForce = 1.5f; // Throwing force of mobs in Newtons @@ -126,11 +127,9 @@ namespace Content.Server.GameObjects.EntitySystems if (handsComp.GetActiveHand == null) return false; - var dir = (coords.Position - ent.Transform.GridPosition.Position); - var ray = new CollisionRay(ent.Transform.GridPosition.Position, dir.Normalized, (int) CollisionGroup.Impassable); - var rayResults = IoCManager.Resolve().IntersectRay(ent.Transform.MapID, ray, dir.Length, ent); + var interactionSystem = _entitySystemManager.GetEntitySystem(); - if(!rayResults.DidHitObject) + if(interactionSystem.InRangeUnobstructed(coords, ent.Transform.GridPosition, 0f, ignoredEnt:ent)) if (coords.InRange(_mapManager, ent.Transform.GridPosition, InteractionSystem.InteractionRange)) { handsComp.Drop(handsComp.ActiveIndex, coords);