2023-03-13 19:34:26 -04:00
using System.Linq ;
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 ;
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 ;
using Robust.Server.GameObjects ;
2023-02-26 18:48:57 +11:00
using Robust.Shared.Utility ;
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
{
2023-03-13 19:34:26 -04:00
[Dependency] private readonly SharedCuffableSystem _cuffable = default ! ;
2022-05-13 14:59:57 +10:00
[Dependency] private readonly SharedHandsSystem _handsSystem = default ! ;
2021-12-30 22:56:10 +01:00
[Dependency] private readonly InventorySystem _inventorySystem = default ! ;
2023-04-03 13:13:48 +12:00
[Dependency] private readonly SharedDoAfterSystem _doAfter = default ! ;
[Dependency] private readonly SharedPopupSystem _popup = default ! ;
2022-08-24 10:50:31 -04:00
[Dependency] private readonly EnsnareableSystem _ensnaring = default ! ;
2022-09-05 22:15:49 -04:00
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = 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 ) ;
2022-05-13 14:59:57 +10:00
}
2022-10-16 06:00:04 +13:00
private void OnStripEnsnareMessage ( EntityUid uid , EnsnareableComponent component , StrippingEnsnareButtonPressed args )
2022-08-24 10:50:31 -04:00
{
if ( args . Session . AttachedEntity is not { Valid : true } user )
return ;
2022-10-16 06:00:04 +13:00
foreach ( var entity in component . Container . ContainedEntities )
2022-08-24 10:50:31 -04:00
{
if ( ! TryComp < EnsnaringComponent > ( entity , out var ensnaring ) )
continue ;
2023-04-03 13:13:48 +12:00
_ensnaring . TryFree ( uid , user , entity , ensnaring ) ;
2022-08-24 10:50:31 -04:00
return ;
}
}
2023-04-03 13:13:48 +12:00
private void OnStripButtonPressed ( EntityUid target , StrippableComponent component , StrippingSlotButtonPressed args )
2022-05-13 14:59:57 +10:00
{
if ( args . Session . AttachedEntity is not { Valid : true } user | |
! TryComp < HandsComponent > ( user , out var userHands ) )
return ;
2022-10-16 06:00:04 +13:00
if ( args . IsHand )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
StripHand ( target , user , args . Slot , component , userHands ) ;
2022-10-16 06:00:04 +13:00
return ;
2022-05-13 14:59:57 +10:00
}
2022-10-16 06:00:04 +13:00
2023-04-03 13:13:48 +12:00
if ( ! TryComp < InventoryComponent > ( target , out var inventory ) )
2022-10-16 06:00:04 +13:00
return ;
2023-04-03 13:13:48 +12:00
var hasEnt = _inventorySystem . TryGetSlotEntity ( target , args . Slot , out var held , inventory ) ;
2022-10-16 06:00:04 +13:00
if ( userHands . ActiveHandEntity ! = null & & ! hasEnt )
2023-04-03 13:13:48 +12:00
PlaceActiveHandItemInInventory ( user , target , userHands . ActiveHandEntity . Value , args . Slot , component ) ;
2022-10-16 06:00:04 +13:00
else if ( userHands . ActiveHandEntity = = null & & hasEnt )
2023-04-03 13:13:48 +12:00
TakeItemFromInventory ( user , target , held ! . Value , args . Slot , component ) ;
2022-05-13 14:59:57 +10:00
}
2022-10-16 06:00:04 +13:00
private void StripHand ( EntityUid target , EntityUid user , string handId , StrippableComponent component , HandsComponent userHands )
2022-05-13 14:59:57 +10:00
{
2023-04-07 11:21:12 -07:00
if ( ! _handsSystem . TryGetHand ( target , handId , out var hand ) )
2022-05-13 14:59:57 +10:00
return ;
2022-10-16 06:00:04 +13:00
// is the target a handcuff?
if ( TryComp ( hand . HeldEntity , out HandVirtualItemComponent ? virt )
& & TryComp ( target , out CuffableComponent ? cuff )
2023-03-13 19:34:26 -04:00
& & _cuffable . GetAllCuffs ( cuff ) . Contains ( virt . BlockingEntity ) )
2022-05-13 14:59:57 +10:00
{
2023-03-13 19:34:26 -04:00
_cuffable . TryUncuff ( target , user , virt . BlockingEntity , cuffable : cuff ) ;
2022-10-16 06:00:04 +13:00
return ;
2022-05-13 14:59:57 +10:00
}
2022-10-16 06:00:04 +13:00
2023-04-03 13:13:48 +12:00
if ( userHands . ActiveHandEntity ! = null & & hand . HeldEntity = = null )
PlaceActiveHandItemInHands ( user , target , userHands . ActiveHandEntity . Value , handId , component ) ;
else if ( userHands . ActiveHandEntity = = null & & hand . HeldEntity ! = null )
TakeItemFromHands ( user , target , hand . HeldEntity . Value , handId , component ) ;
2022-05-13 14:59:57 +10:00
}
2023-02-14 00:29:34 +11:00
public override void StartOpeningStripper ( EntityUid user , StrippableComponent component , bool openInCombat = false )
2022-05-13 14:59:57 +10:00
{
2023-02-14 00:29:34 +11:00
base . StartOpeningStripper ( user , component , openInCombat ) ;
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 ) )
{
2022-09-05 22:15:49 -04:00
if ( _userInterfaceSystem . SessionHasOpenUi ( component . Owner , StrippingUiKey . Key , actor . PlayerSession ) )
2022-05-13 14:59:57 +10:00
return ;
2022-09-05 22:15:49 -04:00
_userInterfaceSystem . TryOpen ( component . Owner , StrippingUiKey . Key , actor . PlayerSession ) ;
2022-05-13 14:59:57 +10:00
}
2021-12-30 22:56:10 +01:00
}
2022-02-10 15:30:59 +13:00
private void AddStripVerb ( EntityUid uid , StrippableComponent component , GetVerbsEvent < Verb > args )
2021-10-05 14:29:03 +11:00
{
if ( args . Hands = = null | | ! args . CanAccess | | ! args . CanInteract | | args . Target = = args . User )
return ;
2021-12-08 13:00:43 +01:00
if ( ! EntityManager . TryGetComponent ( args . User , out ActorComponent ? actor ) )
2021-10-05 14:29:03 +11:00
return ;
2022-05-13 14:59:57 +10:00
Verb verb = new ( )
{
Text = Loc . GetString ( "strip-verb-get-data-text" ) ,
2023-04-20 20:16:01 +10:00
Icon = new SpriteSpecifier . Texture ( new ( "/Textures/Interface/VerbIcons/outfit.svg.192dpi.png" ) ) ,
2022-09-05 22:15:49 -04:00
Act = ( ) = > StartOpeningStripper ( args . User , component , true ) ,
2022-05-13 14:59:57 +10:00
} ;
2021-10-05 14:29:03 +11:00
args . Verbs . Add ( verb ) ;
}
2022-11-06 17:33:17 +01:00
private void AddStripExamineVerb ( EntityUid uid , StrippableComponent component , GetVerbsEvent < ExamineVerb > args )
{
if ( args . Hands = = null | | ! args . CanAccess | | ! args . CanInteract | | args . Target = = args . User )
return ;
if ( ! HasComp < ActorComponent > ( args . User ) )
return ;
ExamineVerb verb = new ( )
{
Text = Loc . GetString ( "strip-verb-get-data-text" ) ,
2023-04-20 20:16:01 +10:00
Icon = new SpriteSpecifier . Texture ( new ( "/Textures/Interface/VerbIcons/outfit.svg.192dpi.png" ) ) ,
2022-11-06 17:33:17 +01:00
Act = ( ) = > StartOpeningStripper ( args . User , component , true ) ,
Category = VerbCategory . Examine ,
} ;
args . Verbs . Add ( verb ) ;
}
2022-05-13 14:59:57 +10:00
2023-02-10 21:06:09 -05:00
private void OnActivateInWorld ( EntityUid uid , StrippableComponent component , ActivateInWorldEvent args )
{
if ( args . Target = = args . User )
return ;
2023-04-03 13:13:48 +12:00
if ( ! TryComp < ActorComponent > ( args . User , out var actor ) )
2023-02-10 21:06:09 -05:00
return ;
StartOpeningStripper ( args . User , component ) ;
}
2022-05-13 14:59:57 +10:00
/// <summary>
/// Places item in user's active hand to an inventory slot.
/// </summary>
2023-04-03 13:13:48 +12:00
private async void PlaceActiveHandItemInInventory (
EntityUid user ,
EntityUid target ,
EntityUid held ,
string slot ,
StrippableComponent component )
2022-05-13 14:59:57 +10:00
{
var userHands = Comp < HandsComponent > ( user ) ;
bool Check ( )
{
2023-04-03 13:13:48 +12:00
if ( userHands . ActiveHandEntity ! = held )
2022-05-13 14:59:57 +10:00
return false ;
2023-04-03 13:13:48 +12:00
if ( ! _handsSystem . CanDropHeld ( user , userHands . ActiveHand ! ) )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupCursor ( Loc . GetString ( "strippable-component-cannot-drop" ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
2023-04-03 13:13:48 +12:00
if ( _inventorySystem . TryGetSlotEntity ( target , slot , out _ ) )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupCursor ( Loc . GetString ( "strippable-component-item-slot-occupied" , ( "owner" , target ) ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
2023-04-03 13:13:48 +12:00
if ( ! _inventorySystem . CanEquip ( user , target , held , slot , out _ ) )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupCursor ( Loc . GetString ( "strippable-component-cannot-equip-message" , ( "owner" , target ) ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
return true ;
}
2023-04-03 13:13:48 +12:00
if ( ! _inventorySystem . TryGetSlot ( target , slot , out var slotDef ) )
2022-06-19 20:55:59 -04:00
{
2023-04-03 13:13:48 +12:00
Logger . 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 ;
}
2023-04-03 13:13:48 +12:00
var userEv = new BeforeStripEvent ( slotDef . StripTime ) ;
RaiseLocalEvent ( user , userEv ) ;
var ev = new BeforeGettingStrippedEvent ( userEv . Time , userEv . Stealth ) ;
RaiseLocalEvent ( target , ev ) ;
2022-07-30 23:02:27 -07:00
2023-09-11 09:42:41 +10:00
var doAfterArgs = new DoAfterArgs ( EntityManager , user , ev . Time , new AwaitedDoAfterEvent ( ) , null , target : target , used : held )
2022-05-13 14:59:57 +10:00
{
ExtraCheck = Check ,
2023-04-03 13:13:48 +12:00
AttemptFrequency = AttemptFrequency . EveryTick ,
2022-05-13 14:59:57 +10:00
BreakOnDamage = true ,
BreakOnTargetMove = true ,
BreakOnUserMove = true ,
NeedHand = true ,
2023-04-03 13:13:48 +12:00
DuplicateCondition = DuplicateConditions . SameTool // Block any other DoAfters featuring this same entity.
2022-05-13 14:59:57 +10:00
} ;
2023-04-03 13:13:48 +12:00
if ( ! ev . Stealth & & Check ( ) & & userHands . ActiveHandEntity ! = null )
2022-06-22 19:58:53 -04:00
{
2022-07-30 23:02:27 -07:00
var message = Loc . GetString ( "strippable-component-alert-owner-insert" ,
( "user" , Identity . Entity ( user , EntityManager ) ) , ( "item" , userHands . ActiveHandEntity ) ) ;
2023-04-03 13:13:48 +12:00
_popup . PopupEntity ( message , target , target , PopupType . Large ) ;
2022-06-22 19:58:53 -04:00
}
2023-06-16 05:58:17 -05:00
_adminLogger . Add ( LogType . Stripping , LogImpact . Low , $"{ToPrettyString(user):user} is trying to place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot" ) ;
2023-04-03 13:13:48 +12:00
var result = await _doAfter . WaitDoAfter ( doAfterArgs ) ;
2022-05-13 14:59:57 +10:00
if ( result ! = DoAfterStatus . Finished ) return ;
2023-04-03 13:13:48 +12:00
DebugTools . Assert ( userHands . ActiveHand ? . HeldEntity = = held ) ;
if ( _handsSystem . TryDrop ( user , handsComp : userHands ) )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
_inventorySystem . TryEquip ( user , target , held , slot ) ;
2022-10-16 03:32:00 -03:00
2023-04-03 13:13:48 +12:00
_adminLogger . Add ( LogType . Stripping , LogImpact . Medium , $"{ToPrettyString(user):user} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s {slot} slot" ) ;
2022-05-13 14:59:57 +10:00
}
}
/// <summary>
/// Places item in user's active hand in one of the entity's hands.
/// </summary>
2023-04-03 13:13:48 +12:00
private async void PlaceActiveHandItemInHands (
EntityUid user ,
EntityUid target ,
EntityUid held ,
string handName ,
StrippableComponent component )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
var hands = Comp < HandsComponent > ( target ) ;
2022-05-13 14:59:57 +10:00
var userHands = Comp < HandsComponent > ( user ) ;
bool Check ( )
{
2023-04-03 13:13:48 +12:00
if ( userHands . ActiveHandEntity ! = held )
2022-05-13 14:59:57 +10:00
return false ;
if ( ! _handsSystem . CanDropHeld ( user , userHands . ActiveHand ! ) )
{
2023-04-03 13:13:48 +12:00
_popup . PopupCursor ( Loc . GetString ( "strippable-component-cannot-drop" ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
2023-04-07 11:21:12 -07:00
if ( ! _handsSystem . TryGetHand ( target , handName , out var hand , hands )
2023-04-03 13:13:48 +12:00
| | ! _handsSystem . CanPickupToHand ( target , userHands . ActiveHandEntity . Value , hand , checkActionBlocker : false , hands ) )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupCursor ( Loc . GetString ( "strippable-component-cannot-put-message" , ( "owner" , target ) ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
return true ;
}
2023-04-03 13:13:48 +12:00
var userEv = new BeforeStripEvent ( component . HandStripDelay ) ;
RaiseLocalEvent ( user , userEv ) ;
var ev = new BeforeGettingStrippedEvent ( userEv . Time , userEv . Stealth ) ;
RaiseLocalEvent ( target , ev ) ;
2022-11-04 12:40:01 +13:00
2023-09-11 09:42:41 +10:00
var doAfterArgs = new DoAfterArgs ( EntityManager , user , ev . Time , new AwaitedDoAfterEvent ( ) , null , target : target , used : held )
2022-05-13 14:59:57 +10:00
{
ExtraCheck = Check ,
2023-04-03 13:13:48 +12:00
AttemptFrequency = AttemptFrequency . EveryTick ,
2022-05-13 14:59:57 +10:00
BreakOnDamage = true ,
BreakOnTargetMove = true ,
BreakOnUserMove = true ,
NeedHand = true ,
2023-04-03 13:13:48 +12:00
DuplicateCondition = DuplicateConditions . SameTool
2022-05-13 14:59:57 +10:00
} ;
2023-06-16 05:58:17 -05:00
_adminLogger . Add ( LogType . Stripping , LogImpact . Low , $"{ToPrettyString(user):user} is trying to place the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands" ) ;
2023-04-03 13:13:48 +12:00
var result = await _doAfter . WaitDoAfter ( doAfterArgs ) ;
2022-05-13 14:59:57 +10:00
if ( result ! = DoAfterStatus . Finished ) return ;
_handsSystem . TryDrop ( user , checkActionBlocker : false , handsComp : userHands ) ;
2023-04-03 13:13:48 +12:00
_handsSystem . TryPickup ( target , held , handName , checkActionBlocker : false , animateUser : true , handsComp : hands ) ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Medium , $"{ToPrettyString(user):user} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands" ) ;
2022-05-13 14:59:57 +10:00
// hand update will trigger strippable update
}
/// <summary>
/// Takes an item from the inventory and places it in the user's active hand.
/// </summary>
2023-04-03 13:13:48 +12:00
private async void TakeItemFromInventory (
EntityUid user ,
EntityUid target ,
EntityUid item ,
string slot ,
StrippableComponent component )
2022-05-13 14:59:57 +10:00
{
bool Check ( )
{
2023-04-03 13:13:48 +12:00
if ( ! _inventorySystem . TryGetSlotEntity ( target , slot , out var ent ) & & ent = = item )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupCursor ( Loc . GetString ( "strippable-component-item-slot-free-message" , ( "owner" , target ) ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
2023-04-03 13:13:48 +12:00
if ( ! _inventorySystem . CanUnequip ( user , target , slot , out var reason ) )
2022-05-13 14:59:57 +10:00
{
2023-08-12 17:39:58 -04:00
_popup . PopupCursor ( Loc . GetString ( reason ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
return true ;
}
2023-04-03 13:13:48 +12:00
if ( ! _inventorySystem . TryGetSlot ( target , slot , out var slotDef ) )
2022-06-19 20:55:59 -04:00
{
2023-04-03 13:13:48 +12:00
Logger . Error ( $"{ToPrettyString(user)} attempted to take an item from a non-existent inventory slot ({slot}) on {ToPrettyString(target)}" ) ;
2022-06-19 20:55:59 -04:00
return ;
}
2023-04-03 13:13:48 +12:00
var userEv = new BeforeStripEvent ( slotDef . StripTime ) ;
RaiseLocalEvent ( user , userEv ) ;
var ev = new BeforeGettingStrippedEvent ( userEv . Time , userEv . Stealth ) ;
RaiseLocalEvent ( target , ev ) ;
2022-06-27 20:14:51 -04:00
2023-09-11 09:42:41 +10:00
var doAfterArgs = new DoAfterArgs ( EntityManager , user , ev . Time , new AwaitedDoAfterEvent ( ) , null , target : target , used : item )
2022-05-13 14:59:57 +10:00
{
ExtraCheck = Check ,
2023-04-03 13:13:48 +12:00
AttemptFrequency = AttemptFrequency . EveryTick ,
2022-05-13 14:59:57 +10:00
BreakOnDamage = true ,
BreakOnTargetMove = true ,
BreakOnUserMove = true ,
2023-04-03 13:13:48 +12:00
NeedHand = true ,
BreakOnHandChange = false , // allow simultaneously removing multiple items.
DuplicateCondition = DuplicateConditions . SameTool
2022-05-13 14:59:57 +10:00
} ;
2023-04-03 13:13:48 +12:00
if ( ! ev . Stealth & & Check ( ) )
2022-06-22 19:58:53 -04:00
{
2022-07-30 23:02:27 -07:00
if ( slotDef . StripHidden )
{
2023-04-03 13:13:48 +12:00
_popup . PopupEntity ( Loc . GetString ( "strippable-component-alert-owner-hidden" , ( "slot" , slot ) ) , target ,
target , PopupType . Large ) ;
2022-07-30 23:02:27 -07:00
}
else if ( _inventorySystem . TryGetSlotEntity ( component . Owner , slot , out var slotItem ) )
2022-06-22 19:58:53 -04:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupEntity ( Loc . GetString ( "strippable-component-alert-owner" , ( "user" , Identity . Entity ( user , EntityManager ) ) , ( "item" , slotItem ) ) , target ,
target , PopupType . Large ) ;
2022-06-22 19:58:53 -04:00
}
}
2023-06-16 05:58:17 -05:00
_adminLogger . Add ( LogType . Stripping , LogImpact . Low , $"{ToPrettyString(user):user} is trying to strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}" ) ;
2023-04-03 13:13:48 +12:00
var result = await _doAfter . WaitDoAfter ( doAfterArgs ) ;
2022-05-13 14:59:57 +10:00
if ( result ! = DoAfterStatus . Finished ) return ;
2023-04-03 13:13:48 +12:00
if ( ! _inventorySystem . TryUnequip ( user , component . Owner , slot ) )
return ;
// Raise a dropped event, so that things like gas tank internals properly deactivate when stripping
RaiseLocalEvent ( item , new DroppedEvent ( user ) , true ) ;
_handsSystem . PickupOrDrop ( user , item ) ;
_adminLogger . Add ( LogType . Stripping , LogImpact . Medium , $"{ToPrettyString(user):user} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}" ) ;
2022-05-13 14:59:57 +10:00
}
/// <summary>
/// Takes an item from a hand and places it in the user's active hand.
/// </summary>
2023-04-03 13:13:48 +12:00
private async void TakeItemFromHands ( EntityUid user , EntityUid target , EntityUid item , string handName , StrippableComponent component )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
var hands = Comp < HandsComponent > ( target ) ;
2022-05-13 14:59:57 +10:00
var userHands = Comp < HandsComponent > ( user ) ;
bool Check ( )
{
2023-04-07 11:21:12 -07:00
if ( ! _handsSystem . TryGetHand ( target , handName , out var hand , hands ) | | hand . HeldEntity ! = item )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupCursor ( Loc . GetString ( "strippable-component-item-slot-free-message" , ( "owner" , target ) ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
if ( HasComp < HandVirtualItemComponent > ( hand . HeldEntity ) )
return false ;
2023-04-03 13:13:48 +12:00
if ( ! _handsSystem . CanDropHeld ( target , hand , false ) )
2022-05-13 14:59:57 +10:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupCursor ( Loc . GetString ( "strippable-component-cannot-drop-message" , ( "owner" , target ) ) , user ) ;
2022-05-13 14:59:57 +10:00
return false ;
}
return true ;
}
2023-04-03 13:13:48 +12:00
var userEv = new BeforeStripEvent ( component . HandStripDelay ) ;
RaiseLocalEvent ( user , userEv ) ;
var ev = new BeforeGettingStrippedEvent ( userEv . Time , userEv . Stealth ) ;
RaiseLocalEvent ( target , ev ) ;
2022-10-16 18:26:28 +13:00
2023-09-11 09:42:41 +10:00
var doAfterArgs = new DoAfterArgs ( EntityManager , user , ev . Time , new AwaitedDoAfterEvent ( ) , null , target : target , used : item )
2022-05-13 14:59:57 +10:00
{
ExtraCheck = Check ,
2023-04-03 13:13:48 +12:00
AttemptFrequency = AttemptFrequency . EveryTick ,
2022-05-13 14:59:57 +10:00
BreakOnDamage = true ,
BreakOnTargetMove = true ,
BreakOnUserMove = true ,
2023-04-03 13:13:48 +12:00
NeedHand = true ,
BreakOnHandChange = false , // allow simultaneously removing multiple items.
DuplicateCondition = DuplicateConditions . SameTool
2022-05-13 14:59:57 +10:00
} ;
2023-04-07 11:21:12 -07:00
if ( Check ( ) & & _handsSystem . TryGetHand ( target , handName , out var handSlot , hands ) & & handSlot . HeldEntity ! = null )
2022-06-22 19:58:53 -04:00
{
2023-04-03 13:13:48 +12:00
_popup . PopupEntity (
2023-03-06 06:12:08 +13:00
Loc . GetString ( "strippable-component-alert-owner" ,
2023-04-03 13:13:48 +12:00
( "user" , Identity . Entity ( user , EntityManager ) ) , ( "item" , item ) ) ,
component . Owner ,
component . Owner ) ;
2022-06-22 19:58:53 -04:00
}
2023-06-16 05:58:17 -05:00
_adminLogger . Add ( LogType . Stripping , LogImpact . Low ,
$"{ToPrettyString(user):user} is trying to strip the item {ToPrettyString(item):item} from {ToPrettyString(target):target}" ) ;
2023-04-03 13:13:48 +12:00
var result = await _doAfter . WaitDoAfter ( doAfterArgs ) ;
2022-05-13 14:59:57 +10:00
if ( result ! = DoAfterStatus . Finished ) return ;
2023-04-03 13:13:48 +12:00
_handsSystem . TryDrop ( target , item , checkActionBlocker : false , handsComp : hands ) ;
_handsSystem . PickupOrDrop ( user , item , handsComp : userHands ) ;
2022-05-13 14:59:57 +10:00
// hand update will trigger strippable update
2023-04-03 13:13:48 +12:00
_adminLogger . Add ( LogType . Stripping , LogImpact . Medium ,
$"{ToPrettyString(user):user} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}" ) ;
2022-05-13 14:59:57 +10:00
}
2021-10-05 14:29:03 +11:00
}
}