2021-07-23 16:12:07 +10:00
using System ;
2021-06-09 22:19:39 +02:00
using Content.Server.Interaction ;
2021-12-30 22:56:10 +01:00
using Content.Shared.Item ;
2021-11-08 15:11:58 +01:00
using Content.Shared.MobState.Components ;
2021-07-23 16:12:07 +10:00
using Content.Shared.Tag ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Throwing ;
2021-03-08 04:09:59 +11:00
using Robust.Shared.GameObjects ;
2021-12-03 11:11:52 +01:00
using Robust.Shared.IoC ;
2021-03-08 04:09:59 +11:00
using Robust.Shared.Log ;
using Robust.Shared.Maths ;
using Robust.Shared.Physics ;
2021-07-25 16:58:02 +10:00
using Robust.Shared.Timing ;
2021-03-08 04:09:59 +11:00
2021-06-09 22:19:39 +02:00
namespace Content.Server.Throwing
2021-03-08 04:09:59 +11:00
{
internal static class ThrowHelper
{
2021-07-25 16:58:02 +10:00
private 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>
private const float FlyTime = 0.15f ;
2021-03-30 21:43:03 +11:00
2021-03-08 04:09:59 +11:00
/// <summary>
/// Tries to throw the entity if it has a physics component, otherwise does nothing.
/// </summary>
2021-07-25 16:58:02 +10:00
/// <param name="entity">The entity being thrown.</param>
/// <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>
2021-03-08 12:10:56 +11:00
/// <param name="user"></param>
2021-12-03 16:26:51 -08:00
/// <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>
2021-12-07 17:48:49 +01:00
internal static void TryThrow ( this EntityUid entity , Vector2 direction , float strength = 1.0f , EntityUid ? user = null , float pushbackRatio = 10.0f )
2021-03-08 04:09:59 +11:00
{
2021-12-06 00:52:58 +01:00
var entities = IoCManager . Resolve < IEntityManager > ( ) ;
if ( entities . GetComponent < MetaDataComponent > ( entity ) . EntityDeleted | |
2021-07-25 16:58:02 +10:00
strength < = 0f | |
2021-12-06 00:52:58 +01:00
! entities . TryGetComponent ( entity , out PhysicsComponent ? physicsComponent ) )
2021-03-08 04:09:59 +11:00
{
return ;
}
2022-02-10 21:05:13 +11:00
if ( physicsComponent . BodyType ! = BodyType . Dynamic )
2021-03-08 04:09:59 +11:00
{
2022-02-10 21:05:13 +11:00
Logger . Warning ( $"Tried to throw entity {entities.ToPrettyString(entity)} but can't throw {physicsComponent.BodyType} bodies!" ) ;
2021-03-08 04:09:59 +11:00
return ;
}
2021-09-15 03:58:45 -07:00
var comp = entity . EnsureComponent < ThrownItemComponent > ( ) ;
2021-12-30 22:56:10 +01:00
if ( entities . HasComponent < SharedItemComponent > ( entity ) )
2021-03-08 04:09:59 +11:00
{
2021-09-15 03:58:45 -07:00
comp . Thrower = user ;
2021-03-30 21:43:03 +11:00
// Give it a l'il spin.
2022-02-08 14:08:11 +11:00
if ( ! EntitySystem . Get < TagSystem > ( ) . HasTag ( entity , "NoSpinOnThrow" ) )
2021-07-23 16:12:07 +10:00
{
physicsComponent . ApplyAngularImpulse ( ThrowAngularImpulse ) ;
}
2021-11-24 00:38:39 +01:00
else if ( direction ! = Vector2 . Zero )
2021-07-23 16:12:07 +10:00
{
2021-12-06 00:52:58 +01:00
entities . GetComponent < TransformComponent > ( entity ) . LocalRotation = direction . ToWorldAngle ( ) - Math . PI ;
2021-07-23 16:12:07 +10:00
}
2021-03-08 04:09:59 +11:00
if ( user ! = null )
2021-12-06 00:52:58 +01:00
EntitySystem . Get < InteractionSystem > ( ) . ThrownInteraction ( user . Value , entity ) ;
2021-03-08 04:09:59 +11:00
}
2021-07-31 08:53:18 -04:00
var impulseVector = direction . Normalized * strength * physicsComponent . Mass ;
physicsComponent . ApplyLinearImpulse ( impulseVector ) ;
2021-09-15 03:58:45 -07:00
2021-07-25 16:58:02 +10:00
// Estimate time to arrival so we can apply OnGround status and slow it much faster.
var time = ( direction / strength ) . Length ;
if ( time < FlyTime )
{
physicsComponent . BodyStatus = BodyStatus . OnGround ;
2021-11-24 00:38:39 +01:00
EntitySystem . Get < ThrownItemSystem > ( ) . LandComponent ( comp ) ;
2021-07-25 16:58:02 +10:00
}
else
{
physicsComponent . BodyStatus = BodyStatus . InAir ;
Timer . Spawn ( TimeSpan . FromSeconds ( time - FlyTime ) , ( ) = >
{
if ( physicsComponent . Deleted ) return ;
physicsComponent . BodyStatus = BodyStatus . OnGround ;
2021-09-15 03:58:45 -07:00
EntitySystem . Get < ThrownItemSystem > ( ) . LandComponent ( comp ) ;
2021-07-25 16:58:02 +10:00
} ) ;
}
2021-03-08 12:10:56 +11:00
// Give thrower an impulse in the other direction
2021-12-06 00:52:58 +01:00
if ( user ! = null & & pushbackRatio > 0.0f & & entities . TryGetComponent ( user . Value , out IPhysBody ? body ) )
2021-03-08 12:10:56 +11:00
{
2021-06-28 14:17:08 +10:00
var msg = new ThrowPushbackAttemptEvent ( ) ;
2021-12-06 00:52:58 +01:00
entities . EventBus . RaiseLocalEvent ( body . Owner , msg ) ;
2021-06-28 14:17:08 +10:00
if ( ! msg . Cancelled )
{
2021-07-31 08:53:18 -04:00
body . ApplyLinearImpulse ( - impulseVector * pushbackRatio ) ;
2021-06-28 14:17:08 +10:00
}
2021-03-08 12:10:56 +11:00
}
2021-03-08 04:09:59 +11:00
}
}
}