2022-07-18 19:49:52 +10:00
using Content.Shared.Gravity ;
2022-03-24 02:33:01 +13:00
using Content.Shared.Interaction ;
2022-06-23 12:13:22 +10:00
using Content.Shared.Movement.Components ;
2022-03-24 02:33:01 +13:00
using Content.Shared.Tag ;
using Robust.Shared.Physics ;
2022-09-14 17:26:26 +10:00
using Robust.Shared.Physics.Components ;
2022-12-28 03:58:53 +11:00
using Robust.Shared.Physics.Systems ;
2022-03-24 02:33:01 +13:00
using Robust.Shared.Timing ;
namespace Content.Shared.Throwing ;
public sealed class ThrowingSystem : EntitySystem
{
public const float ThrowAngularImpulse = 1.5f ;
/// <summary>
/// The minimum amount of time an entity needs to be thrown before the timer can be run.
/// Anything below this threshold never enters the air.
/// </summary>
public const float FlyTime = 0.15f ;
2022-07-18 19:49:52 +10:00
[Dependency] private readonly SharedGravitySystem _gravity = default ! ;
2022-03-24 02:33:01 +13:00
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default ! ;
2022-12-28 03:58:53 +11:00
[Dependency] private readonly SharedPhysicsSystem _physics = default ! ;
2022-03-24 02:33:01 +13:00
[Dependency] private readonly ThrownItemSystem _thrownSystem = default ! ;
[Dependency] private readonly TagSystem _tagSystem = default ! ;
/// <summary>
/// Tries to throw the entity if it has a physics component, otherwise does nothing.
/// </summary>
2022-07-18 19:49:52 +10:00
/// <param name="uid">The entity being thrown.</param>
2022-03-24 02:33:01 +13:00
/// <param name="direction">A vector pointing from the entity to its destination.</param>
/// <param name="strength">How much the direction vector should be multiplied for velocity.</param>
/// <param name="pushbackRatio">The ratio of impulse applied to the thrower - defaults to 10 because otherwise it's not enough to properly recover from getting spaced</param>
public void TryThrow (
EntityUid uid ,
Vector2 direction ,
float strength = 1.0f ,
EntityUid ? user = null ,
2022-07-16 13:51:52 +10:00
float pushbackRatio = 5.0f ,
2022-03-24 02:33:01 +13:00
PhysicsComponent ? physics = null ,
TransformComponent ? transform = null ,
EntityQuery < PhysicsComponent > ? physicsQuery = null ,
EntityQuery < TransformComponent > ? xformQuery = null )
{
if ( strength < = 0 | | direction = = Vector2 . Infinity | | direction = = Vector2 . NaN | | direction = = Vector2 . Zero )
return ;
physicsQuery ? ? = GetEntityQuery < PhysicsComponent > ( ) ;
if ( physics = = null & & ! physicsQuery . Value . TryGetComponent ( uid , out physics ) )
return ;
2022-07-16 13:04:14 +10:00
if ( ( physics . BodyType & ( BodyType . Dynamic | BodyType . KinematicController ) ) = = 0x0 )
2022-03-24 02:33:01 +13:00
{
Logger . Warning ( $"Tried to throw entity {ToPrettyString(uid)} but can't throw {physics.BodyType} bodies!" ) ;
return ;
}
var comp = EnsureComp < ThrownItemComponent > ( uid ) ;
comp . Thrower = user ;
// Give it a l'il spin.
if ( ! _tagSystem . HasTag ( uid , "NoSpinOnThrow" ) )
2023-01-15 15:38:59 +11:00
_physics . ApplyAngularImpulse ( uid , ThrowAngularImpulse , body : physics ) ;
2022-03-24 02:33:01 +13:00
else
{
if ( transform = = null )
{
xformQuery ? ? = GetEntityQuery < TransformComponent > ( ) ;
transform = xformQuery . Value . GetComponent ( uid ) ;
}
transform . LocalRotation = direction . ToWorldAngle ( ) - Math . PI ;
}
if ( user ! = null )
_interactionSystem . ThrownInteraction ( user . Value , uid ) ;
var impulseVector = direction . Normalized * strength * physics . Mass ;
2023-01-15 15:38:59 +11:00
_physics . ApplyLinearImpulse ( uid , impulseVector , body : physics ) ;
2022-03-24 02:33:01 +13:00
// Estimate time to arrival so we can apply OnGround status and slow it much faster.
var time = ( direction / strength ) . Length ;
if ( time < FlyTime )
{
2023-03-11 19:26:01 +11:00
_thrownSystem . LandComponent ( uid , comp , physics ) ;
2022-03-24 02:33:01 +13:00
}
else
{
2022-12-28 03:58:53 +11:00
_physics . SetBodyStatus ( physics , BodyStatus . InAir ) ;
2022-03-24 02:33:01 +13:00
Timer . Spawn ( TimeSpan . FromSeconds ( time - FlyTime ) , ( ) = >
{
2022-12-28 03:58:53 +11:00
if ( physics . Deleted )
return ;
2023-03-11 19:26:01 +11:00
_thrownSystem . LandComponent ( uid , comp , physics ) ;
2022-03-24 02:33:01 +13:00
} ) ;
}
// Give thrower an impulse in the other direction
2022-06-23 12:13:22 +10:00
if ( user ! = null & &
pushbackRatio > 0.0f & &
physicsQuery . Value . TryGetComponent ( user . Value , out var userPhysics ) & &
2022-07-18 19:49:52 +10:00
_gravity . IsWeightless ( user . Value , userPhysics ) )
2022-03-24 02:33:01 +13:00
{
var msg = new ThrowPushbackAttemptEvent ( ) ;
2023-03-11 19:26:01 +11:00
RaiseLocalEvent ( uid , msg ) ;
2022-03-24 02:33:01 +13:00
if ( ! msg . Cancelled )
2023-01-15 15:38:59 +11:00
_physics . ApplyLinearImpulse ( user . Value , - impulseVector * pushbackRatio , body : userPhysics ) ;
2022-03-24 02:33:01 +13:00
}
}
}