using Content.Shared.Examine; using Content.Shared.Hands.Components; using Content.Shared.IdentityManagement; using Content.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Players; namespace Content.Shared.Hands.EntitySystems; public abstract partial class SharedHandsSystem : EntitySystem { private void InitializeInteractions() { SubscribeAllEvent(HandleSetHand); SubscribeAllEvent(HandleActivateItemInHand); SubscribeAllEvent(HandleInteractUsingInHand); SubscribeAllEvent(HandleUseInHand); SubscribeAllEvent(HandleMoveItemFromHand); SubscribeAllEvent(HandleHandAltInteract); SubscribeLocalEvent(HandleExamined); CommandBinds.Builder .Bind(ContentKeyFunctions.UseItemInHand, InputCmdHandler.FromDelegate(HandleUseItem, handle: false, outsidePrediction: false)) .Bind(ContentKeyFunctions.AltUseItemInHand, InputCmdHandler.FromDelegate(HandleAltUseInHand, handle: false, outsidePrediction: false)) .Bind(ContentKeyFunctions.SwapHands, InputCmdHandler.FromDelegate(SwapHandsPressed, handle: false, outsidePrediction: false)) .Bind(ContentKeyFunctions.Drop, new PointerInputCmdHandler(DropPressed)) .Register(); } #region Event and Key-binding Handlers private void HandleAltUseInHand(ICommonSession? session) { if (session?.AttachedEntity != null) TryUseItemInHand(session.AttachedEntity.Value, true); } private void HandleUseItem(ICommonSession? session) { if (session?.AttachedEntity != null) TryUseItemInHand(session.AttachedEntity.Value); } private void HandleMoveItemFromHand(RequestMoveHandItemEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity != null) TryMoveHeldEntityToActiveHand(args.SenderSession.AttachedEntity.Value, msg.HandName); } private void HandleUseInHand(RequestUseInHandEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity != null) TryUseItemInHand(args.SenderSession.AttachedEntity.Value); } private void HandleActivateItemInHand(RequestActivateInHandEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity != null) TryActivateItemInHand(args.SenderSession.AttachedEntity.Value, null, msg.HandName); } private void HandleInteractUsingInHand(RequestHandInteractUsingEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity != null) TryInteractHandWithActiveHand(args.SenderSession.AttachedEntity.Value, msg.HandName); } private void HandleHandAltInteract(RequestHandAltInteractEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity != null) TryUseItemInHand(args.SenderSession.AttachedEntity.Value, true, handName: msg.HandName); } private void SwapHandsPressed(ICommonSession? session) { if (!TryComp(session?.AttachedEntity, out SharedHandsComponent? component)) return; if (!_actionBlocker.CanInteract(session.AttachedEntity.Value, null)) return; if (component.ActiveHand == null || component.Hands.Count < 2) return; var newActiveIndex = component.SortedHands.IndexOf(component.ActiveHand.Name) + 1; var nextHand = component.SortedHands[newActiveIndex % component.Hands.Count]; TrySetActiveHand(component.Owner, nextHand, component); } private bool DropPressed(ICommonSession? session, EntityCoordinates coords, EntityUid uid) { if (TryComp(session?.AttachedEntity, out SharedHandsComponent? hands) && hands.ActiveHand != null) TryDrop(session!.AttachedEntity!.Value, hands.ActiveHand, coords, handsComp: hands); // always send to server. return false; } #endregion public bool TryActivateItemInHand(EntityUid uid, SharedHandsComponent? handsComp = null, string? handName = null) { if (!Resolve(uid, ref handsComp, false)) return false; Hand? hand; if (handName == null || !handsComp.Hands.TryGetValue(handName, out hand)) hand = handsComp.ActiveHand; if (hand?.HeldEntity is not { } held) return false; return _interactionSystem.InteractionActivate(uid, held); } public bool TryInteractHandWithActiveHand(EntityUid uid, string handName, SharedHandsComponent? handsComp = null) { if (!Resolve(uid, ref handsComp, false)) return false; if (handsComp.ActiveHandEntity == null) return false; if (!handsComp.Hands.TryGetValue(handName, out var hand)) return false; if (hand.HeldEntity == null) return false; _interactionSystem.InteractUsing(uid, handsComp.ActiveHandEntity.Value, hand.HeldEntity.Value, Transform(hand.HeldEntity.Value).Coordinates); return true; } public bool TryUseItemInHand(EntityUid uid, bool altInteract = false, SharedHandsComponent? handsComp = null, string? handName = null) { if (!Resolve(uid, ref handsComp, false)) return false; Hand? hand; if (handName == null || !handsComp.Hands.TryGetValue(handName, out hand)) hand = handsComp.ActiveHand; if (hand?.HeldEntity is not { } held) return false; if (altInteract) return _interactionSystem.AltInteract(uid, held); else return _interactionSystem.UseInHandInteraction(uid, held); } /// /// Moves an entity from one hand to the active hand. /// public bool TryMoveHeldEntityToActiveHand(EntityUid uid, string handName, bool checkActionBlocker = true, SharedHandsComponent? handsComp = null) { if (!Resolve(uid, ref handsComp)) return false; if (handsComp.ActiveHand == null || !handsComp.ActiveHand.IsEmpty) return false; if (!handsComp.Hands.TryGetValue(handName, out var hand)) return false; if (!CanDropHeld(uid, hand, checkActionBlocker)) return false; var entity = hand.HeldEntity!.Value; if (!CanPickupToHand(uid, entity, handsComp.ActiveHand, checkActionBlocker, handsComp)) return false; DoDrop(uid, hand, false, handsComp); DoPickup(uid, handsComp.ActiveHand, entity, handsComp); return true; } //TODO: Actually shows all items/clothing/etc. private void HandleExamined(EntityUid uid, SharedHandsComponent handsComp, ExaminedEvent args) { foreach (var inhand in EnumerateHeld(uid, handsComp)) { if (HasComp(inhand)) continue; args.PushText(Loc.GetString("comp-hands-examine", ("user", Identity.Entity(handsComp.Owner, EntityManager)), ("item", inhand))); } } }