diff --git a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs index d53a100acc..3985bd3051 100644 --- a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Content.Shared.Administration.Logs; using Content.Shared.Examine; using Content.Shared.Construction.Components; diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 6b121baf58..61ea2de26c 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Administration.Logs; using Content.Shared.Camera; using Content.Shared.CCVar; using Content.Shared.Construction.Components; +using Content.Shared.Construction.EntitySystems; using Content.Shared.Database; using Content.Shared.Friction; using Content.Shared.Projectiles; @@ -11,6 +12,7 @@ using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; +using Robust.Shared.Serialization; using Robust.Shared.Timing; namespace Content.Shared.Throwing; @@ -35,11 +37,16 @@ public sealed class ThrowingSystem : EntitySystem [Dependency] private readonly SharedCameraRecoilSystem _recoil = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; + [Dependency] private readonly AnchorableSystem _anchorable = default!; + + private EntityQuery _anchorableQuery; public override void Initialize() { base.Initialize(); + _anchorableQuery = GetEntityQuery(); + Subs.CVar(_configManager, CCVars.TileFrictionModifier, value => _frictionModifier = value, true); Subs.CVar(_configManager, CCVars.AirFriction, value => _airDamping = value, true); } @@ -56,7 +63,7 @@ public sealed class ThrowingSystem : EntitySystem bool animated = true, bool playSound = true, bool doSpin = true, - bool unanchor = false) + ThrowingUnanchorStrength unanchor = ThrowingUnanchorStrength.None) { var thrownPos = _transform.GetMapCoordinates(uid); var mapPos = _transform.ToMapCoordinates(coordinates); @@ -77,7 +84,7 @@ public sealed class ThrowingSystem : EntitySystem /// friction value used for the distance calculation. If set to null this defaults to the standard tile values /// True will adjust the throw so the item stops at the target coordinates. False means it will land at the target and keep sliding. /// Whether spin will be applied to the thrown entity. - /// If true and the thrown entity has , unanchor the thrown entity + /// If set to Unanchorable, if the entity has and is unanchorable, it will unanchor the thrown entity. If set to All, it will unanchor the entity regardless. public void TryThrow(EntityUid uid, Vector2 direction, float baseThrowSpeed = 10.0f, @@ -89,7 +96,7 @@ public sealed class ThrowingSystem : EntitySystem bool animated = true, bool playSound = true, bool doSpin = true, - bool unanchor = false) + ThrowingUnanchorStrength unanchor = ThrowingUnanchorStrength.None) { var physicsQuery = GetEntityQuery(); if (!physicsQuery.TryGetComponent(uid, out var physics)) @@ -119,7 +126,7 @@ public sealed class ThrowingSystem : EntitySystem /// friction value used for the distance calculation. If set to null this defaults to the standard tile values /// True will adjust the throw so the item stops at the target coordinates. False means it will land at the target and keep sliding. /// Whether spin will be applied to the thrown entity. - /// If true and the thrown entity has , unanchor the thrown entity + /// If set to Unanchorable, if the entity has and is unanchorable, it will unanchor the thrown entity. If set to All, it will unanchor the entity regardless. public void TryThrow(EntityUid uid, Vector2 direction, PhysicsComponent physics, @@ -134,12 +141,16 @@ public sealed class ThrowingSystem : EntitySystem bool animated = true, bool playSound = true, bool doSpin = true, - bool unanchor = false) + ThrowingUnanchorStrength unanchor = ThrowingUnanchorStrength.None) { if (baseThrowSpeed <= 0 || direction == Vector2Helpers.Infinity || direction == Vector2Helpers.NaN || direction == Vector2.Zero || friction < 0) return; - if (unanchor && HasComp(uid)) + // Unanchor the entity if applicable + if (unanchor == ThrowingUnanchorStrength.All || + unanchor == ThrowingUnanchorStrength.Unanchorable && + _anchorableQuery.TryComp(uid, out var anchorableComponent) && + (anchorableComponent.Flags & AnchorableFlags.Unanchorable) != 0) _transform.Unanchor(uid); if ((physics.BodyType & (BodyType.Dynamic | BodyType.KinematicController)) == 0x0) @@ -243,4 +254,26 @@ public sealed class ThrowingSystem : EntitySystem if (pushEv.Push) _physics.ApplyLinearImpulse(user.Value, -impulseVector / physics.Mass * pushbackRatio * MathF.Min(massLimit, physics.Mass), body: userPhysics); } + + +} + +/// +/// If a throwing action should attempt to unanchor anchored entities. +/// +[Serializable, NetSerializable] +public enum ThrowingUnanchorStrength : byte +{ + /// + /// No entites will be unanchored. + /// + None, + /// + /// Only entities that can be unanchored (e.g. via wrench) will be unanchored. + /// + Unanchorable, + /// + /// All entities will be unanchored. + /// + All, } diff --git a/Content.Shared/Weapons/Melee/Components/MeleeThrowOnHitComponent.cs b/Content.Shared/Weapons/Melee/Components/MeleeThrowOnHitComponent.cs index 42b72efede..2c16ea7582 100644 --- a/Content.Shared/Weapons/Melee/Components/MeleeThrowOnHitComponent.cs +++ b/Content.Shared/Weapons/Melee/Components/MeleeThrowOnHitComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Throwing; using Robust.Shared.GameStates; namespace Content.Shared.Weapons.Melee.Components; @@ -26,7 +27,7 @@ public sealed partial class MeleeThrowOnHitComponent : Component /// Whether or not anchorable entities should be unanchored when hit. /// [DataField, AutoNetworkedField] - public bool UnanchorOnHit; + public ThrowingUnanchorStrength UnanchorOnHit = ThrowingUnanchorStrength.None; /// /// How long should this stun the target, if applicable? diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml index 71dbed0aac..e9b365de9a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml @@ -188,7 +188,7 @@ path: "/Audio/Weapons/Guns/Gunshots/kinetic_accel.ogg" - type: CorePoweredThrower - type: MeleeThrowOnHit - unanchorOnHit: true + unanchorOnHit: Unanchorable - type: ItemSlots slots: core_slot: