protected override void Initialize() { base.Initialize(); _powerSolarSystem = _entitySystemManager.GetEntitySystem <PowerSolarSystem>(); }
public virtual bool TryUseFood(IEntity?user, IEntity?target, UtensilComponent?utensilUsed = null) { if (!Owner.TryGetComponent(out SolutionContainerComponent? solution)) { return(false); } if (user == null) { return(false); } if (UsesRemaining <= 0) { user.PopupMessage(Loc.GetString("{0:TheName} is empty!", Owner)); return(false); } var trueTarget = target ?? user; if (!trueTarget.TryGetComponent(out IBody? body) || !body.TryGetMechanismBehaviors <StomachBehavior>(out var stomachs)) { return(false); } var utensils = utensilUsed != null ? new List <UtensilComponent> { utensilUsed } : null; if (_utensilsNeeded != UtensilType.None) { utensils = new List <UtensilComponent>(); var types = UtensilType.None; if (user.TryGetComponent(out HandsComponent? hands)) { foreach (var item in hands.GetAllHeldItems()) { if (!item.Owner.TryGetComponent(out UtensilComponent? utensil)) { continue; } utensils.Add(utensil); types |= utensil.Types; } } if (!types.HasFlag(_utensilsNeeded)) { trueTarget.PopupMessage(user, Loc.GetString("food-you-need-to-hold-utensil", ("utensil", _utensilsNeeded))); return(false); } } if (!user.InRangeUnobstructed(trueTarget, popup: true)) { return(false); } var transferAmount = ReagentUnit.Min(_transferAmount, solution.CurrentVolume); var split = solution.SplitSolution(transferAmount); var firstStomach = stomachs.FirstOrDefault(stomach => stomach.CanTransferSolution(split)); if (firstStomach == null) { trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!")); return(false); } // TODO: Account for partial transfer. split.DoEntityReaction(trueTarget, ReactionMethod.Ingestion); firstStomach.TryTransferSolution(split); _entitySystem.GetEntitySystem <AudioSystem>() .PlayFromEntity(_useSound, trueTarget, AudioParams.Default.WithVolume(-1f)); trueTarget.PopupMessage(user, Loc.GetString("Nom")); // If utensils were used if (utensils != null) { foreach (var utensil in utensils) { utensil.TryBreak(user); } } if (UsesRemaining > 0) { return(true); } if (string.IsNullOrEmpty(_trashPrototype)) { Owner.Delete(); return(true); } //We're empty. Become trash. var position = Owner.Transform.Coordinates; var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position); // If the user is holding the item if (user.TryGetComponent(out HandsComponent? handsComponent) && handsComponent.IsHolding(Owner)) { Owner.Delete(); // Put the trash in the user's hand if (finisher.TryGetComponent(out ItemComponent? item) && handsComponent.CanPutInHand(item)) { handsComponent.PutInHand(item); } }
public virtual bool TryUseFood(IEntity user, IEntity target, UtensilComponent utensilUsed = null) { if (user == null) { return(false); } if (UsesRemaining <= 0) { user.PopupMessage(user, Loc.GetString("{0:TheName} is empty!", Owner)); return(false); } var trueTarget = target ?? user; if (!trueTarget.TryGetComponent(out StomachComponent stomach)) { return(false); } var utensils = utensilUsed != null ? new List <UtensilComponent> { utensilUsed } : null; if (_utensilsNeeded != UtensilType.None) { utensils = new List <UtensilComponent>(); var types = UtensilType.None; if (user.TryGetComponent(out HandsComponent hands)) { foreach (var item in hands.GetAllHeldItems()) { if (!item.Owner.TryGetComponent(out UtensilComponent utensil)) { continue; } utensils.Add(utensil); types |= utensil.Types; } } if (!types.HasFlag(_utensilsNeeded)) { trueTarget.PopupMessage(user, Loc.GetString("You need to be holding a {0} to eat that!", _utensilsNeeded)); return(false); } } if (!InteractionChecks.InRangeUnobstructed(user, trueTarget.Transform.MapPosition)) { return(false); } var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume); var split = _contents.SplitSolution(transferAmount); if (!stomach.TryTransferSolution(split)) { _contents.TryAddSolution(split); trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!")); return(false); } _entitySystem.GetEntitySystem <AudioSystem>() .PlayFromEntity(_useSound, trueTarget, AudioParams.Default.WithVolume(-1f)); trueTarget.PopupMessage(user, Loc.GetString("Nom")); // If utensils were used if (utensils != null) { foreach (var utensil in utensils) { utensil.TryBreak(user); } } if (UsesRemaining > 0) { return(true); } if (string.IsNullOrEmpty(_trashPrototype)) { Owner.Delete(); return(true); } //We're empty. Become trash. var position = Owner.Transform.GridPosition; var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position); // If the user is holding the item if (user.TryGetComponent(out HandsComponent handsComponent) && handsComponent.IsHolding(Owner)) { Owner.Delete(); // Put the trash in the user's hand if (finisher.TryGetComponent(out ItemComponent item) && handsComponent.CanPutInHand(item)) { handsComponent.PutInHand(item); } }
public override void Initialize() { base.Initialize(); _actSystem = _entitySystemManager.GetEntitySystem <ActSystem>(); }
public void Init() { _reactions = _prototypeManager.EnumeratePrototypes <ReactionPrototype>(); _audioSystem = _entitySystemManager.GetEntitySystem <AudioSystem>(); }
/// <summary> /// Gets called by an AreaEffectInceptionComponent. "Clones" Owner into the four directions and copies the /// solution into each of them. /// </summary> public void Spread() { var meta = _entities.GetComponent <MetaDataComponent>(Owner); if (meta.EntityPrototype == null) { Logger.Error("AreaEffectComponent needs its owner to be spawned by a prototype."); return; } var xform = _entities.GetComponent <TransformComponent>(Owner); var solSys = _systems.GetEntitySystem <SolutionContainerSystem>(); if (!_entities.TryGetComponent(xform.GridUid, out IMapGridComponent? gridComp)) { return; } var grid = gridComp.Grid; var origin = grid.TileIndicesFor(xform.Coordinates); DebugTools.Assert(xform.Anchored, "Area effect entity prototypes must be anchored."); void SpreadToDir(Direction dir) { // Currently no support for spreading off or across grids. var index = origin + dir.ToIntVec(); if (!grid.TryGetTileRef(index, out var tile) || tile.Tile.IsEmpty) { return; } foreach (var neighbor in grid.GetAnchoredEntities(index)) { if (_entities.TryGetComponent(neighbor, out SolutionAreaEffectComponent? comp) && comp.Inception == Inception) { return; } // TODO for thindows and the like, need to check the directions that are being blocked. // --> would then also mean you need to check for blockers on the origin tile. if (_entities.TryGetComponent(neighbor, out AirtightComponent? airtight) && airtight.AirBlocked) { return; } } var newEffect = _entities.SpawnEntity( meta.EntityPrototype.ID, grid.GridTileToLocal(index)); if (!_entities.TryGetComponent(newEffect, out SolutionAreaEffectComponent? effectComponent)) { _entities.DeleteEntity(newEffect); return; } if (solSys.TryGetSolution(Owner, SolutionName, out var solution)) { effectComponent.TryAddSolution(solution.Clone()); } effectComponent.Amount = Amount - 1; Inception?.Add(effectComponent); } SpreadToDir(Direction.North); SpreadToDir(Direction.East); SpreadToDir(Direction.South); SpreadToDir(Direction.West); }
private bool Explosion() { //Prevent adjacent explosives from infinitely blowing each other up. if (_beingExploded) { return(true); } _beingExploded = true; var maxRange = MathHelper.Max(DevastationRange, HeavyImpactRange, LightImpactRange, 0f); //Entity damage calculation var entitiesAll = _serverEntityManager.GetEntitiesInRange(Owner.Transform.GridPosition, maxRange).ToList(); foreach (var entity in entitiesAll) { if (entity == Owner) { continue; } if (!entity.Transform.IsMapTransform) { continue; } var distanceFromEntity = (int)entity.Transform.GridPosition.Distance(_mapManager, Owner.Transform.GridPosition); var exAct = _entitySystemManager.GetEntitySystem <ActSystem>(); var severity = ExplosionSeverity.Destruction; if (distanceFromEntity < DevastationRange) { severity = ExplosionSeverity.Destruction; } else if (distanceFromEntity < HeavyImpactRange) { severity = ExplosionSeverity.Heavy; } else if (distanceFromEntity < LightImpactRange) { severity = ExplosionSeverity.Light; } else { continue; } exAct.HandleExplosion(Owner, entity, severity); } //Tile damage calculation mockup //TODO: make it into some sort of actual damage component or whatever the boys think is appropriate var mapGrid = _mapManager.GetGrid(Owner.Transform.GridPosition.GridID); var circle = new Circle(Owner.Transform.GridPosition.Position, maxRange); var tiles = mapGrid.GetTilesIntersecting(circle); foreach (var tile in tiles) { var tileLoc = mapGrid.GridTileToLocal(tile.GridIndices); var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId]; var distanceFromTile = (int)tileLoc.Distance(_mapManager, Owner.Transform.GridPosition); if (!string.IsNullOrWhiteSpace(tileDef.SubFloor)) { if (distanceFromTile < DevastationRange) { mapGrid.SetTile(tileLoc, new Tile(_tileDefinitionManager["space"].TileId)); } if (distanceFromTile < HeavyImpactRange) { if (_robustRandom.Prob(80)) { mapGrid.SetTile(tileLoc, new Tile(_tileDefinitionManager[tileDef.SubFloor].TileId)); } else { mapGrid.SetTile(tileLoc, new Tile(_tileDefinitionManager["space"].TileId)); } } if (distanceFromTile < LightImpactRange) { if (_robustRandom.Prob(50)) { mapGrid.SetTile(tileLoc, new Tile(_tileDefinitionManager[tileDef.SubFloor].TileId)); } } } } //Effects and sounds var time = IoCManager.Resolve <IGameTiming>().CurTime; var message = new EffectSystemMessage { EffectSprite = "Effects/explosion.rsi", RsiState = "explosionfast", Born = time, DeathTime = time + TimeSpan.FromSeconds(5), Size = new Vector2(FlashRange / 2, FlashRange / 2), Coordinates = Owner.Transform.GridPosition, //Rotated from east facing Rotation = 0f, ColorDelta = new Vector4(0, 0, 0, -1500f), Color = Vector4.Multiply(new Vector4(255, 255, 255, 750), 0.5f), Shaded = false }; _entitySystemManager.GetEntitySystem <EffectSystem>().CreateParticle(message); _entitySystemManager.GetEntitySystem <AudioSystem>().Play("/Audio/effects/explosion.ogg", Owner); // Knock back cameras of all players in the area. var playerManager = IoCManager.Resolve <IPlayerManager>(); var selfPos = Owner.Transform.WorldPosition; foreach (var player in playerManager.GetAllPlayers()) { if (player.AttachedEntity == null || player.AttachedEntity.Transform.MapID != mapGrid.ParentMapId || !player.AttachedEntity.TryGetComponent(out CameraRecoilComponent recoil)) { continue; } var playerPos = player.AttachedEntity.Transform.WorldPosition; var delta = selfPos - playerPos; var distance = delta.LengthSquared; var effect = 1 / (1 + 0.2f * distance); if (effect > 0.01f) { var kick = -delta.Normalized * effect; recoil.Kick(kick); } } Owner.Delete(); return(true); }
private void TryCreatePackage(EntityUid user, UiAction action, string label, int pillAmount, int bottleAmount) { if (BufferSolution.TotalVolume == 0) { user.PopupMessageCursor(Loc.GetString("chem-master-window-buffer-empty-text")); return; } var handSys = _sysMan.GetEntitySystem <SharedHandsSystem>(); var solSys = _sysMan.GetEntitySystem <SolutionContainerSystem>(); if (action == UiAction.CreateBottles) { var individualVolume = BufferSolution.TotalVolume / FixedPoint2.New(bottleAmount); if (individualVolume < FixedPoint2.New(1)) { user.PopupMessageCursor(Loc.GetString("chem-master-window-buffer-low-text")); return; } var actualVolume = FixedPoint2.Min(individualVolume, FixedPoint2.New(30)); for (int i = 0; i < bottleAmount; i++) { var bottle = _entities.SpawnEntity("ChemistryEmptyBottle01", _entities.GetComponent <TransformComponent>(Owner).Coordinates); //Adding label LabelComponent labelComponent = bottle.EnsureComponent <LabelComponent>(); labelComponent.OriginalName = _entities.GetComponent <MetaDataComponent>(bottle).EntityName; string val = _entities.GetComponent <MetaDataComponent>(bottle).EntityName + $" ({label})"; _entities.GetComponent <MetaDataComponent>(bottle).EntityName = val; labelComponent.CurrentLabel = label; var bufferSolution = BufferSolution.SplitSolution(actualVolume); var bottleSolution = solSys.EnsureSolution(bottle, "drink"); solSys.TryAddSolution(bottle, bottleSolution, bufferSolution); //Try to give them the bottle handSys.PickupOrDrop(user, bottle); } } else //Pills { var individualVolume = BufferSolution.TotalVolume / FixedPoint2.New(pillAmount); if (individualVolume < FixedPoint2.New(1)) { user.PopupMessageCursor(Loc.GetString("chem-master-window-buffer-low-text")); return; } var actualVolume = FixedPoint2.Min(individualVolume, FixedPoint2.New(50)); for (int i = 0; i < pillAmount; i++) { var pill = _entities.SpawnEntity("Pill", _entities.GetComponent <TransformComponent>(Owner).Coordinates); //Adding label LabelComponent labelComponent = pill.EnsureComponent <LabelComponent>(); labelComponent.OriginalName = _entities.GetComponent <MetaDataComponent>(pill).EntityName; string val = _entities.GetComponent <MetaDataComponent>(pill).EntityName + $" ({label})"; _entities.GetComponent <MetaDataComponent>(pill).EntityName = val; labelComponent.CurrentLabel = label; var bufferSolution = BufferSolution.SplitSolution(actualVolume); var pillSolution = EntitySystem.Get <SolutionContainerSystem>().EnsureSolution(pill, "food"); solSys.TryAddSolution(pill, pillSolution, bufferSolution); //Change pill Sprite component state if (!_entities.TryGetComponent(pill, out SpriteComponent? sprite)) { return; } sprite?.LayerSetState(0, "pill" + _pillType); //Try to give them the bottle handSys.PickupOrDrop(user, pill); } } if (_bufferSolution?.Contents.Count == 0) { _label = ""; } UpdateUserInterface(); }
public override void FrameUpdate(FrameEventArgs e) { base.FrameUpdate(e); // If there is no local player, there is no session, and therefore nothing to do here. var localPlayer = PlayerManager.LocalPlayer; if (localPlayer == null) { return; } var mousePosWorld = EyeManager.ScreenToMap(InputManager.MouseScreenPosition); var entityToClick = UserInterfaceManager.CurrentlyHovered != null ? null : GetEntityUnderPosition(mousePosWorld); var inRange = false; if (localPlayer.ControlledEntity != null && entityToClick != null) { var playerPos = localPlayer.ControlledEntity.Transform.MapPosition; var entityPos = entityToClick.Transform.MapPosition; inRange = EntitySystemManager.GetEntitySystem <SharedInteractionSystem>() .InRangeUnobstructed(playerPos, entityPos, predicate: entity => entity == localPlayer.ControlledEntity || entity == entityToClick, ignoreInsideBlocker: true); } InteractionOutlineComponent outline; if (!ConfigurationManager.GetCVar <bool>("outline.enabled")) { if (entityToClick != null && entityToClick.TryGetComponent(out outline)) { outline.OnMouseLeave(); //Prevent outline remains from persisting post command. } return; } if (entityToClick == _lastHoveredEntity) { if (entityToClick != null && entityToClick.TryGetComponent(out outline)) { outline.UpdateInRange(inRange); } return; } if (_lastHoveredEntity != null && !_lastHoveredEntity.Deleted && _lastHoveredEntity.TryGetComponent(out outline)) { outline.OnMouseLeave(); } _lastHoveredEntity = entityToClick; if (_lastHoveredEntity != null && _lastHoveredEntity.TryGetComponent(out outline)) { outline.OnMouseEnter(inRange); } }
void TryStartStructureConstruction(GridCoordinates loc, string prototypeName, Angle angle, int ack) { var prototype = _prototypeManager.Index <ConstructionPrototype>(prototypeName); var transform = Owner.Transform; if (!loc.InRange(_mapManager, transform.GridPosition, InteractionSystem.InteractionRange)) { return; } if (prototype.Stages.Count < 2) { throw new InvalidOperationException($"Prototype '{prototypeName}' does not have enough stages."); } var stage0 = prototype.Stages[0]; if (!(stage0.Forward is ConstructionStepMaterial matStep)) { throw new NotImplementedException(); } // Try to find the stack with the material in the user's hand. var hands = Owner.GetComponent <HandsComponent>(); var activeHand = hands.GetActiveHand?.Owner; if (activeHand == null) { return; } if (!activeHand.TryGetComponent(out StackComponent stack) || !ConstructionComponent.MaterialStackValidFor(matStep, stack)) { return; } if (!stack.Use(matStep.Amount)) { return; } // OK WE'RE GOOD CONSTRUCTION STARTED. _entitySystemManager.GetEntitySystem <AudioSystem>().Play("/Audio/items/deconstruct.ogg", loc); if (prototype.Stages.Count == 2) { // Exactly 2 stages, so don't make an intermediate frame. var ent = _serverEntityManager.SpawnEntity(prototype.Result, loc); ent.Transform.LocalRotation = angle; } else { var frame = _serverEntityManager.SpawnEntity("structureconstructionframe", loc); var construction = frame.GetComponent <ConstructionComponent>(); construction.Init(prototype); frame.Transform.LocalRotation = angle; } var msg = new AckStructureConstructionMessage(ack); SendNetworkMessage(msg); }
/// <inheritdoc /> public void SendGameStateUpdate() { DebugTools.Assert(_networkManager.IsServer); _entityManager.Update(); if (!_networkManager.IsConnected) { // Prevent deletions piling up if we have no clients. _entityManager.CullDeletionHistory(GameTick.MaxValue); _mapManager.CullDeletionHistory(GameTick.MaxValue); return; } var inputSystem = _systemManager.GetEntitySystem <InputSystem>(); var oldestAck = GameTick.MaxValue; foreach (var channel in _networkManager.Channels) { var session = _playerManager.GetSessionByChannel(channel); if (session == null || session.Status != SessionStatus.InGame) { // client still joining, maybe iterate over sessions instead? continue; } if (!_ackedStates.TryGetValue(channel.ConnectionId, out var lastAck)) { DebugTools.Assert("Why does this channel not have an entry?"); } var entStates = lastAck == GameTick.Zero || !PvsEnabled ? _entityManager.GetEntityStates(lastAck) : _entityManager.UpdatePlayerSeenEntityStates(lastAck, session, _entityManager.MaxUpdateRange); var playerStates = _playerManager.GetPlayerStates(lastAck); var deletions = _entityManager.GetDeletedEntities(lastAck); var mapData = _mapManager.GetStateData(lastAck); // lastAck varies with each client based on lag and such, we can't just make 1 global state and send it to everyone var lastInputCommand = inputSystem.GetLastInputCommand(session); var lastSystemMessage = _entityNetworkManager.GetLastMessageSequence(session); var state = new GameState(lastAck, _gameTiming.CurTick, Math.Max(lastInputCommand, lastSystemMessage), entStates, playerStates, deletions, mapData); if (lastAck < oldestAck) { oldestAck = lastAck; } // actually send the state var stateUpdateMessage = _networkManager.CreateNetMessage <MsgState>(); stateUpdateMessage.State = state; _networkManager.ServerSendMessage(stateUpdateMessage, channel); // If the state is too big we let Lidgren send it reliably. // This is to avoid a situation where a state is so large that it consistently gets dropped // (or, well, part of it). // When we send them reliably, we immediately update the ack so that the next state will not be huge. if (stateUpdateMessage.ShouldSendReliably()) { _ackedStates[channel.ConnectionId] = _gameTiming.CurTick; } } // keep the deletion history buffers clean if (oldestAck > _lastOldestAck) { _lastOldestAck = oldestAck; _entityManager.CullDeletionHistory(oldestAck); _mapManager.CullDeletionHistory(oldestAck); } }
private bool TryBuckle(IEntity user, IEntity to) { if (user == null || user == to) { return(false); } if (!ActionBlockerSystem.CanInteract(user)) { _notifyManager.PopupMessage(user, user, Loc.GetString("You can't do that!")); return(false); } var strapPosition = Owner.Transform.MapPosition; var range = SharedInteractionSystem.InteractionRange / 2; if (!InteractionChecks.InRangeUnobstructed(user, strapPosition, range)) { _notifyManager.PopupMessage(user, user, Loc.GetString("You can't reach there!")); return(false); } if (!user.TryGetComponent(out HandsComponent hands)) { _notifyManager.PopupMessage(user, user, Loc.GetString("You don't have hands!")); return(false); } if (hands.GetActiveHand != null) { _notifyManager.PopupMessage(user, user, Loc.GetString("Your hand isn't free!")); return(false); } if (BuckledTo != null) { _notifyManager.PopupMessage(Owner, user, Loc.GetString(Owner == user ? "You are already buckled in!" : "{0:They} are already buckled in!", Owner)); return(false); } if (!to.TryGetComponent(out StrapComponent strap)) { _notifyManager.PopupMessage(Owner, user, Loc.GetString(Owner == user ? "You can't buckle yourself there!" : "You can't buckle {0:them} there!", Owner)); return(false); } var parent = to.Transform.Parent; while (parent != null) { if (parent == user.Transform) { _notifyManager.PopupMessage(Owner, user, Loc.GetString(Owner == user ? "You can't buckle yourself there!" : "You can't buckle {0:them} there!", Owner)); return(false); } parent = parent.Parent; } if (!strap.HasSpace(this)) { _notifyManager.PopupMessage(Owner, user, Loc.GetString(Owner == user ? "You can't fit there!" : "{0:They} can't fit there!", Owner)); return(false); } _entitySystem.GetEntitySystem <AudioSystem>() .PlayFromEntity(strap.BuckleSound, Owner); if (!strap.TryAdd(this)) { _notifyManager.PopupMessage(Owner, user, Loc.GetString(Owner == user ? "You can't buckle yourself there!" : "You can't buckle {0:them} there!", Owner)); return(false); } BuckledTo = strap; if (Owner.TryGetComponent(out AppearanceComponent appearance)) { appearance.SetData(BuckleVisuals.Buckled, true); } var ownTransform = Owner.Transform; var strapTransform = strap.Owner.Transform; ownTransform.GridPosition = strapTransform.GridPosition; ownTransform.AttachParent(strapTransform); switch (strap.Position) { case StrapPosition.None: ownTransform.WorldRotation = strapTransform.WorldRotation; break; case StrapPosition.Stand: StandingStateHelper.Standing(Owner); ownTransform.WorldRotation = strapTransform.WorldRotation; break; case StrapPosition.Down: StandingStateHelper.Down(Owner); ownTransform.WorldRotation = Angle.South; break; } BuckleStatus(); return(true); }
/// <summary> /// Places item in user's active hand to an inventory slot. /// </summary> private async void PlaceActiveHandItemInInventory(EntityUid user, string slot) { var userHands = _entities.GetComponent <HandsComponent>(user); var invSystem = _sysMan.GetEntitySystem <InventorySystem>(); var handSys = _sysMan.GetEntitySystem <SharedHandsSystem>(); bool Check() { if (userHands.ActiveHand?.HeldEntity is not EntityUid held) { user.PopupMessageCursor(Loc.GetString("strippable-component-not-holding-anything")); return(false); } if (!handSys.CanDropHeld(user, userHands.ActiveHand)) { user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-drop")); return(false); } if (!invSystem.HasSlot(Owner, slot)) { return(false); } if (invSystem.TryGetSlotEntity(Owner, slot, out _)) { user.PopupMessageCursor(Loc.GetString("strippable-component-item-slot-occupied", ("owner", Owner))); return(false); } if (!invSystem.CanEquip(user, Owner, held, slot, out _)) { user.PopupMessageCursor(Loc.GetString("strippable-component-cannot-equip-message", ("owner", Owner))); return(false); } return(true); } var doAfterSystem = EntitySystem.Get <DoAfterSystem>(); var doAfterArgs = new DoAfterEventArgs(user, StripDelay, CancellationToken.None, Owner) { ExtraCheck = Check, BreakOnStun = true, BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = true, }; var result = await doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) { return; } if (userHands.ActiveHand?.HeldEntity is EntityUid held && handSys.TryDrop(user, userHands.ActiveHand, handsComp: userHands)) { invSystem.TryEquip(user, Owner, held, slot); } UpdateState(); }