2023-04-07 11:21:12 -07:00
using Content.Server.Administration.Logs ;
2022-08-24 10:50:31 -04:00
using Content.Server.Ensnaring ;
2022-10-16 06:00:04 +13:00
using Content.Shared.CombatMode ;
2023-04-07 11:21:12 -07:00
using Content.Shared.Cuffs ;
using Content.Shared.Cuffs.Components ;
using Content.Shared.Database ;
using Content.Shared.DoAfter ;
using Content.Shared.Ensnaring.Components ;
2021-12-30 22:56:10 +01:00
using Content.Shared.Hands.Components ;
2022-05-13 14:59:57 +10:00
using Content.Shared.Hands.EntitySystems ;
2022-07-10 18:36:53 -07:00
using Content.Shared.IdentityManagement ;
2023-04-07 11:21:12 -07:00
using Content.Shared.Interaction ;
2022-05-13 14:59:57 +10:00
using Content.Shared.Interaction.Events ;
2021-12-30 22:56:10 +01:00
using Content.Shared.Inventory ;
2024-01-14 06:18:47 -04:00
using Content.Shared.Inventory.VirtualItem ;
2022-05-13 14:59:57 +10:00
using Content.Shared.Popups ;
2023-04-07 11:21:12 -07:00
using Content.Shared.Strip ;
2021-12-30 22:56:10 +01:00
using Content.Shared.Strip.Components ;
2021-10-05 14:29:03 +11:00
using Content.Shared.Verbs ;
2024-03-21 02:08:17 +02:00
using Content.Shared._White.MagGloves ;
2021-10-05 14:29:03 +11:00
using Robust.Server.GameObjects ;
2023-10-29 04:21:02 +11:00
using Robust.Shared.Player ;
2023-02-26 18:48:57 +11:00
using Robust.Shared.Utility ;
2024-03-14 22:57:52 -04:00
using System.Linq ;
2021-10-05 14:29:03 +11:00
namespace Content.Server.Strip
{
2023-02-14 00:29:34 +11:00
public sealed class StrippableSystem : SharedStrippableSystem
2021-10-05 14:29:03 +11:00
{
2021-12-30 22:56:10 +01:00
[Dependency] private readonly InventorySystem _inventorySystem = default ! ;
2024-03-14 22:57:52 -04:00
[Dependency] private readonly EnsnareableSystem _ensnaringSystem = default ! ;
2022-09-05 22:15:49 -04:00
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default ! ;
2024-03-14 22:57:52 -04:00
[Dependency] private readonly SharedCuffableSystem _cuffableSystem = default ! ;
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default ! ;
[Dependency] private readonly SharedHandsSystem _handsSystem = default ! ;
[Dependency] private readonly SharedPopupSystem _popupSystem = default ! ;
2022-10-16 03:32:00 -03:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2022-05-13 14:59:57 +10:00
// TODO: ECS popups. Not all of these have ECS equivalents yet.
2021-10-05 14:29:03 +11:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2022-02-10 15:30:59 +13:00
SubscribeLocalEvent < StrippableComponent , GetVerbsEvent < Verb > > ( AddStripVerb ) ;
2022-11-06 17:33:17 +01:00
SubscribeLocalEvent < StrippableComponent , GetVerbsEvent < ExamineVerb > > ( AddStripExamineVerb ) ;
2023-02-10 21:06:09 -05:00
SubscribeLocalEvent < StrippableComponent , ActivateInWorldEvent > ( OnActivateInWorld ) ;
2022-05-13 14:59:57 +10:00
// BUI
2022-10-16 06:00:04 +13:00
SubscribeLocalEvent < StrippableComponent , StrippingSlotButtonPressed > ( OnStripButtonPressed ) ;
SubscribeLocalEvent < EnsnareableComponent , StrippingEnsnareButtonPressed > ( OnStripEnsnareMessage ) ;
2024-03-14 22:57:52 -04:00
// DoAfters
SubscribeLocalEvent < HandsComponent , DoAfterAttemptEvent < StrippableDoAfterEvent > > ( OnStrippableDoAfterRunning ) ;
SubscribeLocalEvent < HandsComponent , StrippableDoAfterEvent > ( OnStrippableDoAfterFinished ) ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
private void AddStripVerb ( EntityUid uid , StrippableComponent component , GetVerbsEvent < Verb > args )
2022-08-24 10:50:31 -04:00
{
2024-03-14 22:57:52 -04:00
if ( args . Hands = = null | | ! args . CanAccess | | ! args . CanInteract | | args . Target = = args . User )
2022-08-24 10:50:31 -04:00
return ;
2024-03-14 22:57:52 -04:00
if ( ! HasComp < ActorComponent > ( args . User ) )
return ;
Verb verb = new ( )
2022-08-24 10:50:31 -04:00
{
2024-03-14 22:57:52 -04:00
Text = Loc . GetString ( "strip-verb-get-data-text" ) ,
Icon = new SpriteSpecifier . Texture ( new ( "/Textures/Interface/VerbIcons/outfit.svg.192dpi.png" ) ) ,
Act = ( ) = > StartOpeningStripper ( args . User , ( uid , component ) , true ) ,
} ;
2022-08-24 10:50:31 -04:00
2024-03-14 22:57:52 -04:00
args . Verbs . Add ( verb ) ;
2022-08-24 10:50:31 -04:00
}
2024-03-14 22:57:52 -04:00
private void AddStripExamineVerb ( EntityUid uid , StrippableComponent component , GetVerbsEvent < ExamineVerb > args )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( args . Hands = = null | | ! args . CanAccess | | ! args . CanInteract | | args . Target = = args . User )
2022-05-13 14:59:57 +10:00
return ;
2024-03-14 22:57:52 -04:00
if ( ! HasComp < ActorComponent > ( args . User ) )
2024-03-21 02:08:17 +02:00
return ;
2024-03-14 22:57:52 -04:00
ExamineVerb verb = new ( )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
Text = Loc . GetString ( "strip-verb-get-data-text" ) ,
Icon = new SpriteSpecifier . Texture ( new ( "/Textures/Interface/VerbIcons/outfit.svg.192dpi.png" ) ) ,
Act = ( ) = > StartOpeningStripper ( args . User , ( uid , component ) , true ) ,
Category = VerbCategory . Examine ,
} ;
2022-10-16 06:00:04 +13:00
2024-03-14 22:57:52 -04:00
args . Verbs . Add ( verb ) ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
private void OnActivateInWorld ( EntityUid uid , StrippableComponent component , ActivateInWorldEvent args )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( args . Target = = args . User )
2022-05-13 14:59:57 +10:00
return ;
2024-03-14 22:57:52 -04:00
if ( ! HasComp < ActorComponent > ( args . User ) )
2022-10-16 06:00:04 +13:00
return ;
2024-03-14 22:57:52 -04:00
StartOpeningStripper ( args . User , ( uid , component ) ) ;
2022-05-13 14:59:57 +10:00
}
2023-10-19 12:34:31 -07:00
public override void StartOpeningStripper ( EntityUid user , Entity < StrippableComponent > strippable , bool openInCombat = false )
2022-05-13 14:59:57 +10:00
{
2023-10-19 12:34:31 -07:00
base . StartOpeningStripper ( user , strippable , openInCombat ) ;
2023-02-14 00:29:34 +11:00
2023-04-08 13:16:48 -07:00
if ( TryComp < CombatModeComponent > ( user , out var mode ) & & mode . IsInCombatMode & & ! openInCombat )
2022-09-05 22:15:49 -04:00
return ;
2022-05-13 14:59:57 +10:00
if ( TryComp < ActorComponent > ( user , out var actor ) )
{
2023-10-19 12:34:31 -07:00
if ( _userInterfaceSystem . SessionHasOpenUi ( strippable , StrippingUiKey . Key , actor . PlayerSession ) )
2022-05-13 14:59:57 +10:00
return ;
2023-10-19 12:34:31 -07:00
_userInterfaceSystem . TryOpen ( strippable , StrippingUiKey . Key , actor . PlayerSession ) ;
2022-05-13 14:59:57 +10:00
}
2021-12-30 22:56:10 +01:00
}
2024-03-14 22:57:52 -04:00
private void OnStripButtonPressed ( Entity < StrippableComponent > strippable , ref StrippingSlotButtonPressed args )
2021-10-05 14:29:03 +11:00
{
2024-03-14 22:57:52 -04:00
if ( args . Session . AttachedEntity is not { Valid : true } user | |
2024-03-15 23:50:53 -04:00
! TryComp < HandsComponent > ( user , out var userHands ) )
2024-03-26 15:52:23 +07:00
{
2021-10-05 14:29:03 +11:00
return ;
2024-03-26 15:52:23 +07:00
}
2021-10-05 14:29:03 +11:00
2024-03-26 15:52:23 +07:00
// WD EDIT
if ( ( args . Slot = = "gloves" | | args . IsHand ) & & TryComp ( strippable , out PreventStrippingFromHandsAndGlovesComponent ? _ ) )
{
var message = Loc . GetString ( "maggloves-cant-strip" ) ;
_popupSystem . PopupEntity ( message , user , user ) ;
2021-10-05 14:29:03 +11:00
return ;
2024-03-26 15:52:23 +07:00
}
// WD EDIT END
2021-10-05 14:29:03 +11:00
2024-03-14 22:57:52 -04:00
if ( args . IsHand )
2022-05-13 14:59:57 +10:00
{
2024-03-15 23:50:53 -04:00
StripHand ( ( user , userHands ) , ( strippable . Owner , null ) , args . Slot , strippable ) ;
2021-10-05 14:29:03 +11:00
return ;
2024-03-14 22:57:52 -04:00
}
2021-10-05 14:29:03 +11:00
2024-03-14 22:57:52 -04:00
if ( ! TryComp < InventoryComponent > ( strippable , out var inventory ) )
return ;
var hasEnt = _inventorySystem . TryGetSlotEntity ( strippable , args . Slot , out var held , inventory ) ;
if ( userHands . ActiveHandEntity ! = null & & ! hasEnt )
StartStripInsertInventory ( ( user , userHands ) , strippable . Owner , userHands . ActiveHandEntity . Value , args . Slot ) ;
else if ( userHands . ActiveHandEntity = = null & & hasEnt )
StartStripRemoveInventory ( user , strippable . Owner , held ! . Value , args . Slot ) ;
2021-10-05 14:29:03 +11:00
}
2022-11-06 17:33:17 +01:00
2024-03-14 22:57:52 -04:00
private void StripHand (
Entity < HandsComponent ? > user ,
Entity < HandsComponent ? > target ,
string handId ,
StrippableComponent ? targetStrippable )
2022-11-06 17:33:17 +01:00
{
2024-03-14 22:57:52 -04:00
if ( ! Resolve ( user , ref user . Comp ) | |
! Resolve ( target , ref target . Comp ) | |
! Resolve ( target , ref targetStrippable ) )
2022-11-06 17:33:17 +01:00
return ;
2024-03-14 22:57:52 -04:00
if ( ! _handsSystem . TryGetHand ( target . Owner , handId , out var handSlot ) )
2022-11-06 17:33:17 +01:00
return ;
2024-03-14 22:57:52 -04:00
// Is the target a handcuff?
if ( TryComp < VirtualItemComponent > ( handSlot . HeldEntity , out var virtualItem ) & &
TryComp < CuffableComponent > ( target . Owner , out var cuffable ) & &
_cuffableSystem . GetAllCuffs ( cuffable ) . Contains ( virtualItem . BlockingEntity ) )
2022-11-06 17:33:17 +01:00
{
2024-03-14 22:57:52 -04:00
_cuffableSystem . TryUncuff ( target . Owner , user , virtualItem . BlockingEntity , cuffable ) ;
return ;
}
2022-11-06 17:33:17 +01:00
2024-03-14 22:57:52 -04:00
if ( user . Comp . ActiveHandEntity ! = null & & handSlot . HeldEntity = = null )
StartStripInsertHand ( user , target , user . Comp . ActiveHandEntity . Value , handId , targetStrippable ) ;
else if ( user . Comp . ActiveHandEntity = = null & & handSlot . HeldEntity ! = null )
StartStripRemoveHand ( user , target , handSlot . HeldEntity . Value , handId , targetStrippable ) ;
2022-11-06 17:33:17 +01:00
}
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
private void OnStripEnsnareMessage ( EntityUid uid , EnsnareableComponent component , StrippingEnsnareButtonPressed args )
2023-02-10 21:06:09 -05:00
{
2024-03-14 22:57:52 -04:00
if ( args . Session . AttachedEntity is not { Valid : true } user )
2023-02-10 21:06:09 -05:00
return ;
2024-03-14 22:57:52 -04:00
foreach ( var entity in component . Container . ContainedEntities )
{
if ( ! TryComp < EnsnaringComponent > ( entity , out var ensnaring ) )
continue ;
2023-02-10 21:06:09 -05:00
2024-03-14 22:57:52 -04:00
_ensnaringSystem . TryFree ( uid , user , entity , ensnaring ) ;
return ;
}
2023-02-10 21:06:09 -05:00
}
2022-05-13 14:59:57 +10:00
/// <summary>
2024-03-14 22:57:52 -04:00
/// Checks whether the item is in a user's active hand and whether it can be inserted into the inventory slot.
2022-05-13 14:59:57 +10:00
/// </summary>
2024-03-14 22:57:52 -04:00
private bool CanStripInsertInventory (
Entity < HandsComponent ? > user ,
2023-04-03 13:13:48 +12:00
EntityUid target ,
EntityUid held ,
2024-03-14 22:57:52 -04:00
string slot )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( ! Resolve ( user , ref user . Comp ) )
return false ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( user . Comp . ActiveHand = = null )
return false ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( user . Comp . ActiveHandEntity = = null )
return false ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( user . Comp . ActiveHandEntity ! = held )
return false ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( ! _handsSystem . CanDropHeld ( user , user . Comp . ActiveHand ) )
{
_popupSystem . PopupCursor ( Loc . GetString ( "strippable-component-cannot-drop" ) , user ) ;
return false ;
}
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( _inventorySystem . TryGetSlotEntity ( target , slot , out _ ) )
{
_popupSystem . PopupCursor ( Loc . GetString ( "strippable-component-item-slot-occupied" , ( "owner" , target ) ) , user ) ;
return false ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
if ( ! _inventorySystem . CanEquip ( user , target , held , slot , out _ ) )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
_popupSystem . PopupCursor ( Loc . GetString ( "strippable-component-cannot-equip-message" , ( "owner" , target ) ) , user ) ;
return false ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
return true ;
}
/// <summary>
/// Begins a DoAfter to insert the item in the user's active hand into the inventory slot.
/// </summary>
private void StartStripInsertInventory (
Entity < HandsComponent ? > user ,
EntityUid target ,
EntityUid held ,
string slot )
{
if ( ! Resolve ( user , ref user . Comp ) )
return ;
if ( ! CanStripInsertInventory ( user , target , held , slot ) )
return ;
2023-04-03 13:13:48 +12:00
if ( ! _inventorySystem . TryGetSlot ( target , slot , out var slotDef ) )
2022-06-19 20:55:59 -04:00
{
2024-03-10 01:15:13 +01:00
Log . Error ( $"{ToPrettyString(user)} attempted to place an item in a non-existent inventory slot ({slot}) on {ToPrettyString(target)}" ) ;
2022-06-19 20:55:59 -04:00
return ;
}
2024-03-14 22:57:52 -04:00
var ( time , stealth ) = GetStripTimeModifiers ( user , target , slotDef . StripTime ) ;
if ( ! stealth )
_popupSystem . PopupEntity ( Loc . GetString ( "strippable-component-alert-owner-insert" , ( "user" , Identity . Entity ( user , EntityManager ) ) , ( "item" , user . Comp . ActiveHandEntity ! . Value ) ) , target , target , PopupType . Large ) ;
var prefix = stealth ? "stealthily " : "" ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Low , $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot" ) ;
2022-07-30 23:02:27 -07:00
2024-03-14 22:57:52 -04:00
var doAfterArgs = new DoAfterArgs ( EntityManager , user , time , new StrippableDoAfterEvent ( true , true , slot ) , user , target , held )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
Hidden = stealth ,
2023-04-03 13:13:48 +12:00
AttemptFrequency = AttemptFrequency . EveryTick ,
2022-05-13 14:59:57 +10:00
BreakOnDamage = true ,
2024-03-19 12:09:00 +02:00
BreakOnMove = true ,
2022-05-13 14:59:57 +10:00
NeedHand = true ,
2024-03-14 22:57:52 -04:00
DuplicateCondition = DuplicateConditions . SameTool
2022-05-13 14:59:57 +10:00
} ;
2024-03-14 22:57:52 -04:00
_doAfterSystem . TryStartDoAfter ( doAfterArgs ) ;
}
2022-06-22 19:58:53 -04:00
2024-03-14 22:57:52 -04:00
/// <summary>
/// Inserts the item in the user's active hand into the inventory slot.
/// </summary>
private void StripInsertInventory (
Entity < HandsComponent ? > user ,
EntityUid target ,
EntityUid held ,
string slot )
{
if ( ! Resolve ( user , ref user . Comp ) )
return ;
2023-06-16 05:58:17 -05:00
2024-03-14 22:57:52 -04:00
if ( ! CanStripInsertInventory ( user , target , held , slot ) )
2023-10-19 12:34:31 -07:00
return ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( ! _handsSystem . TryDrop ( user , handsComp : user . Comp ) )
return ;
2023-04-03 13:13:48 +12:00
2024-03-14 22:57:52 -04:00
_inventorySystem . TryEquip ( user , target , held , slot ) ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Medium , $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot" ) ;
}
2023-04-03 13:13:48 +12:00
2024-03-14 22:57:52 -04:00
/// <summary>
/// Checks whether the item can be removed from the target's inventory.
/// </summary>
private bool CanStripRemoveInventory (
EntityUid user ,
EntityUid target ,
EntityUid item ,
string slot )
{
if ( ! _inventorySystem . TryGetSlotEntity ( target , slot , out var slotItem ) )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
_popupSystem . PopupCursor ( Loc . GetString ( "strippable-component-item-slot-free-message" , ( "owner" , target ) ) , user ) ;
return false ;
}
2022-10-16 03:32:00 -03:00
2024-03-14 22:57:52 -04:00
if ( slotItem ! = item )
return false ;
2022-10-16 03:32:00 -03:00
2024-03-14 22:57:52 -04:00
if ( ! _inventorySystem . CanUnequip ( user , target , slot , out var reason ) )
{
_popupSystem . PopupCursor ( Loc . GetString ( reason ) , user ) ;
return false ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
return true ;
2022-05-13 14:59:57 +10:00
}
/// <summary>
2024-03-14 22:57:52 -04:00
/// Begins a DoAfter to remove the item from the target's inventory and insert it in the user's active hand.
2022-05-13 14:59:57 +10:00
/// </summary>
2024-03-14 22:57:52 -04:00
private void StartStripRemoveInventory (
2023-04-03 13:13:48 +12:00
EntityUid user ,
EntityUid target ,
2024-03-14 22:57:52 -04:00
EntityUid item ,
string slot )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( ! CanStripRemoveInventory ( user , target , item , slot ) )
return ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( ! _inventorySystem . TryGetSlot ( target , slot , out var slotDef ) )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
Log . Error ( $"{ToPrettyString(user)} attempted to take an item from a non-existent inventory slot ({slot}) on {ToPrettyString(target)}" ) ;
return ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
var ( time , stealth ) = GetStripTimeModifiers ( user , target , slotDef . StripTime ) ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( ! stealth )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( slotDef . StripHidden )
_popupSystem . PopupEntity ( Loc . GetString ( "strippable-component-alert-owner-hidden" , ( "slot" , slot ) ) , target , target , PopupType . Large ) ;
else
_popupSystem . PopupEntity ( Loc . GetString ( "strippable-component-alert-owner" , ( "user" , Identity . Entity ( user , EntityManager ) ) , ( "item" , item ) ) , target , target , PopupType . Large ) ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
var prefix = stealth ? "stealthily " : "" ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Low , $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot" ) ;
2022-11-04 12:40:01 +13:00
2024-03-14 22:57:52 -04:00
var doAfterArgs = new DoAfterArgs ( EntityManager , user , time , new StrippableDoAfterEvent ( false , true , slot ) , user , target , item )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
Hidden = stealth ,
2023-04-03 13:13:48 +12:00
AttemptFrequency = AttemptFrequency . EveryTick ,
2022-05-13 14:59:57 +10:00
BreakOnDamage = true ,
2024-03-19 12:09:00 +02:00
BreakOnMove = true ,
2022-05-13 14:59:57 +10:00
NeedHand = true ,
2024-03-14 22:57:52 -04:00
BreakOnHandChange = false , // Allow simultaneously removing multiple items.
2023-04-03 13:13:48 +12:00
DuplicateCondition = DuplicateConditions . SameTool
2022-05-13 14:59:57 +10:00
} ;
2024-03-14 22:57:52 -04:00
_doAfterSystem . TryStartDoAfter ( doAfterArgs ) ;
2022-05-13 14:59:57 +10:00
}
/// <summary>
2024-03-14 22:57:52 -04:00
/// Removes the item from the target's inventory and inserts it in the user's active hand.
2022-05-13 14:59:57 +10:00
/// </summary>
2024-03-14 22:57:52 -04:00
private void StripRemoveInventory (
2023-04-03 13:13:48 +12:00
EntityUid user ,
EntityUid target ,
EntityUid item ,
string slot ,
2024-03-14 22:57:52 -04:00
bool stealth )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( ! CanStripRemoveInventory ( user , target , item , slot ) )
return ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( ! _inventorySystem . TryUnequip ( user , target , slot ) )
return ;
RaiseLocalEvent ( item , new DroppedEvent ( user ) , true ) ; // Gas tank internals etc.
_handsSystem . PickupOrDrop ( user , item , animateUser : stealth , animate : stealth ) ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Medium , $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot" ) ;
}
/// <summary>
/// Checks whether the item in the user's active hand can be inserted into one of the target's hands.
/// </summary>
private bool CanStripInsertHand (
Entity < HandsComponent ? > user ,
Entity < HandsComponent ? > target ,
EntityUid held ,
string handName )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( ! Resolve ( user , ref user . Comp ) | |
! Resolve ( target , ref target . Comp ) )
return false ;
if ( user . Comp . ActiveHand = = null )
return false ;
if ( user . Comp . ActiveHandEntity = = null )
return false ;
if ( user . Comp . ActiveHandEntity ! = held )
return false ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( ! _handsSystem . CanDropHeld ( user , user . Comp . ActiveHand ) )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
_popupSystem . PopupCursor ( Loc . GetString ( "strippable-component-cannot-drop" ) , user ) ;
return false ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
if ( ! _handsSystem . TryGetHand ( target , handName , out var handSlot , target . Comp ) | |
! _handsSystem . CanPickupToHand ( target , user . Comp . ActiveHandEntity . Value , handSlot , checkActionBlocker : false , target . Comp ) )
2022-06-19 20:55:59 -04:00
{
2024-03-14 22:57:52 -04:00
_popupSystem . PopupCursor ( Loc . GetString ( "strippable-component-cannot-put-message" , ( "owner" , target ) ) , user ) ;
return false ;
2022-06-19 20:55:59 -04:00
}
2024-03-14 22:57:52 -04:00
return true ;
}
2022-06-27 20:14:51 -04:00
2024-03-14 22:57:52 -04:00
/// <summary>
/// Begins a DoAfter to insert the item in the user's active hand into one of the target's hands.
/// </summary>
private void StartStripInsertHand (
Entity < HandsComponent ? > user ,
Entity < HandsComponent ? > target ,
EntityUid held ,
string handName ,
StrippableComponent ? targetStrippable = null )
{
if ( ! Resolve ( user , ref user . Comp ) | |
! Resolve ( target , ref target . Comp ) | |
! Resolve ( target , ref targetStrippable ) )
return ;
if ( ! CanStripInsertHand ( user , target , held , handName ) )
return ;
2022-06-27 20:14:51 -04:00
2024-03-14 22:57:52 -04:00
var ( time , stealth ) = GetStripTimeModifiers ( user , target , targetStrippable . HandStripDelay ) ;
var prefix = stealth ? "stealthily " : "" ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Low , $"{ToPrettyString(user):actor} is trying to {prefix}place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands" ) ;
var doAfterArgs = new DoAfterArgs ( EntityManager , user , time , new StrippableDoAfterEvent ( true , false , handName ) , user , target , held )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
Hidden = stealth ,
2023-04-03 13:13:48 +12:00
AttemptFrequency = AttemptFrequency . EveryTick ,
2022-05-13 14:59:57 +10:00
BreakOnDamage = true ,
2024-03-19 12:09:00 +02:00
BreakOnMove = true ,
2023-04-03 13:13:48 +12:00
NeedHand = true ,
DuplicateCondition = DuplicateConditions . SameTool
2022-05-13 14:59:57 +10:00
} ;
2024-03-14 22:57:52 -04:00
_doAfterSystem . TryStartDoAfter ( doAfterArgs ) ;
}
2023-06-16 05:58:17 -05:00
2024-03-14 22:57:52 -04:00
/// <summary>
/// Places the item in the user's active hand into one of the target's hands.
/// </summary>
private void StripInsertHand (
Entity < HandsComponent ? > user ,
Entity < HandsComponent ? > target ,
EntityUid held ,
string handName ,
bool stealth )
{
if ( ! Resolve ( user , ref user . Comp ) | |
! Resolve ( target , ref target . Comp ) )
2023-10-19 12:34:31 -07:00
return ;
2022-05-13 14:59:57 +10:00
2024-03-15 23:50:53 -04:00
if ( ! CanStripInsertHand ( user , target , held , handName ) )
2023-04-03 13:13:48 +12:00
return ;
2024-03-14 22:57:52 -04:00
_handsSystem . TryDrop ( user , checkActionBlocker : false , handsComp : user . Comp ) ;
_handsSystem . TryPickup ( target , held , handName , checkActionBlocker : false , animateUser : stealth , animate : stealth , handsComp : target . Comp ) ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Medium , $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands" ) ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
// Hand update will trigger strippable update.
2022-05-13 14:59:57 +10:00
}
/// <summary>
2024-03-14 22:57:52 -04:00
/// Checks whether the item is in the target's hand and whether it can be dropped.
2022-05-13 14:59:57 +10:00
/// </summary>
2024-03-14 22:57:52 -04:00
private bool CanStripRemoveHand (
EntityUid user ,
Entity < HandsComponent ? > target ,
EntityUid item ,
string handName )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( ! Resolve ( target , ref target . Comp ) )
return false ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( ! _handsSystem . TryGetHand ( target , handName , out var handSlot , target . Comp ) )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
_popupSystem . PopupCursor ( Loc . GetString ( "strippable-component-item-slot-free-message" , ( "owner" , target ) ) , user ) ;
return false ;
2022-06-22 19:58:53 -04:00
}
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( HasComp < VirtualItemComponent > ( handSlot . HeldEntity ) )
return false ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( handSlot . HeldEntity = = null )
return false ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( handSlot . HeldEntity ! = item )
return false ;
2023-04-03 13:13:48 +12:00
2024-03-14 22:57:52 -04:00
if ( ! _handsSystem . CanDropHeld ( target , handSlot , false ) )
{
_popupSystem . PopupCursor ( Loc . GetString ( "strippable-component-cannot-drop-message" , ( "owner" , target ) ) , user ) ;
return false ;
2022-05-13 14:59:57 +10:00
}
2024-03-14 22:57:52 -04:00
return true ;
2022-05-13 14:59:57 +10:00
}
/// <summary>
2024-03-14 22:57:52 -04:00
/// Begins a DoAfter to remove the item from the target's hand and insert it in the user's active hand.
2022-05-13 14:59:57 +10:00
/// </summary>
2024-03-14 22:57:52 -04:00
private void StartStripRemoveHand (
Entity < HandsComponent ? > user ,
Entity < HandsComponent ? > target ,
EntityUid item ,
string handName ,
StrippableComponent ? targetStrippable = null )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
if ( ! Resolve ( user , ref user . Comp ) | |
! Resolve ( target , ref target . Comp ) | |
! Resolve ( target , ref targetStrippable ) )
return ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
if ( ! CanStripRemoveHand ( user , target , item , handName ) )
return ;
2022-10-16 18:26:28 +13:00
2024-03-14 22:57:52 -04:00
var ( time , stealth ) = GetStripTimeModifiers ( user , target , targetStrippable . HandStripDelay ) ;
2022-10-16 18:26:28 +13:00
2024-03-14 22:57:52 -04:00
if ( ! stealth )
2024-03-15 23:50:53 -04:00
_popupSystem . PopupEntity ( Loc . GetString ( "strippable-component-alert-owner" , ( "user" , Identity . Entity ( user , EntityManager ) ) , ( "item" , item ) ) , target , target ) ;
2024-03-14 22:57:52 -04:00
var prefix = stealth ? "stealthily " : "" ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Low , $"{ToPrettyString(user):actor} is trying to {prefix}strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands" ) ;
var doAfterArgs = new DoAfterArgs ( EntityManager , user , time , new StrippableDoAfterEvent ( false , false , handName ) , user , target , item )
2022-05-13 14:59:57 +10:00
{
2024-03-14 22:57:52 -04:00
Hidden = stealth ,
2023-04-03 13:13:48 +12:00
AttemptFrequency = AttemptFrequency . EveryTick ,
2022-05-13 14:59:57 +10:00
BreakOnDamage = true ,
2024-03-19 12:09:00 +02:00
BreakOnMove = true ,
2023-04-03 13:13:48 +12:00
NeedHand = true ,
2024-03-14 22:57:52 -04:00
BreakOnHandChange = false , // Allow simultaneously removing multiple items.
2023-04-03 13:13:48 +12:00
DuplicateCondition = DuplicateConditions . SameTool
2022-05-13 14:59:57 +10:00
} ;
2024-03-14 22:57:52 -04:00
_doAfterSystem . TryStartDoAfter ( doAfterArgs ) ;
}
/// <summary>
/// Takes the item from the target's hand and inserts it in the user's active hand.
/// </summary>
private void StripRemoveHand (
Entity < HandsComponent ? > user ,
Entity < HandsComponent ? > target ,
EntityUid item ,
2024-03-15 23:50:53 -04:00
string handName ,
2024-03-14 22:57:52 -04:00
bool stealth )
{
if ( ! Resolve ( user , ref user . Comp ) | |
! Resolve ( target , ref target . Comp ) )
return ;
2024-03-15 23:50:53 -04:00
if ( ! CanStripRemoveHand ( user , target , item , handName ) )
return ;
2024-03-14 22:57:52 -04:00
_handsSystem . TryDrop ( target , item , checkActionBlocker : false , handsComp : target . Comp ) ;
_handsSystem . PickupOrDrop ( user , item , animateUser : stealth , animate : stealth , handsComp : user . Comp ) ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Medium , $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands" ) ;
// Hand update will trigger strippable update.
}
private void OnStrippableDoAfterRunning ( Entity < HandsComponent > entity , ref DoAfterAttemptEvent < StrippableDoAfterEvent > ev )
{
var args = ev . DoAfter . Args ;
DebugTools . Assert ( entity . Owner = = args . User ) ;
DebugTools . Assert ( args . Target ! = null ) ;
DebugTools . Assert ( args . Used ! = null ) ;
DebugTools . Assert ( ev . Event . SlotOrHandName ! = null ) ;
if ( ev . Event . InventoryOrHand )
2022-06-22 19:58:53 -04:00
{
2024-03-14 22:57:52 -04:00
if ( ev . Event . InsertOrRemove & & ! CanStripInsertInventory ( ( entity . Owner , entity . Comp ) , args . Target . Value , args . Used . Value , ev . Event . SlotOrHandName ) | |
! ev . Event . InsertOrRemove & & ! CanStripRemoveInventory ( entity . Owner , args . Target . Value , args . Used . Value , ev . Event . SlotOrHandName ) )
2024-03-26 15:52:23 +07:00
{
ev . Cancel ( ) ;
}
2022-06-22 19:58:53 -04:00
}
2024-03-14 22:57:52 -04:00
else
{
if ( ev . Event . InsertOrRemove & & ! CanStripInsertHand ( ( entity . Owner , entity . Comp ) , args . Target . Value , args . Used . Value , ev . Event . SlotOrHandName ) | |
! ev . Event . InsertOrRemove & & ! CanStripRemoveHand ( entity . Owner , args . Target . Value , args . Used . Value , ev . Event . SlotOrHandName ) )
2024-03-26 15:52:23 +07:00
{
ev . Cancel ( ) ;
}
2024-03-14 22:57:52 -04:00
}
}
2022-06-22 19:58:53 -04:00
2024-03-14 22:57:52 -04:00
private void OnStrippableDoAfterFinished ( Entity < HandsComponent > entity , ref StrippableDoAfterEvent ev )
{
if ( ev . Cancelled )
2023-10-19 12:34:31 -07:00
return ;
2022-05-13 14:59:57 +10:00
2024-03-14 22:57:52 -04:00
DebugTools . Assert ( entity . Owner = = ev . User ) ;
DebugTools . Assert ( ev . Target ! = null ) ;
DebugTools . Assert ( ev . Used ! = null ) ;
DebugTools . Assert ( ev . SlotOrHandName ! = null ) ;
if ( ev . InventoryOrHand )
{
if ( ev . InsertOrRemove )
StripInsertInventory ( ( entity . Owner , entity . Comp ) , ev . Target . Value , ev . Used . Value , ev . SlotOrHandName ) ;
else StripRemoveInventory ( entity . Owner , ev . Target . Value , ev . Used . Value , ev . SlotOrHandName , ev . Args . Hidden ) ;
}
else
{
if ( ev . InsertOrRemove )
StripInsertHand ( ( entity . Owner , entity . Comp ) , ev . Target . Value , ev . Used . Value , ev . SlotOrHandName , ev . Args . Hidden ) ;
2024-03-15 23:50:53 -04:00
else StripRemoveHand ( ( entity . Owner , entity . Comp ) , ev . Target . Value , ev . Used . Value , ev . SlotOrHandName , ev . Args . Hidden ) ;
2024-03-14 22:57:52 -04:00
}
2022-05-13 14:59:57 +10:00
}
2021-10-05 14:29:03 +11:00
}
}