private void MoveEvent(EntityUid uid, BuckleComponent buckle, MoveEvent ev) { var strap = buckle.BuckledTo; if (strap == null) { return; } var strapPosition = strap.Owner.Transform.Coordinates.Offset(buckle.BuckleOffset); if (ev.NewPosition.InRange(EntityManager, strapPosition, 0.2f)) { return; } buckle.TryUnbuckle(buckle.Owner, true); }
private void MoveEvent(EntityUid uid, BuckleComponent buckle, ref MoveEvent ev) { var strap = buckle.BuckledTo; if (strap == null) { return; } var strapPosition = EntityManager.GetComponent <TransformComponent>(strap.Owner).Coordinates.Offset(buckle.BuckleOffset); if (ev.NewPosition.InRange(EntityManager, strapPosition, strap.MaxBuckleDistance)) { return; } buckle.TryUnbuckle(buckle.Owner, true); }
private void ContainerModifiedReAttach(BuckleComponent buckle, StrapComponent?strap) { if (strap == null) { return; } var contained = buckle.Owner.TryGetContainer(out var ownContainer); var strapContained = strap.Owner.TryGetContainer(out var strapContainer); if (contained != strapContained || ownContainer != strapContainer) { buckle.TryUnbuckle(buckle.Owner, true); return; } if (!contained) { buckle.ReAttach(strap); } }
private void AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetInteractionVerbsEvent args) { if (!args.CanAccess || !args.CanInteract || !component.Buckled) { return; } Verb verb = new(); verb.Act = () => component.TryUnbuckle(args.User); verb.Category = VerbCategory.Unbuckle; 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 AddUnbuckleVerb(EntityUid uid, BuckleComponent component, GetInteractionVerbsEvent args) { if (!args.CanAccess || !args.CanInteract || !component.Buckled) { return; } Verb verb = new(); verb.Act = () => component.TryUnbuckle(args.User); verb.Text = Loc.GetString("verb-categories-unbuckle"); verb.IconTexture = "/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); }
public async Task BuckleUnbuckleCooldownRangeTest() { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings { ExtraPrototypes = Prototypes }); var server = pairTracker.Pair.Server; var testMap = await PoolManager.CreateTestMap(pairTracker); var coordinates = testMap.GridCoords; EntityUid human = default; EntityUid chair = default; BuckleComponent buckle = null; StrapComponent strap = null; await server.WaitAssertion(() => { var mapManager = IoCManager.Resolve <IMapManager>(); var entityManager = IoCManager.Resolve <IEntityManager>(); var actionBlocker = EntitySystem.Get <ActionBlockerSystem>(); var standingState = EntitySystem.Get <StandingStateSystem>(); human = entityManager.SpawnEntity(BuckleDummyId, coordinates); chair = entityManager.SpawnEntity(StrapDummyId, coordinates); // Default state, unbuckled Assert.True(entityManager.TryGetComponent(human, out buckle)); Assert.NotNull(buckle); Assert.Null(buckle.BuckledTo); Assert.False(buckle.Buckled); Assert.True(actionBlocker.CanMove(human)); Assert.True(actionBlocker.CanChangeDirection(human)); Assert.True(standingState.Down(human)); Assert.True(standingState.Stand(human)); // Default state, no buckled entities, strap Assert.True(entityManager.TryGetComponent(chair, out strap)); Assert.NotNull(strap); Assert.IsEmpty(strap.BuckledEntities); Assert.Zero(strap.OccupiedSize); // Side effects of buckling Assert.True(buckle.TryBuckle(human, chair)); Assert.NotNull(buckle.BuckledTo); Assert.True(buckle.Buckled); Assert.True(((BuckleComponentState)buckle.GetComponentState()).Buckled); Assert.False(actionBlocker.CanMove(human)); Assert.False(actionBlocker.CanChangeDirection(human)); Assert.False(standingState.Down(human)); Assert.That((entityManager.GetComponent <TransformComponent>(human).WorldPosition - entityManager.GetComponent <TransformComponent>(chair).WorldPosition).Length, Is.LessThanOrEqualTo(buckle.BuckleOffset.Length)); // Side effects of buckling for the strap Assert.That(strap.BuckledEntities, Does.Contain(human)); Assert.That(strap.OccupiedSize, Is.EqualTo(buckle.Size)); Assert.Positive(strap.OccupiedSize); // Trying to buckle while already buckled fails Assert.False(buckle.TryBuckle(human, chair)); // Trying to unbuckle too quickly fails Assert.False(buckle.TryUnbuckle(human)); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); }); // Wait enough ticks for the unbuckling cooldown to run out await server.WaitRunTicks(60); await server.WaitAssertion(() => { var actionBlocker = EntitySystem.Get <ActionBlockerSystem>(); var standingState = EntitySystem.Get <StandingStateSystem>(); // Still buckled Assert.True(buckle.Buckled); // Unbuckle Assert.True(buckle.TryUnbuckle(human)); Assert.Null(buckle.BuckledTo); Assert.False(buckle.Buckled); Assert.True(actionBlocker.CanMove(human)); Assert.True(actionBlocker.CanChangeDirection(human)); Assert.True(standingState.Down(human)); // Unbuckle, strap Assert.IsEmpty(strap.BuckledEntities); Assert.Zero(strap.OccupiedSize); // Re-buckling has no cooldown Assert.True(buckle.TryBuckle(human, chair)); Assert.True(buckle.Buckled); // On cooldown Assert.False(buckle.TryUnbuckle(human)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); }); // Wait enough ticks for the unbuckling cooldown to run out await server.WaitRunTicks(60); await server.WaitAssertion(() => { var entityManager = IoCManager.Resolve <IEntityManager>(); var actionBlocker = EntitySystem.Get <ActionBlockerSystem>(); var standingState = EntitySystem.Get <StandingStateSystem>(); // Still buckled Assert.True(buckle.Buckled); // Unbuckle Assert.True(buckle.TryUnbuckle(human)); Assert.False(buckle.Buckled); // Move away from the chair entityManager.GetComponent <TransformComponent>(human).WorldPosition += (1000, 1000); // Out of range Assert.False(buckle.TryBuckle(human, chair)); Assert.False(buckle.TryUnbuckle(human)); Assert.False(buckle.ToggleBuckle(human, chair)); // Move near the chair entityManager.GetComponent <TransformComponent>(human).WorldPosition = entityManager.GetComponent <TransformComponent>(chair).WorldPosition + (0.5f, 0); // In range Assert.True(buckle.TryBuckle(human, chair)); Assert.True(buckle.Buckled); Assert.False(buckle.TryUnbuckle(human)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); // Force unbuckle Assert.True(buckle.TryUnbuckle(human, true)); Assert.False(buckle.Buckled); Assert.True(actionBlocker.CanMove(human)); Assert.True(actionBlocker.CanChangeDirection(human)); Assert.True(standingState.Down(human)); // Re-buckle Assert.True(buckle.TryBuckle(human, chair)); // Move away from the chair entityManager.GetComponent <TransformComponent>(human).WorldPosition += (1, 0); }); await server.WaitRunTicks(1); await server.WaitAssertion(() => { // No longer buckled Assert.False(buckle.Buckled); Assert.Null(buckle.BuckledTo); Assert.IsEmpty(strap.BuckledEntities); }); await pairTracker.CleanReturnAsync(); }
public async Task BuckledDyingDropItemsTest() { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings { NoClient = true, ExtraPrototypes = Prototypes }); var server = pairTracker.Pair.Server; var testMap = await PoolManager.CreateTestMap(pairTracker); var coordinates = testMap.GridCoords; EntityUid human = default; BuckleComponent buckle = null; HandsComponent hands = null; SharedBodyComponent body = null; await server.WaitIdleAsync(); await server.WaitAssertion(() => { var entityManager = IoCManager.Resolve <IEntityManager>(); human = entityManager.SpawnEntity(BuckleDummyId, coordinates); var chair = entityManager.SpawnEntity(StrapDummyId, coordinates); // Component sanity check Assert.True(entityManager.TryGetComponent(human, out buckle)); Assert.True(entityManager.HasComponent <StrapComponent>(chair)); Assert.True(entityManager.TryGetComponent(human, out hands)); Assert.True(entityManager.TryGetComponent(human, out body)); // Buckle Assert.True(buckle.TryBuckle(human, chair)); Assert.NotNull(buckle.BuckledTo); Assert.True(buckle.Buckled); // Put an item into every hand for (var i = 0; i < hands.Count; i++) { var akms = entityManager.SpawnEntity(ItemDummyId, coordinates); Assert.True(EntitySystem.Get <SharedHandsSystem>().TryPickupAnyHand(human, akms)); } }); await server.WaitRunTicks(10); await server.WaitAssertion(() => { // Still buckled Assert.True(buckle.Buckled); // With items in all hands foreach (var hand in hands.Hands.Values) { Assert.NotNull(hands.ActiveHandEntity); } var legs = body.GetPartsOfType(BodyPartType.Leg); // Break our guy's kneecaps foreach (var leg in legs) { body.RemovePart(leg); } }); await server.WaitRunTicks(10); await server.WaitAssertion(() => { // Still buckled Assert.True(buckle.Buckled); // Now with no item in any hand foreach (var hand in hands.Hands.Values) { Assert.Null(hands.ActiveHandEntity); } buckle.TryUnbuckle(human, true); }); await pairTracker.CleanReturnAsync(); }
private void HandleInteractHand(EntityUid uid, BuckleComponent component, InteractHandEvent args) { args.Handled = component.TryUnbuckle(args.User); }
private void HandleAttackHand(EntityUid uid, BuckleComponent component, AttackHandEvent args) { args.Handled = component.TryUnbuckle(args.User); }
public async Task BuckledDyingDropItemsTest() { var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes }; var server = StartServer(options); EntityUid human = default; BuckleComponent buckle = null; HandsComponent hands = null; SharedBodyComponent body = null; await server.WaitIdleAsync(); await server.WaitAssertion(() => { var mapManager = IoCManager.Resolve <IMapManager>(); var entityManager = IoCManager.Resolve <IEntityManager>(); var grid = GetMainGrid(mapManager); var coordinates = new EntityCoordinates(grid.GridEntityId, 0, 0); human = entityManager.SpawnEntity(BuckleDummyId, coordinates); var chair = entityManager.SpawnEntity(StrapDummyId, coordinates); // Component sanity check Assert.True(entityManager.TryGetComponent(human, out buckle)); Assert.True(entityManager.HasComponent <StrapComponent>(chair)); Assert.True(entityManager.TryGetComponent(human, out hands)); Assert.True(entityManager.TryGetComponent(human, out body)); // Buckle Assert.True(buckle.TryBuckle(human, chair)); Assert.NotNull(buckle.BuckledTo); Assert.True(buckle.Buckled); // Put an item into every hand for (var i = 0; i < hands.Count; i++) { var akms = entityManager.SpawnEntity(ItemDummyId, coordinates); // Equip items Assert.True(entityManager.TryGetComponent(akms, out SharedItemComponent item)); Assert.True(hands.PutInHand(item)); } }); await server.WaitRunTicks(10); await server.WaitAssertion(() => { // Still buckled Assert.True(buckle.Buckled); // With items in all hands foreach (var slot in hands.HandNames) { Assert.NotNull(hands.GetItem(slot)); } var legs = body.GetPartsOfType(BodyPartType.Leg); // Break our guy's kneecaps foreach (var leg in legs) { body.RemovePart(leg); } }); await server.WaitRunTicks(10); await server.WaitAssertion(() => { // Still buckled Assert.True(buckle.Buckled); // Now with no item in any hand foreach (var slot in hands.HandNames) { Assert.Null(hands.GetItem(slot)); } buckle.TryUnbuckle(human, true); }); }
public async Task BuckleUnbuckleCooldownRangeTest() { var cOptions = new ClientIntegrationOptions { ExtraPrototypes = Prototypes }; var sOptions = new ServerIntegrationOptions { ExtraPrototypes = Prototypes }; var(_, server) = await StartConnectedServerClientPair(cOptions, sOptions); IEntity human = null; IEntity chair = null; BuckleComponent buckle = null; StrapComponent strap = null; await server.WaitAssertion(() => { var mapManager = IoCManager.Resolve <IMapManager>(); var entityManager = IoCManager.Resolve <IEntityManager>(); var actionBlocker = EntitySystem.Get <ActionBlockerSystem>(); var gridId = new GridId(1); var grid = mapManager.GetGrid(gridId); var coordinates = grid.GridEntityId.ToCoordinates(); human = entityManager.SpawnEntity(BuckleDummyId, coordinates); chair = entityManager.SpawnEntity(StrapDummyId, coordinates); // Default state, unbuckled Assert.True(human.TryGetComponent(out buckle)); Assert.NotNull(buckle); Assert.Null(buckle.BuckledTo); Assert.False(buckle.Buckled); Assert.True(actionBlocker.CanMove(human)); Assert.True(actionBlocker.CanChangeDirection(human)); Assert.True(EffectBlockerSystem.CanFall(human)); // Default state, no buckled entities, strap Assert.True(chair.TryGetComponent(out strap)); Assert.NotNull(strap); Assert.IsEmpty(strap.BuckledEntities); Assert.Zero(strap.OccupiedSize); // Side effects of buckling Assert.True(buckle.TryBuckle(human, chair)); Assert.NotNull(buckle.BuckledTo); Assert.True(buckle.Buckled); var player = IoCManager.Resolve <IPlayerManager>().GetAllPlayers().Single(); Assert.True(((BuckleComponentState)buckle.GetComponentState(player)).Buckled); Assert.False(actionBlocker.CanMove(human)); Assert.False(actionBlocker.CanChangeDirection(human)); Assert.False(EffectBlockerSystem.CanFall(human)); Assert.That(human.Transform.WorldPosition, Is.EqualTo(chair.Transform.WorldPosition)); // Side effects of buckling for the strap Assert.That(strap.BuckledEntities, Does.Contain(human)); Assert.That(strap.OccupiedSize, Is.EqualTo(buckle.Size)); Assert.Positive(strap.OccupiedSize); // Trying to buckle while already buckled fails Assert.False(buckle.TryBuckle(human, chair)); // Trying to unbuckle too quickly fails Assert.False(buckle.TryUnbuckle(human)); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); }); // Wait enough ticks for the unbuckling cooldown to run out await server.WaitRunTicks(60); await server.WaitAssertion(() => { var actionBlocker = EntitySystem.Get <ActionBlockerSystem>(); // Still buckled Assert.True(buckle.Buckled); // Unbuckle Assert.True(buckle.TryUnbuckle(human)); Assert.Null(buckle.BuckledTo); Assert.False(buckle.Buckled); Assert.True(actionBlocker.CanMove(human)); Assert.True(actionBlocker.CanChangeDirection(human)); Assert.True(EffectBlockerSystem.CanFall(human)); // Unbuckle, strap Assert.IsEmpty(strap.BuckledEntities); Assert.Zero(strap.OccupiedSize); // Re-buckling has no cooldown Assert.True(buckle.TryBuckle(human, chair)); Assert.True(buckle.Buckled); // On cooldown Assert.False(buckle.TryUnbuckle(human)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); }); // Wait enough ticks for the unbuckling cooldown to run out await server.WaitRunTicks(60); await server.WaitAssertion(() => { var actionBlocker = EntitySystem.Get <ActionBlockerSystem>(); // Still buckled Assert.True(buckle.Buckled); // Unbuckle Assert.True(buckle.TryUnbuckle(human)); Assert.False(buckle.Buckled); // Move away from the chair human.Transform.WorldPosition += (1000, 1000); // Out of range Assert.False(buckle.TryBuckle(human, chair)); Assert.False(buckle.TryUnbuckle(human)); Assert.False(buckle.ToggleBuckle(human, chair)); // Move near the chair human.Transform.WorldPosition = chair.Transform.WorldPosition + (0.5f, 0); // In range Assert.True(buckle.TryBuckle(human, chair)); Assert.True(buckle.Buckled); Assert.False(buckle.TryUnbuckle(human)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); // Force unbuckle Assert.True(buckle.TryUnbuckle(human, true)); Assert.False(buckle.Buckled); Assert.True(actionBlocker.CanMove(human)); Assert.True(actionBlocker.CanChangeDirection(human)); Assert.True(EffectBlockerSystem.CanFall(human)); // Re-buckle Assert.True(buckle.TryBuckle(human, chair)); // Move away from the chair human.Transform.WorldPosition += (1, 0); }); await server.WaitRunTicks(1); await server.WaitAssertion(() => { // No longer buckled Assert.False(buckle.Buckled); Assert.Null(buckle.BuckledTo); Assert.IsEmpty(strap.BuckledEntities); }); }
public async Task BuckleUnbuckleCooldownRangeTest() { var server = StartServerDummyTicker(); IEntity human = null; IEntity chair = null; BuckleComponent buckle = null; StrapComponent strap = null; await server.WaitAssertion(() => { var mapManager = IoCManager.Resolve <IMapManager>(); mapManager.CreateNewMapEntity(MapId.Nullspace); var entityManager = IoCManager.Resolve <IEntityManager>(); human = entityManager.SpawnEntity("HumanMob_Content", MapCoordinates.Nullspace); chair = entityManager.SpawnEntity("ChairWood", MapCoordinates.Nullspace); // Default state, unbuckled Assert.True(human.TryGetComponent(out buckle)); Assert.NotNull(buckle); Assert.Null(buckle.BuckledTo); Assert.False(buckle.Buckled); Assert.True(ActionBlockerSystem.CanMove(human)); Assert.True(ActionBlockerSystem.CanChangeDirection(human)); Assert.True(EffectBlockerSystem.CanFall(human)); // Default state, no buckled entities, strap Assert.True(chair.TryGetComponent(out strap)); Assert.NotNull(strap); Assert.IsEmpty(strap.BuckledEntities); Assert.Zero(strap.OccupiedSize); // Side effects of buckling Assert.True(buckle.TryBuckle(human, chair)); Assert.NotNull(buckle.BuckledTo); Assert.True(buckle.Buckled); Assert.True(((BuckleComponentState)buckle.GetComponentState()).Buckled); Assert.False(ActionBlockerSystem.CanMove(human)); Assert.False(ActionBlockerSystem.CanChangeDirection(human)); Assert.False(EffectBlockerSystem.CanFall(human)); Assert.That(human.Transform.WorldPosition, Is.EqualTo(chair.Transform.WorldPosition)); // Side effects of buckling for the strap Assert.That(strap.BuckledEntities, Does.Contain(human)); Assert.That(strap.OccupiedSize, Is.EqualTo(buckle.Size)); Assert.Positive(strap.OccupiedSize); // Trying to buckle while already buckled fails Assert.False(buckle.TryBuckle(human, chair)); // Trying to unbuckle too quickly fails Assert.False(buckle.TryUnbuckle(human)); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); }); // Wait enough ticks for the unbuckling cooldown to run out await server.WaitRunTicks(60); await server.WaitAssertion(() => { // Still buckled Assert.True(buckle.Buckled); // Unbuckle Assert.True(buckle.TryUnbuckle(human)); Assert.Null(buckle.BuckledTo); Assert.False(buckle.Buckled); Assert.True(ActionBlockerSystem.CanMove(human)); Assert.True(ActionBlockerSystem.CanChangeDirection(human)); Assert.True(EffectBlockerSystem.CanFall(human)); // Unbuckle, strap Assert.IsEmpty(strap.BuckledEntities); Assert.Zero(strap.OccupiedSize); // Re-buckling has no cooldown Assert.True(buckle.TryBuckle(human, chair)); Assert.True(buckle.Buckled); // On cooldown Assert.False(buckle.TryUnbuckle(human)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); }); // Wait enough ticks for the unbuckling cooldown to run out await server.WaitRunTicks(60); await server.WaitAssertion(() => { // Still buckled Assert.True(buckle.Buckled); // Unbuckle Assert.True(buckle.TryUnbuckle(human)); Assert.False(buckle.Buckled); // Move away from the chair human.Transform.WorldPosition += (1000, 1000); // Out of range Assert.False(buckle.TryBuckle(human, chair)); Assert.False(buckle.TryUnbuckle(human)); Assert.False(buckle.ToggleBuckle(human, chair)); // Move near the chair human.Transform.WorldPosition = chair.Transform.WorldPosition + (0.5f, 0); // In range Assert.True(buckle.TryBuckle(human, chair)); Assert.True(buckle.Buckled); Assert.False(buckle.TryUnbuckle(human)); Assert.True(buckle.Buckled); Assert.False(buckle.ToggleBuckle(human, chair)); Assert.True(buckle.Buckled); // Force unbuckle Assert.True(buckle.TryUnbuckle(human, true)); Assert.False(buckle.Buckled); Assert.True(ActionBlockerSystem.CanMove(human)); Assert.True(ActionBlockerSystem.CanChangeDirection(human)); Assert.True(EffectBlockerSystem.CanFall(human)); // Re-buckle Assert.True(buckle.TryBuckle(human, chair)); // Move away from the chair human.Transform.WorldPosition += (1, 0); }); await server.WaitRunTicks(1); await server.WaitAssertion(() => { // No longer buckled Assert.False(buckle.Buckled); Assert.Null(buckle.BuckledTo); Assert.IsEmpty(strap.BuckledEntities); }); }
public async Task BuckledDyingDropItemsTest() { var options = new ServerIntegrationOptions { ExtraPrototypes = PROTOTYPES }; var server = StartServer(options); IEntity human = null; BuckleComponent buckle = null; HandsComponent hands = null; IBody body = null; await server.WaitIdleAsync(); await server.WaitAssertion(() => { var mapManager = IoCManager.Resolve <IMapManager>(); var entityManager = IoCManager.Resolve <IEntityManager>(); var gridId = new GridId(1); var grid = mapManager.GetGrid(gridId); var coordinates = grid.GridEntityId.ToCoordinates(); human = entityManager.SpawnEntity("BuckleDummy", coordinates); IEntity chair = entityManager.SpawnEntity("StrapDummy", coordinates); // Component sanity check Assert.True(human.TryGetComponent(out buckle)); Assert.True(chair.HasComponent <StrapComponent>()); Assert.True(human.TryGetComponent(out hands)); Assert.True(human.TryGetComponent(out body)); // Buckle Assert.True(buckle.TryBuckle(human, chair)); Assert.NotNull(buckle.BuckledTo); Assert.True(buckle.Buckled); // Put an item into every hand for (var i = 0; i < hands.Count; i++) { var akms = entityManager.SpawnEntity("RifleAk", coordinates); // Equip items Assert.True(akms.TryGetComponent(out ItemComponent item)); Assert.True(hands.PutInHand(item)); } }); await server.WaitRunTicks(10); await server.WaitAssertion(() => { // Still buckled Assert.True(buckle.Buckled); // With items in all hands foreach (var slot in hands.Hands) { Assert.NotNull(hands.GetItem(slot)); } var legs = body.GetPartsOfType(BodyPartType.Leg); // Break our guy's kneecaps foreach (var leg in legs) { body.RemovePart(leg); } }); await server.WaitRunTicks(10); await server.WaitAssertion(() => { // Still buckled Assert.True(buckle.Buckled); // Now with no item in any hand foreach (var slot in hands.Hands) { Assert.Null(hands.GetItem(slot)); } buckle.TryUnbuckle(human, true); }); }