2020-05-25 14:04:58 +02:00
using System.Linq ;
2018-10-30 01:13:10 -07:00
using Content.Server.GameObjects.Components.Stack ;
2020-05-05 00:39:15 +02:00
using Content.Server.Interfaces ;
2018-11-11 11:32:05 -08:00
using Content.Server.Interfaces.GameObjects ;
2020-02-24 07:52:15 +05:00
using Content.Server.Throw ;
2020-05-05 00:39:15 +02:00
using Content.Shared.GameObjects.Components.Inventory ;
2018-08-22 01:19:47 -07:00
using Content.Shared.Input ;
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.GameObjects.EntitySystems ;
using Robust.Server.Interfaces.Player ;
using Robust.Shared.GameObjects ;
using Robust.Shared.GameObjects.Systems ;
using Robust.Shared.Input ;
2019-11-25 00:11:47 +01:00
using Robust.Shared.Interfaces.GameObjects ;
2019-04-20 16:20:18 -07:00
using Robust.Shared.Interfaces.Map ;
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-05-28 13:23:50 +02:00
using System ;
2018-08-18 15:28:02 -07:00
namespace Content.Server.GameObjects.EntitySystems
{
2019-05-05 13:09:21 +02:00
[UsedImplicitly]
internal sealed class HandsSystem : EntitySystem
2018-08-18 15:28:02 -07:00
{
2019-04-20 16:20:18 -07:00
#pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager ;
2020-05-05 00:39:15 +02:00
[Dependency] private readonly IServerNotifyManager _notifyManager ;
2019-04-20 16:20:18 -07:00
#pragma warning restore 649
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
2018-08-18 15:28:02 -07:00
var input = EntitySystemManager . GetEntitySystem < InputSystem > ( ) ;
input . BindMap . BindFunction ( ContentKeyFunctions . SwapHands , InputCmdHandler . FromDelegate ( HandleSwapHands ) ) ;
2018-08-22 01:19:47 -07:00
input . BindMap . BindFunction ( ContentKeyFunctions . Drop , new PointerInputCmdHandler ( HandleDrop ) ) ;
2018-08-18 15:28:02 -07:00
input . BindMap . BindFunction ( ContentKeyFunctions . ActivateItemInHand , InputCmdHandler . FromDelegate ( HandleActivateItem ) ) ;
2018-08-22 01:19:47 -07:00
input . BindMap . BindFunction ( ContentKeyFunctions . ThrowItemInHand , new PointerInputCmdHandler ( HandleThrowItem ) ) ;
2020-05-05 00:39:15 +02:00
input . BindMap . BindFunction ( ContentKeyFunctions . SmartEquipBackpack , InputCmdHandler . FromDelegate ( HandleSmartEquipBackpack ) ) ;
input . BindMap . BindFunction ( ContentKeyFunctions . SmartEquipBelt , InputCmdHandler . FromDelegate ( HandleSmartEquipBelt ) ) ;
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 ( )
{
if ( EntitySystemManager . TryGetEntitySystem ( out InputSystem input ) )
{
input . BindMap . UnbindFunction ( ContentKeyFunctions . SwapHands ) ;
input . BindMap . UnbindFunction ( ContentKeyFunctions . Drop ) ;
input . BindMap . UnbindFunction ( ContentKeyFunctions . ActivateItemInHand ) ;
2018-08-22 01:19:47 -07:00
input . BindMap . UnbindFunction ( ContentKeyFunctions . ThrowItemInHand ) ;
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 ;
if ( ent = = null | | ! ent . IsValid ( ) )
return false ;
if ( ! ent . TryGetComponent ( out T comp ) )
return false ;
component = comp ;
return true ;
}
private static void HandleSwapHands ( ICommonSession session )
{
if ( ! TryGetAttachedComponent ( session as IPlayerSession , out HandsComponent handsComp ) )
return ;
2020-05-23 02:27:31 -07:00
var interactionSystem = EntitySystem . 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 ;
if ( oldItem ! = null )
interactionSystem . HandDeselectedInteraction ( handsComp . Owner , oldItem . Owner ) ;
if ( newItem ! = null )
interactionSystem . HandSelectedInteraction ( handsComp . Owner , newItem . Owner ) ;
2018-08-18 15:28:02 -07:00
}
2019-09-17 16:08:45 -07:00
private bool HandleDrop ( ICommonSession session , GridCoordinates 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-05-28 13:23:50 +02:00
var entCoords = ent . Transform . GridPosition . Position ;
var entToDesiredDropCoords = coords . Position - entCoords ;
var targetLength = Math . Min ( entToDesiredDropCoords . Length , InteractionSystem . InteractionRange - 0.001f ) ; // InteractionRange is reduced due to InRange not dealing with floating point error
var newCoords = new GridCoordinates ( ( entToDesiredDropCoords . Normalized * targetLength ) + entCoords , coords . GridID ) ;
var rayLength = EntitySystem . Get < SharedInteractionSystem > ( ) . UnobstructedRayLength ( ent . Transform . MapPosition , newCoords . ToMap ( _mapManager ) , ignoredEnt : ent ) ;
2020-02-12 00:01:44 +01:00
2020-05-28 13:23:50 +02:00
handsComp . Drop ( handsComp . ActiveIndex , new GridCoordinates ( entCoords + ( entToDesiredDropCoords . Normalized * rayLength ) , coords . GridID ) ) ;
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
2019-09-17 16:08:45 -07:00
private bool HandleThrowItem ( ICommonSession session , GridCoordinates 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
2018-10-30 01:13:10 -07:00
if ( ! handsComp . CanDrop ( handsComp . ActiveIndex ) )
2019-09-17 16:08:45 -07:00
return false ;
2018-10-30 01:13:10 -07:00
var throwEnt = handsComp . GetHand ( handsComp . ActiveIndex ) . Owner ;
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
{
2018-12-13 05:49:05 -08:00
handsComp . Drop ( handsComp . ActiveIndex ) ;
2018-10-30 01:13:10 -07:00
}
else
{
stackComp . Use ( 1 ) ;
2020-01-24 16:10:48 -08:00
throwEnt = throwEnt . EntityManager . SpawnEntity ( throwEnt . Prototype . ID , plyEnt . Transform . GridPosition ) ;
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-05-25 14:04:58 +02:00
ThrowHelper . ThrowTo ( throwEnt , ThrowForce , coords , plyEnt . Transform . GridPosition , 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 )
{
HandleSmartEquip ( session , EquipmentSlotDefines . Slots . BACKPACK ) ;
}
private void HandleSmartEquipBelt ( ICommonSession session )
{
HandleSmartEquip ( session , EquipmentSlotDefines . Slots . BELT ) ;
}
private void HandleSmartEquip ( ICommonSession session , EquipmentSlotDefines . Slots equipementSlot )
{
var plyEnt = ( ( IPlayerSession ) session ) . AttachedEntity ;
if ( plyEnt = = null | | ! plyEnt . IsValid ( ) )
return ;
if ( ! plyEnt . TryGetComponent ( out HandsComponent handsComp ) | | ! plyEnt . TryGetComponent ( out InventoryComponent inventoryComp ) )
return ;
if ( ! inventoryComp . TryGetSlotItem ( equipementSlot , out ItemComponent equipmentItem )
| | ! equipmentItem . Owner . TryGetComponent < ServerStorageComponent > ( out var storageComponent ) )
{
_notifyManager . PopupMessage ( plyEnt , plyEnt , Loc . GetString ( "You have no {0} to take something out of!" , EquipmentSlotDefines . SlotNames [ equipementSlot ] . ToLower ( ) ) ) ;
return ;
}
var heldItem = handsComp . GetHand ( handsComp . ActiveIndex ) ? . Owner ;
if ( heldItem ! = null )
{
storageComponent . PlayerInsertEntity ( plyEnt ) ;
}
else
{
if ( storageComponent . StoredEntities . Count = = 0 )
{
_notifyManager . PopupMessage ( plyEnt , plyEnt , Loc . GetString ( "There's nothing in your {0} to take out!" , EquipmentSlotDefines . SlotNames [ equipementSlot ] . ToLower ( ) ) ) ;
}
else
{
var lastStoredEntity = Enumerable . Last ( storageComponent . StoredEntities ) ;
if ( storageComponent . Remove ( lastStoredEntity ) )
handsComp . PutInHandOrDrop ( lastStoredEntity . GetComponent < ItemComponent > ( ) ) ;
}
}
}
2018-08-18 15:28:02 -07:00
}
}