2020-08-13 14:40:27 +02:00
using System ;
using System.Linq ;
using Content.Server.GameObjects.Components.GUI ;
using Content.Server.GameObjects.Components.Items.Storage ;
2018-10-30 01:13:10 -07:00
using Content.Server.GameObjects.Components.Stack ;
2020-08-13 14:40:27 +02:00
using Content.Server.GameObjects.EntitySystems.Click ;
using Content.Server.Interfaces.GameObjects.Components.Items ;
2020-02-24 07:52:15 +05:00
using Content.Server.Throw ;
2020-08-13 14:40:27 +02:00
using Content.Shared.GameObjects.EntitySystems ;
2018-08-22 01:19:47 -07:00
using Content.Shared.Input ;
2020-09-01 12:34:53 +02:00
using Content.Shared.Interfaces ;
2019-05-05 13:09:21 +02:00
using JetBrains.Annotations ;
using Robust.Server.GameObjects.EntitySystemMessages ;
2019-04-15 21:11:38 -06:00
using Robust.Server.Interfaces.Player ;
using Robust.Shared.GameObjects ;
using Robust.Shared.GameObjects.Systems ;
2020-05-31 14:32:05 -07:00
using Robust.Shared.Input.Binding ;
2020-09-06 16:11:53 +02:00
using Robust.Shared.Interfaces.GameObjects ;
2019-04-15 21:11:38 -06:00
using Robust.Shared.IoC ;
2020-05-05 00:39:15 +02:00
using Robust.Shared.Localization ;
2019-04-15 21:11:38 -06:00
using Robust.Shared.Map ;
using Robust.Shared.Players ;
2020-09-13 14:23:52 +02:00
using static Content . Shared . GameObjects . Components . Inventory . EquipmentSlotDefines ;
2018-08-18 15:28:02 -07:00
2020-08-13 14:40:27 +02:00
namespace Content.Server.GameObjects.EntitySystems
2018-08-18 15:28:02 -07:00
{
2019-05-05 13:09:21 +02:00
[UsedImplicitly]
internal sealed class HandsSystem : EntitySystem
2018-08-18 15:28:02 -07:00
{
2020-09-06 16:11:53 +02:00
[Dependency] private readonly IEntityManager _entityManager = default ! ;
2019-04-20 16:20:18 -07:00
2018-10-30 01:13:10 -07:00
private const float ThrowForce = 1.5f ; // Throwing force of mobs in Newtons
2018-08-22 01:19:47 -07:00
2018-08-18 15:28:02 -07:00
/// <inheritdoc />
public override void Initialize ( )
{
base . Initialize ( ) ;
2020-02-19 17:08:59 -08:00
SubscribeLocalEvent < EntRemovedFromContainerMessage > ( HandleContainerModified ) ;
SubscribeLocalEvent < EntInsertedIntoContainerMessage > ( HandleContainerModified ) ;
2020-02-18 19:43:54 -08:00
2020-05-31 14:32:05 -07:00
CommandBinds . Builder
. Bind ( ContentKeyFunctions . SwapHands , InputCmdHandler . FromDelegate ( HandleSwapHands ) )
. Bind ( ContentKeyFunctions . Drop , new PointerInputCmdHandler ( HandleDrop ) )
. Bind ( ContentKeyFunctions . ActivateItemInHand , InputCmdHandler . FromDelegate ( HandleActivateItem ) )
. Bind ( ContentKeyFunctions . ThrowItemInHand , new PointerInputCmdHandler ( HandleThrowItem ) )
. Bind ( ContentKeyFunctions . SmartEquipBackpack , InputCmdHandler . FromDelegate ( HandleSmartEquipBackpack ) )
2020-07-27 00:54:32 +02:00
. Bind ( ContentKeyFunctions . SmartEquipBelt , InputCmdHandler . FromDelegate ( HandleSmartEquipBelt ) )
. Register < HandsSystem > ( ) ;
2018-08-18 15:28:02 -07:00
}
2018-11-21 20:58:11 +01:00
2018-08-18 15:28:02 -07:00
/// <inheritdoc />
public override void Shutdown ( )
{
2020-05-31 14:32:05 -07:00
CommandBinds . Unregister < HandsSystem > ( ) ;
2018-08-18 15:28:02 -07:00
base . Shutdown ( ) ;
}
2020-02-19 14:39:00 -08:00
private static void HandleContainerModified ( ContainerModifiedMessage args )
2018-08-22 01:19:47 -07:00
{
2019-05-05 13:09:21 +02:00
if ( args . Container . Owner . TryGetComponent ( out IHandsComponent handsComponent ) )
2018-11-11 11:32:05 -08:00
{
2019-05-05 13:09:21 +02:00
handsComponent . HandleSlotModifiedMaybe ( args ) ;
2018-11-11 11:32:05 -08:00
}
2018-08-22 01:19:47 -07:00
}
2018-08-18 15:28:02 -07:00
private static bool TryGetAttachedComponent < T > ( IPlayerSession session , out T component )
where T : Component
{
2018-09-13 20:09:53 +02:00
component = default ;
2018-08-18 15:28:02 -07:00
var ent = session . AttachedEntity ;
2020-07-25 15:11:16 +02:00
if ( ent = = null | | ! ent . IsValid ( ) | | ! ent . TryGetComponent ( out T comp ) )
{
2018-08-18 15:28:02 -07:00
return false ;
2020-07-25 15:11:16 +02:00
}
2018-08-18 15:28:02 -07:00
component = comp ;
return true ;
}
private static void HandleSwapHands ( ICommonSession session )
{
if ( ! TryGetAttachedComponent ( session as IPlayerSession , out HandsComponent handsComp ) )
2020-07-25 15:11:16 +02:00
{
2018-08-18 15:28:02 -07:00
return ;
2020-07-25 15:11:16 +02:00
}
2018-08-18 15:28:02 -07:00
2020-07-25 15:11:16 +02:00
var interactionSystem = Get < InteractionSystem > ( ) ;
2019-11-25 00:11:47 +01:00
var oldItem = handsComp . GetActiveHand ;
2018-08-18 15:28:02 -07:00
handsComp . SwapHands ( ) ;
2019-11-25 00:11:47 +01:00
var newItem = handsComp . GetActiveHand ;
2020-07-25 15:11:16 +02:00
if ( oldItem ! = null )
{
2019-11-25 00:11:47 +01:00
interactionSystem . HandDeselectedInteraction ( handsComp . Owner , oldItem . Owner ) ;
2020-07-25 15:11:16 +02:00
}
2019-11-25 00:11:47 +01:00
2020-07-25 15:11:16 +02:00
if ( newItem ! = null )
{
2019-11-25 00:11:47 +01:00
interactionSystem . HandSelectedInteraction ( handsComp . Owner , newItem . Owner ) ;
2020-07-25 15:11:16 +02:00
}
2018-08-18 15:28:02 -07:00
}
2020-09-06 16:11:53 +02:00
private bool HandleDrop ( ICommonSession session , EntityCoordinates coords , EntityUid uid )
2018-08-18 15:28:02 -07:00
{
2018-08-22 01:19:47 -07:00
var ent = ( ( IPlayerSession ) session ) . AttachedEntity ;
2019-04-17 23:26:00 +02:00
if ( ent = = null | | ! ent . IsValid ( ) )
2019-09-17 16:08:45 -07:00
return false ;
2018-08-18 15:28:02 -07:00
2018-08-22 01:19:47 -07:00
if ( ! ent . TryGetComponent ( out HandsComponent handsComp ) )
2019-09-17 16:08:45 -07:00
return false ;
2019-11-25 00:11:47 +01:00
if ( handsComp . GetActiveHand = = null )
return false ;
2020-09-06 16:11:53 +02:00
var entCoords = ent . Transform . Coordinates . Position ;
2020-05-28 13:23:50 +02:00
var entToDesiredDropCoords = coords . Position - entCoords ;
2020-07-25 15:11:16 +02:00
var targetLength = Math . Min ( entToDesiredDropCoords . Length , SharedInteractionSystem . InteractionRange - 0.001f ) ; // InteractionRange is reduced due to InRange not dealing with floating point error
2020-09-20 15:29:11 +00:00
var newCoords = coords . WithPosition ( entToDesiredDropCoords . Normalized * targetLength + entCoords ) . ToMap ( _entityManager ) ;
2020-09-06 16:11:53 +02:00
var rayLength = Get < SharedInteractionSystem > ( ) . UnobstructedDistance ( ent . Transform . MapPosition , newCoords , ignoredEnt : ent ) ;
2020-02-12 00:01:44 +01:00
2020-09-20 15:29:11 +00:00
handsComp . Drop ( handsComp . ActiveHand , coords . WithPosition ( entCoords + entToDesiredDropCoords . Normalized * rayLength ) ) ;
2019-09-17 16:08:45 -07:00
return true ;
2018-08-18 15:28:02 -07:00
}
private static void HandleActivateItem ( ICommonSession session )
{
if ( ! TryGetAttachedComponent ( session as IPlayerSession , out HandsComponent handsComp ) )
return ;
handsComp . ActivateItem ( ) ;
}
2018-08-22 01:19:47 -07:00
2020-09-06 16:11:53 +02:00
private bool HandleThrowItem ( ICommonSession session , EntityCoordinates coords , EntityUid uid )
2018-08-22 01:19:47 -07:00
{
var plyEnt = ( ( IPlayerSession ) session ) . AttachedEntity ;
if ( plyEnt = = null | | ! plyEnt . IsValid ( ) )
2019-09-17 16:08:45 -07:00
return false ;
2018-08-22 01:19:47 -07:00
if ( ! plyEnt . TryGetComponent ( out HandsComponent handsComp ) )
2019-09-17 16:08:45 -07:00
return false ;
2018-08-22 01:19:47 -07:00
2020-07-25 15:11:16 +02:00
if ( ! handsComp . CanDrop ( handsComp . ActiveHand ) )
2019-09-17 16:08:45 -07:00
return false ;
2018-10-30 01:13:10 -07:00
2020-07-25 15:11:16 +02:00
var throwEnt = handsComp . GetItem ( handsComp . ActiveHand ) . Owner ;
2018-10-30 01:13:10 -07:00
2019-07-18 23:33:02 +02:00
if ( ! handsComp . ThrowItem ( ) )
2019-09-17 16:08:45 -07:00
return false ;
2019-07-18 23:33:02 +02:00
2020-02-13 22:43:02 +00:00
// throw the item, split off from a stack if it's meant to be thrown individually
if ( ! throwEnt . TryGetComponent ( out StackComponent stackComp ) | | stackComp . Count < 2 | | ! stackComp . ThrowIndividually )
2018-08-22 01:19:47 -07:00
{
2020-07-25 15:11:16 +02:00
handsComp . Drop ( handsComp . ActiveHand ) ;
2018-10-30 01:13:10 -07:00
}
else
{
stackComp . Use ( 1 ) ;
2020-09-06 16:11:53 +02:00
throwEnt = throwEnt . EntityManager . SpawnEntity ( throwEnt . Prototype . ID , plyEnt . Transform . Coordinates ) ;
2019-09-01 16:23:30 -07:00
// can only throw one item at a time, regardless of what the prototype stack size is.
if ( throwEnt . TryGetComponent < StackComponent > ( out var newStackComp ) )
newStackComp . Count = 1 ;
2018-10-30 01:13:10 -07:00
}
2018-11-21 20:58:11 +01:00
2020-10-14 22:41:44 +02:00
throwEnt . ThrowTo ( ThrowForce , coords , plyEnt . Transform . Coordinates , false , plyEnt ) ;
2019-07-18 23:33:02 +02:00
2019-09-17 16:08:45 -07:00
return true ;
2018-08-22 01:19:47 -07:00
}
2020-05-05 00:39:15 +02:00
private void HandleSmartEquipBackpack ( ICommonSession session )
{
2020-09-13 14:23:52 +02:00
HandleSmartEquip ( session , Slots . BACKPACK ) ;
2020-05-05 00:39:15 +02:00
}
private void HandleSmartEquipBelt ( ICommonSession session )
{
2020-09-13 14:23:52 +02:00
HandleSmartEquip ( session , Slots . BELT ) ;
2020-05-05 00:39:15 +02:00
}
2020-09-13 14:23:52 +02:00
private void HandleSmartEquip ( ICommonSession session , Slots equipmentSlot )
2020-05-05 00:39:15 +02:00
{
var plyEnt = ( ( IPlayerSession ) session ) . AttachedEntity ;
if ( plyEnt = = null | | ! plyEnt . IsValid ( ) )
return ;
2020-07-27 00:54:32 +02:00
if ( ! plyEnt . TryGetComponent ( out HandsComponent handsComp ) | |
! plyEnt . TryGetComponent ( out InventoryComponent inventoryComp ) )
2020-05-05 00:39:15 +02:00
return ;
2020-09-13 14:23:52 +02:00
if ( ! inventoryComp . TryGetSlotItem ( equipmentSlot , out ItemComponent equipmentItem )
2020-05-05 00:39:15 +02:00
| | ! equipmentItem . Owner . TryGetComponent < ServerStorageComponent > ( out var storageComponent ) )
{
2020-09-01 12:34:53 +02:00
plyEnt . PopupMessage ( Loc . GetString ( "You have no {0} to take something out of!" ,
2020-09-13 14:23:52 +02:00
SlotNames [ equipmentSlot ] . ToLower ( ) ) ) ;
2020-05-05 00:39:15 +02:00
return ;
}
2020-07-25 15:11:16 +02:00
var heldItem = handsComp . GetItem ( handsComp . ActiveHand ) ? . Owner ;
2020-05-05 00:39:15 +02:00
if ( heldItem ! = null )
{
storageComponent . PlayerInsertEntity ( plyEnt ) ;
}
else
{
if ( storageComponent . StoredEntities . Count = = 0 )
{
2020-09-01 12:34:53 +02:00
plyEnt . PopupMessage ( Loc . GetString ( "There's nothing in your {0} to take out!" ,
2020-09-13 14:23:52 +02:00
SlotNames [ equipmentSlot ] . ToLower ( ) ) ) ;
2020-05-05 00:39:15 +02:00
}
else
{
var lastStoredEntity = Enumerable . Last ( storageComponent . StoredEntities ) ;
if ( storageComponent . Remove ( lastStoredEntity ) )
handsComp . PutInHandOrDrop ( lastStoredEntity . GetComponent < ItemComponent > ( ) ) ;
}
}
}
2018-08-18 15:28:02 -07:00
}
}