2023-08-04 22:24:20 +00:00
using System.Diagnostics.CodeAnalysis ;
2023-07-08 14:08:32 +10:00
using System.Numerics ;
2023-05-01 03:04:23 -04:00
using Content.Shared.Alert ;
using Content.Shared.Bed.Sleep ;
using Content.Shared.Buckle.Components ;
using Content.Shared.Database ;
using Content.Shared.Hands.Components ;
using Content.Shared.IdentityManagement ;
using Content.Shared.Interaction ;
2022-11-18 22:08:28 +01:00
using Content.Shared.Interaction.Events ;
2023-05-01 03:04:23 -04:00
using Content.Shared.Mobs.Components ;
2022-11-18 22:08:28 +01:00
using Content.Shared.Movement.Events ;
2023-05-01 03:04:23 -04:00
using Content.Shared.Popups ;
2024-02-03 10:32:30 -08:00
using Content.Shared.Pulling.Components ;
2022-11-18 22:08:28 +01:00
using Content.Shared.Standing ;
2023-05-01 03:04:23 -04:00
using Content.Shared.Storage.Components ;
using Content.Shared.Stunnable ;
2022-11-18 22:08:28 +01:00
using Content.Shared.Throwing ;
2023-05-01 03:04:23 -04:00
using Content.Shared.Verbs ;
2023-09-16 07:15:05 +03:00
using Robust.Shared.Physics.Components ;
2022-11-18 22:08:28 +01:00
using Robust.Shared.Physics.Events ;
2023-05-01 03:04:23 -04:00
using Robust.Shared.Utility ;
2022-11-18 22:08:28 +01:00
namespace Content.Shared.Buckle ;
public abstract partial class SharedBuckleSystem
{
private void InitializeBuckle ( )
{
2023-05-01 03:04:23 -04:00
SubscribeLocalEvent < BuckleComponent , ComponentStartup > ( OnBuckleComponentStartup ) ;
SubscribeLocalEvent < BuckleComponent , ComponentShutdown > ( OnBuckleComponentShutdown ) ;
SubscribeLocalEvent < BuckleComponent , MoveEvent > ( OnBuckleMove ) ;
SubscribeLocalEvent < BuckleComponent , InteractHandEvent > ( OnBuckleInteractHand ) ;
SubscribeLocalEvent < BuckleComponent , GetVerbsEvent < InteractionVerb > > ( AddUnbuckleVerb ) ;
SubscribeLocalEvent < BuckleComponent , InsertIntoEntityStorageAttemptEvent > ( OnBuckleInsertIntoEntityStorageAttempt ) ;
SubscribeLocalEvent < BuckleComponent , PreventCollideEvent > ( OnBucklePreventCollide ) ;
SubscribeLocalEvent < BuckleComponent , DownAttemptEvent > ( OnBuckleDownAttempt ) ;
SubscribeLocalEvent < BuckleComponent , StandAttemptEvent > ( OnBuckleStandAttempt ) ;
SubscribeLocalEvent < BuckleComponent , ThrowPushbackAttemptEvent > ( OnBuckleThrowPushbackAttempt ) ;
SubscribeLocalEvent < BuckleComponent , UpdateCanMoveEvent > ( OnBuckleUpdateCanMove ) ;
2022-12-23 23:55:31 -05:00
SubscribeLocalEvent < BuckleComponent , ChangeDirectionAttemptEvent > ( OnBuckleChangeDirectionAttempt ) ;
2022-11-18 22:08:28 +01:00
}
2023-05-01 03:04:23 -04:00
private void OnBuckleComponentStartup ( EntityUid uid , BuckleComponent component , ComponentStartup args )
{
UpdateBuckleStatus ( uid , component ) ;
}
private void OnBuckleComponentShutdown ( EntityUid uid , BuckleComponent component , ComponentShutdown args )
{
TryUnbuckle ( uid , uid , true , component ) ;
component . BuckleTime = default ;
}
private void OnBuckleMove ( EntityUid uid , BuckleComponent component , ref MoveEvent ev )
{
if ( component . BuckledTo is not { } strapUid )
return ;
if ( ! TryComp < StrapComponent > ( strapUid , out var strapComp ) )
return ;
var strapPosition = Transform ( strapUid ) . Coordinates ;
2023-09-16 07:15:05 +03:00
if ( ev . NewPosition . InRange ( EntityManager , _transform , strapPosition , strapComp . MaxBuckleDistance ) )
2023-05-01 03:04:23 -04:00
return ;
TryUnbuckle ( uid , uid , true , component ) ;
}
private void OnBuckleInteractHand ( EntityUid uid , BuckleComponent component , InteractHandEvent args )
{
if ( ! component . Buckled )
return ;
if ( TryUnbuckle ( uid , args . User , buckleComp : component ) )
args . Handled = true ;
}
private void AddUnbuckleVerb ( EntityUid uid , BuckleComponent component , GetVerbsEvent < InteractionVerb > args )
{
if ( ! args . CanAccess | | ! args . CanInteract | | ! component . Buckled )
return ;
InteractionVerb verb = new ( )
{
Act = ( ) = > TryUnbuckle ( uid , args . User , buckleComp : component ) ,
Text = Loc . GetString ( "verb-categories-unbuckle" ) ,
Icon = new SpriteSpecifier . Texture ( new ( "/Textures/Interface/VerbIcons/unbuckle.svg.192dpi.png" ) )
} ;
if ( args . Target = = args . User & & args . Using = = null )
{
// A user is left clicking themselves with an empty hand, while buckled.
// It is very likely they are trying to unbuckle themselves.
verb . Priority = 1 ;
}
args . Verbs . Add ( verb ) ;
}
private void OnBuckleInsertIntoEntityStorageAttempt ( EntityUid uid , BuckleComponent component , ref InsertIntoEntityStorageAttemptEvent args )
{
if ( component . Buckled )
args . Cancelled = true ;
}
private void OnBucklePreventCollide ( EntityUid uid , BuckleComponent component , ref PreventCollideEvent args )
2022-11-18 22:08:28 +01:00
{
2023-06-03 00:20:09 +12:00
if ( args . OtherEntity ! = component . BuckledTo )
2022-11-18 22:08:28 +01:00
return ;
if ( component . Buckled | | component . DontCollide )
args . Cancelled = true ;
}
2023-05-01 03:04:23 -04:00
private void OnBuckleDownAttempt ( EntityUid uid , BuckleComponent component , DownAttemptEvent args )
2022-11-18 22:08:28 +01:00
{
if ( component . Buckled )
args . Cancel ( ) ;
}
2023-05-01 03:04:23 -04:00
private void OnBuckleStandAttempt ( EntityUid uid , BuckleComponent component , StandAttemptEvent args )
2022-11-18 22:08:28 +01:00
{
if ( component . Buckled )
args . Cancel ( ) ;
}
2023-05-01 03:04:23 -04:00
private void OnBuckleThrowPushbackAttempt ( EntityUid uid , BuckleComponent component , ThrowPushbackAttemptEvent args )
2022-11-18 22:08:28 +01:00
{
if ( component . Buckled )
args . Cancel ( ) ;
}
2023-05-01 03:04:23 -04:00
private void OnBuckleUpdateCanMove ( EntityUid uid , BuckleComponent component , UpdateCanMoveEvent args )
2022-11-18 22:08:28 +01:00
{
if ( component . LifeStage > ComponentLifeStage . Running )
return ;
2024-02-01 11:33:10 +11:00
if ( component . Buckled ) // buckle shitcode
2022-11-18 22:08:28 +01:00
args . Cancel ( ) ;
}
2022-12-23 23:55:31 -05:00
private void OnBuckleChangeDirectionAttempt ( EntityUid uid , BuckleComponent component , ChangeDirectionAttemptEvent args )
2022-11-18 22:08:28 +01:00
{
if ( component . Buckled )
args . Cancel ( ) ;
}
2022-12-23 23:55:31 -05:00
public bool IsBuckled ( EntityUid uid , BuckleComponent ? component = null )
2022-11-18 22:08:28 +01:00
{
return Resolve ( uid , ref component , false ) & & component . Buckled ;
}
/// <summary>
2023-05-01 03:04:23 -04:00
/// Shows or hides the buckled status effect depending on if the
/// entity is buckled or not.
2022-11-18 22:08:28 +01:00
/// </summary>
2023-05-01 03:04:23 -04:00
/// <param name="uid"> Entity that we want to show the alert </param>
/// <param name="buckleComp"> buckle component of the entity </param>
/// <param name="strapComp"> strap component of the thing we are strapping to </param>
private void UpdateBuckleStatus ( EntityUid uid , BuckleComponent buckleComp , StrapComponent ? strapComp = null )
2022-11-18 22:08:28 +01:00
{
2023-09-16 07:15:05 +03:00
Appearance . SetData ( uid , StrapVisuals . State , buckleComp . Buckled ) ;
2023-05-01 03:04:23 -04:00
if ( buckleComp . BuckledTo ! = null )
{
if ( ! Resolve ( buckleComp . BuckledTo . Value , ref strapComp ) )
return ;
2022-11-18 22:08:28 +01:00
2023-05-01 03:04:23 -04:00
var alertType = strapComp . BuckledAlertType ;
2023-09-16 07:15:05 +03:00
_alerts . ShowAlert ( uid , alertType ) ;
2023-05-01 03:04:23 -04:00
}
else
{
2023-09-16 07:15:05 +03:00
_alerts . ClearAlertCategory ( uid , AlertCategory . Buckled ) ;
2023-05-01 03:04:23 -04:00
}
}
2022-11-18 22:08:28 +01:00
2023-05-01 03:04:23 -04:00
/// <summary>
/// Sets the <see cref="BuckleComponent.BuckledTo"/> field in the component to a value
/// </summary>
/// <param name="strapUid"> Value tat with be assigned to the field </param>
private void SetBuckledTo ( EntityUid buckleUid , EntityUid ? strapUid , StrapComponent ? strapComp , BuckleComponent buckleComp )
{
buckleComp . BuckledTo = strapUid ;
2022-11-18 22:08:28 +01:00
2023-05-01 03:04:23 -04:00
if ( strapUid = = null )
{
buckleComp . Buckled = false ;
}
else
{
buckleComp . LastEntityBuckledTo = strapUid ;
buckleComp . DontCollide = true ;
buckleComp . Buckled = true ;
buckleComp . BuckleTime = _gameTiming . CurTime ;
}
2022-11-18 22:08:28 +01:00
2023-09-16 07:15:05 +03:00
ActionBlocker . UpdateCanMove ( buckleUid ) ;
2023-05-01 03:04:23 -04:00
UpdateBuckleStatus ( buckleUid , buckleComp , strapComp ) ;
Dirty ( buckleComp ) ;
}
2022-11-18 22:08:28 +01:00
2023-05-01 03:04:23 -04:00
/// <summary>
/// Checks whether or not buckling is possible
/// </summary>
/// <param name="buckleUid"> Uid of the owner of BuckleComponent </param>
/// <param name="userUid">
/// Uid of a third party entity,
/// i.e, the uid of someone else you are dragging to a chair.
/// Can equal buckleUid sometimes
/// </param>
/// <param name="strapUid"> Uid of the owner of strap component </param>
private bool CanBuckle (
EntityUid buckleUid ,
EntityUid userUid ,
EntityUid strapUid ,
[NotNullWhen(true)] out StrapComponent ? strapComp ,
BuckleComponent ? buckleComp = null )
{
strapComp = null ;
if ( userUid = = strapUid | |
! Resolve ( buckleUid , ref buckleComp , false ) | |
! Resolve ( strapUid , ref strapComp , false ) )
{
return false ;
}
// Does it pass the Whitelist
if ( strapComp . AllowedEntities ! = null & &
! strapComp . AllowedEntities . IsValid ( userUid , EntityManager ) )
{
if ( _netManager . IsServer )
2023-09-16 07:15:05 +03:00
_popup . PopupEntity ( Loc . GetString ( "buckle-component-cannot-fit-message" ) , userUid , buckleUid , PopupType . Medium ) ;
2023-05-01 03:04:23 -04:00
return false ;
}
// Is it within range
bool Ignored ( EntityUid entity ) = > entity = = buckleUid | | entity = = userUid | | entity = = strapUid ;
2023-09-16 07:15:05 +03:00
if ( ! _interaction . InRangeUnobstructed ( buckleUid , strapUid , buckleComp . Range , predicate : Ignored ,
2023-05-01 03:04:23 -04:00
popup : true ) )
2022-11-18 22:08:28 +01:00
{
2023-05-01 03:04:23 -04:00
return false ;
2022-11-18 22:08:28 +01:00
}
2023-05-01 03:04:23 -04:00
// If in a container
2023-09-16 07:15:05 +03:00
if ( _container . TryGetContainingContainer ( buckleUid , out var ownerContainer ) )
2023-05-01 03:04:23 -04:00
{
// And not in the same container as the strap
2023-09-16 07:15:05 +03:00
if ( ! _container . TryGetContainingContainer ( strapUid , out var strapContainer ) | |
2023-05-01 03:04:23 -04:00
ownerContainer ! = strapContainer )
{
return false ;
}
}
if ( ! HasComp < HandsComponent > ( userUid ) )
{
// PopupPredicted when
if ( _netManager . IsServer )
2023-09-16 07:15:05 +03:00
_popup . PopupEntity ( Loc . GetString ( "buckle-component-no-hands-message" ) , userUid , userUid ) ;
2023-05-01 03:04:23 -04:00
return false ;
}
if ( buckleComp . Buckled )
{
var message = Loc . GetString ( buckleUid = = userUid
? "buckle-component-already-buckled-message"
: "buckle-component-other-already-buckled-message" ,
( "owner" , Identity . Entity ( buckleUid , EntityManager ) ) ) ;
if ( _netManager . IsServer )
2023-09-16 07:15:05 +03:00
_popup . PopupEntity ( message , userUid , userUid ) ;
2023-05-01 03:04:23 -04:00
return false ;
}
var parent = Transform ( strapUid ) . ParentUid ;
while ( parent . IsValid ( ) )
{
if ( parent = = userUid )
{
var message = Loc . GetString ( buckleUid = = userUid
? "buckle-component-cannot-buckle-message"
: "buckle-component-other-cannot-buckle-message" , ( "owner" , Identity . Entity ( buckleUid , EntityManager ) ) ) ;
if ( _netManager . IsServer )
2023-09-16 07:15:05 +03:00
_popup . PopupEntity ( message , userUid , userUid ) ;
2023-05-01 03:04:23 -04:00
return false ;
}
parent = Transform ( parent ) . ParentUid ;
}
if ( ! StrapHasSpace ( strapUid , buckleComp , strapComp ) )
{
var message = Loc . GetString ( buckleUid = = userUid
? "buckle-component-cannot-fit-message"
: "buckle-component-other-cannot-fit-message" , ( "owner" , Identity . Entity ( buckleUid , EntityManager ) ) ) ;
if ( _netManager . IsServer )
2023-09-16 07:15:05 +03:00
_popup . PopupEntity ( message , userUid , userUid ) ;
2023-05-01 03:04:23 -04:00
return false ;
}
2023-06-28 23:19:56 -04:00
var attemptEvent = new BuckleAttemptEvent ( strapUid , buckleUid , userUid , true ) ;
RaiseLocalEvent ( attemptEvent . BuckledEntity , ref attemptEvent ) ;
RaiseLocalEvent ( attemptEvent . StrapEntity , ref attemptEvent ) ;
if ( attemptEvent . Cancelled )
return false ;
2023-05-01 03:04:23 -04:00
return true ;
}
/// <summary>
/// Attempts to buckle an entity to a strap
/// </summary>
/// <param name="buckleUid"> Uid of the owner of BuckleComponent </param>
/// <param name="userUid">
/// Uid of a third party entity,
/// i.e, the uid of someone else you are dragging to a chair.
/// Can equal buckleUid sometimes
/// </param>
/// <param name="strapUid"> Uid of the owner of strap component </param>
public bool TryBuckle ( EntityUid buckleUid , EntityUid userUid , EntityUid strapUid , BuckleComponent ? buckleComp = null )
{
2023-09-16 07:15:05 +03:00
if ( ! Resolve ( buckleUid , ref buckleComp , false ) )
2023-05-01 03:04:23 -04:00
return false ;
2023-09-16 07:15:05 +03:00
if ( ! CanBuckle ( buckleUid , userUid , strapUid , out var strapComp , buckleComp ) )
return false ;
2023-05-01 03:04:23 -04:00
2023-09-16 07:15:05 +03:00
if ( ! StrapTryAdd ( strapUid , buckleUid , buckleComp , false , strapComp ) )
{
var message = Loc . GetString ( buckleUid = = userUid
? "buckle-component-cannot-buckle-message"
: "buckle-component-other-cannot-buckle-message" , ( "owner" , Identity . Entity ( buckleUid , EntityManager ) ) ) ;
2023-05-01 03:04:23 -04:00
if ( _netManager . IsServer )
2023-09-16 07:15:05 +03:00
_popup . PopupEntity ( message , userUid , userUid ) ;
return false ;
}
if ( TryComp < AppearanceComponent > ( buckleUid , out var appearance ) )
Appearance . SetData ( buckleUid , BuckleVisuals . Buckled , true , appearance ) ;
2024-01-30 18:23:30 -05:00
_rotationVisuals . SetHorizontalAngle ( buckleUid , strapComp . Rotation ) ;
2023-12-26 18:32:25 -05:00
2023-09-16 07:15:05 +03:00
ReAttach ( buckleUid , strapUid , buckleComp , strapComp ) ;
SetBuckledTo ( buckleUid , strapUid , strapComp , buckleComp ) ;
// TODO user is currently set to null because if it isn't the sound fails to play in some situations, fix that
2024-01-20 17:22:19 +11:00
_audio . PlayPredicted ( strapComp . BuckleSound , strapUid , userUid ) ;
2023-09-16 07:15:05 +03:00
var ev = new BuckleChangeEvent ( strapUid , buckleUid , true ) ;
RaiseLocalEvent ( ev . BuckledEntity , ref ev ) ;
RaiseLocalEvent ( ev . StrapEntity , ref ev ) ;
2024-02-03 10:32:30 -08:00
if ( TryComp < SharedPullableComponent > ( buckleUid , out var ownerPullable ) )
2023-09-16 07:15:05 +03:00
{
if ( ownerPullable . Puller ! = null )
{
2024-02-03 10:32:30 -08:00
_pulling . TryStopPull ( ownerPullable ) ;
2023-09-16 07:15:05 +03:00
}
}
if ( TryComp < PhysicsComponent > ( buckleUid , out var physics ) )
{
_physics . ResetDynamics ( physics ) ;
}
2024-02-03 10:32:30 -08:00
if ( ! buckleComp . PullStrap & & TryComp < SharedPullableComponent > ( strapUid , out var toPullable ) )
2023-09-16 07:15:05 +03:00
{
if ( toPullable . Puller = = buckleUid )
{
// can't pull it and buckle to it at the same time
2024-02-03 10:32:30 -08:00
_pulling . TryStopPull ( toPullable ) ;
2023-09-16 07:15:05 +03:00
}
}
// Logging
if ( userUid ! = buckleUid )
_adminLogger . Add ( LogType . Action , LogImpact . Low , $"{ToPrettyString(userUid):player} buckled {ToPrettyString(buckleUid)} to {ToPrettyString(strapUid)}" ) ;
else
_adminLogger . Add ( LogType . Action , LogImpact . Low , $"{ToPrettyString(userUid):player} buckled themselves to {ToPrettyString(strapUid)}" ) ;
return true ;
2023-05-01 03:04:23 -04:00
}
/// <summary>
/// Tries to unbuckle the Owner of this component from its current strap.
/// </summary>
/// <param name="buckleUid">The entity to unbuckle.</param>
/// <param name="userUid">The entity doing the unbuckling.</param>
/// <param name="force">
/// Whether to force the unbuckling or not. Does not guarantee true to
/// be returned, but guarantees the owner to be unbuckled afterwards.
/// </param>
/// <param name="buckleComp">The buckle component of the entity to unbuckle.</param>
/// <returns>
/// true if the owner was unbuckled, otherwise false even if the owner
/// was previously already unbuckled.
/// </returns>
public bool TryUnbuckle ( EntityUid buckleUid , EntityUid userUid , bool force = false , BuckleComponent ? buckleComp = null )
{
if ( ! Resolve ( buckleUid , ref buckleComp , false ) | |
buckleComp . BuckledTo is not { } strapUid )
return false ;
if ( ! force )
{
2023-06-28 23:19:56 -04:00
var attemptEvent = new BuckleAttemptEvent ( strapUid , buckleUid , userUid , false ) ;
RaiseLocalEvent ( attemptEvent . BuckledEntity , ref attemptEvent ) ;
RaiseLocalEvent ( attemptEvent . StrapEntity , ref attemptEvent ) ;
if ( attemptEvent . Cancelled )
return false ;
2023-09-28 16:20:29 -07:00
if ( _gameTiming . CurTime < buckleComp . BuckleTime + buckleComp . Delay )
2023-05-01 03:04:23 -04:00
return false ;
2023-09-16 07:15:05 +03:00
if ( ! _interaction . InRangeUnobstructed ( userUid , strapUid , buckleComp . Range , popup : true ) )
2023-05-01 03:04:23 -04:00
return false ;
if ( HasComp < SleepingComponent > ( buckleUid ) & & buckleUid = = userUid )
return false ;
2023-11-16 03:39:04 +01:00
// If the person is crit or dead in any kind of strap, return. This prevents people from unbuckling themselves while incapacitated.
if ( _mobState . IsIncapacitated ( buckleUid ) & & userUid = = buckleUid )
2023-05-01 03:04:23 -04:00
return false ;
}
// Logging
if ( userUid ! = buckleUid )
_adminLogger . Add ( LogType . Action , LogImpact . Low , $"{ToPrettyString(userUid):player} unbuckled {ToPrettyString(buckleUid)} from {ToPrettyString(strapUid)}" ) ;
else
_adminLogger . Add ( LogType . Action , LogImpact . Low , $"{ToPrettyString(userUid):player} unbuckled themselves from {ToPrettyString(strapUid)}" ) ;
SetBuckledTo ( buckleUid , null , null , buckleComp ) ;
if ( ! TryComp < StrapComponent > ( strapUid , out var strapComp ) )
return false ;
var buckleXform = Transform ( buckleUid ) ;
var oldBuckledXform = Transform ( strapUid ) ;
if ( buckleXform . ParentUid = = strapUid & & ! Terminating ( buckleXform . ParentUid ) )
{
2023-10-19 12:34:31 -07:00
_container . AttachParentToContainerOrGrid ( ( buckleUid , buckleXform ) ) ;
2023-05-01 03:04:23 -04:00
2023-09-16 07:15:05 +03:00
var oldBuckledToWorldRot = _transform . GetWorldRotation ( strapUid ) ;
_transform . SetWorldRotation ( buckleXform , oldBuckledToWorldRot ) ;
2023-05-01 03:04:23 -04:00
if ( strapComp . UnbuckleOffset ! = Vector2 . Zero )
2024-02-28 00:51:20 +11:00
buckleXform . Coordinates = oldBuckledXform . Coordinates . Offset ( strapComp . UnbuckleOffset ) ;
2023-05-01 03:04:23 -04:00
}
if ( TryComp ( buckleUid , out AppearanceComponent ? appearance ) )
2023-09-16 07:15:05 +03:00
Appearance . SetData ( buckleUid , BuckleVisuals . Buckled , false , appearance ) ;
2023-12-26 18:32:25 -05:00
_rotationVisuals . ResetHorizontalAngle ( buckleUid ) ;
2023-05-01 03:04:23 -04:00
if ( TryComp < MobStateComponent > ( buckleUid , out var mobState )
2023-09-16 07:15:05 +03:00
& & _mobState . IsIncapacitated ( buckleUid , mobState )
2023-05-01 03:04:23 -04:00
| | HasComp < KnockedDownComponent > ( buckleUid ) )
{
2023-09-16 07:15:05 +03:00
_standing . Down ( buckleUid ) ;
2023-05-01 03:04:23 -04:00
}
else
{
2023-09-16 07:15:05 +03:00
_standing . Stand ( buckleUid ) ;
2023-05-01 03:04:23 -04:00
}
2023-09-16 07:15:05 +03:00
if ( _mobState . IsIncapacitated ( buckleUid , mobState ) )
2023-05-01 03:04:23 -04:00
{
2023-09-16 07:15:05 +03:00
_standing . Down ( buckleUid ) ;
2023-05-01 03:04:23 -04:00
}
if ( strapComp . BuckledEntities . Remove ( buckleUid ) )
{
strapComp . OccupiedSize - = buckleComp . Size ;
//Dirty(strapUid);
Dirty ( strapComp ) ;
}
2023-08-30 22:37:49 +10:00
_joints . RefreshRelay ( buckleUid ) ;
2023-09-16 07:15:05 +03:00
Appearance . SetData ( strapUid , StrapVisuals . State , strapComp . BuckledEntities . Count ! = 0 ) ;
2023-11-27 22:12:34 +11:00
// TODO: Buckle listening to moveevents is sussy anyway.
if ( ! TerminatingOrDeleted ( strapUid ) )
_audio . PlayPredicted ( strapComp . UnbuckleSound , strapUid , userUid ) ;
2023-05-01 03:04:23 -04:00
var ev = new BuckleChangeEvent ( strapUid , buckleUid , false ) ;
RaiseLocalEvent ( buckleUid , ref ev ) ;
RaiseLocalEvent ( strapUid , ref ev ) ;
return true ;
}
/// <summary>
/// Makes an entity toggle the buckling status of the owner to a
/// specific entity.
/// </summary>
/// <param name="buckleUid">The entity to buckle/unbuckle from <see cref="to"/>.</param>
/// <param name="userUid">The entity doing the buckling/unbuckling.</param>
/// <param name="strapUid">
/// The entity to toggle the buckle status of the owner to.
/// </param>
/// <param name="force">
/// Whether to force the unbuckling or not, if it happens. Does not
/// guarantee true to be returned, but guarantees the owner to be
/// unbuckled afterwards.
/// </param>
/// <param name="buckle">The buckle component of the entity to buckle/unbuckle from <see cref="to"/>.</param>
/// <returns>true if the buckling status was changed, false otherwise.</returns>
public bool ToggleBuckle (
EntityUid buckleUid ,
EntityUid userUid ,
EntityUid strapUid ,
bool force = false ,
BuckleComponent ? buckle = null )
{
if ( ! Resolve ( buckleUid , ref buckle , false ) )
return false ;
if ( ! buckle . Buckled )
{
return TryBuckle ( buckleUid , userUid , strapUid , buckle ) ;
}
else
{
return TryUnbuckle ( buckleUid , userUid , force , buckle ) ;
}
2022-11-18 22:08:28 +01:00
}
}