| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- using Content.Shared.Hands.EntitySystems;
- using Content.Shared.Interaction;
- using Content.Shared.Verbs;
- using Content.Shared.Examine;
- using Content.Shared.Item.ItemToggle.Components;
- using Content.Shared.Storage;
- using JetBrains.Annotations;
- using Robust.Shared.Containers;
- using Robust.Shared.GameStates;
- using Robust.Shared.Prototypes;
- using Robust.Shared.Utility;
- namespace Content.Shared.Item;
- public abstract class SharedItemSystem : EntitySystem
- {
- [Dependency] private readonly IPrototypeManager _prototype = default!;
- [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
- [Dependency] protected readonly SharedContainerSystem Container = default!;
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent<ItemComponent, GetVerbsEvent<InteractionVerb>>(AddPickupVerb);
- SubscribeLocalEvent<ItemComponent, InteractHandEvent>(OnHandInteract);
- SubscribeLocalEvent<ItemComponent, AfterAutoHandleStateEvent>(OnItemAutoState);
- SubscribeLocalEvent<ItemComponent, ExaminedEvent>(OnExamine);
- SubscribeLocalEvent<ItemToggleSizeComponent, ItemToggledEvent>(OnItemToggle);
- }
- private void OnItemAutoState(EntityUid uid, ItemComponent component, ref AfterAutoHandleStateEvent args)
- {
- SetHeldPrefix(uid, component.HeldPrefix, force: true, component);
- }
- #region Public API
- public void SetSize(EntityUid uid, ProtoId<ItemSizePrototype> size, ItemComponent? component = null)
- {
- if (!Resolve(uid, ref component, false))
- return;
- component.Size = size;
- Dirty(uid, component);
- }
- public void SetShape(EntityUid uid, List<Box2i>? shape, ItemComponent? component = null)
- {
- if (!Resolve(uid, ref component, false))
- return;
- component.Shape = shape;
- Dirty(uid, component);
- }
- public void SetHeldPrefix(EntityUid uid, string? heldPrefix, bool force = false, ItemComponent? component = null)
- {
- if (!Resolve(uid, ref component, false))
- return;
- if (!force && component.HeldPrefix == heldPrefix)
- return;
- component.HeldPrefix = heldPrefix;
- Dirty(uid, component);
- VisualsChanged(uid);
- }
- /// <summary>
- /// Copy all item specific visuals from another item.
- /// </summary>
- public void CopyVisuals(EntityUid uid, ItemComponent otherItem, ItemComponent? item = null)
- {
- if (!Resolve(uid, ref item))
- return;
- item.RsiPath = otherItem.RsiPath;
- item.InhandVisuals = otherItem.InhandVisuals;
- item.HeldPrefix = otherItem.HeldPrefix;
- Dirty(uid, item);
- VisualsChanged(uid);
- }
- #endregion
- private void OnHandInteract(EntityUid uid, ItemComponent component, InteractHandEvent args)
- {
- if (args.Handled)
- return;
- args.Handled = _handsSystem.TryPickup(args.User, uid, animateUser: false);
- }
- private void AddPickupVerb(EntityUid uid, ItemComponent component, GetVerbsEvent<InteractionVerb> args)
- {
- if (args.Hands == null ||
- args.Using != null ||
- !args.CanAccess ||
- !args.CanInteract ||
- !_handsSystem.CanPickupAnyHand(args.User, args.Target, handsComp: args.Hands, item: component))
- return;
- InteractionVerb verb = new();
- verb.Act = () => _handsSystem.TryPickupAnyHand(args.User, args.Target, checkActionBlocker: false,
- handsComp: args.Hands, item: component);
- verb.Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/pickup.svg.192dpi.png"));
- // if the item already in a container (that is not the same as the user's), then change the text.
- // this occurs when the item is in their inventory or in an open backpack
- Container.TryGetContainingContainer((args.User, null, null), out var userContainer);
- if (Container.TryGetContainingContainer((args.Target, null, null), out var container) && container != userContainer)
- verb.Text = Loc.GetString("pick-up-verb-get-data-text-inventory");
- else
- verb.Text = Loc.GetString("pick-up-verb-get-data-text");
- args.Verbs.Add(verb);
- }
- private void OnExamine(EntityUid uid, ItemComponent component, ExaminedEvent args)
- {
- // show at end of message generally
- args.PushMarkup(Loc.GetString("item-component-on-examine-size",
- ("size", GetItemSizeLocale(component.Size))), priority: -1);
- }
- public ItemSizePrototype GetSizePrototype(ProtoId<ItemSizePrototype> id)
- {
- return _prototype.Index(id);
- }
- /// <summary>
- /// Notifies any entity that is holding or wearing this item that they may need to update their sprite.
- /// </summary>
- /// <remarks>
- /// This is used for updating both inhand sprites and clothing sprites, but it's here just cause it needs to
- /// be in one place.
- /// </remarks>
- public virtual void VisualsChanged(EntityUid owner)
- {
- }
- [PublicAPI]
- public string GetItemSizeLocale(ProtoId<ItemSizePrototype> size)
- {
- return Loc.GetString(GetSizePrototype(size).Name);
- }
- [PublicAPI]
- public int GetItemSizeWeight(ProtoId<ItemSizePrototype> size)
- {
- return GetSizePrototype(size).Weight;
- }
- /// <summary>
- /// Gets the default shape of an item.
- /// </summary>
- public IReadOnlyList<Box2i> GetItemShape(Entity<ItemComponent?> uid)
- {
- if (!Resolve(uid, ref uid.Comp))
- return new Box2i[] { };
- return uid.Comp.Shape ?? GetSizePrototype(uid.Comp.Size).DefaultShape;
- }
- /// <summary>
- /// Gets the default shape of an item.
- /// </summary>
- public IReadOnlyList<Box2i> GetItemShape(ItemComponent component)
- {
- return component.Shape ?? GetSizePrototype(component.Size).DefaultShape;
- }
- /// <summary>
- /// Gets the shape of an item, adjusting for rotation and offset.
- /// </summary>
- public IReadOnlyList<Box2i> GetAdjustedItemShape(Entity<ItemComponent?> entity, ItemStorageLocation location)
- {
- return GetAdjustedItemShape(entity, location.Rotation, location.Position);
- }
- /// <summary>
- /// Gets the shape of an item, adjusting for rotation and offset.
- /// </summary>
- public IReadOnlyList<Box2i> GetAdjustedItemShape(Entity<ItemComponent?> entity, Angle rotation, Vector2i position)
- {
- if (!Resolve(entity, ref entity.Comp))
- return new Box2i[] { };
- var shapes = GetItemShape(entity);
- var boundingShape = shapes.GetBoundingBox();
- var boundingCenter = ((Box2) boundingShape).Center;
- var matty = Matrix3Helpers.CreateTransform(boundingCenter, rotation);
- var drift = boundingShape.BottomLeft - matty.TransformBox(boundingShape).BottomLeft;
- var adjustedShapes = new List<Box2i>();
- foreach (var shape in shapes)
- {
- var transformed = matty.TransformBox(shape).Translated(drift);
- var floored = new Box2i(transformed.BottomLeft.Floored(), transformed.TopRight.Floored());
- var translated = floored.Translated(position);
- adjustedShapes.Add(translated);
- }
- return adjustedShapes;
- }
- /// <summary>
- /// Used to update the Item component on item toggle (specifically size).
- /// </summary>
- private void OnItemToggle(EntityUid uid, ItemToggleSizeComponent itemToggleSize, ItemToggledEvent args)
- {
- if (!TryComp(uid, out ItemComponent? item))
- return;
- if (args.Activated)
- {
- if (itemToggleSize.ActivatedShape != null)
- {
- // Set the deactivated shape to the default item's shape before it gets changed.
- itemToggleSize.DeactivatedShape ??= new List<Box2i>(GetItemShape(item));
- SetShape(uid, itemToggleSize.ActivatedShape, item);
- }
- if (itemToggleSize.ActivatedSize != null)
- {
- // Set the deactivated size to the default item's size before it gets changed.
- itemToggleSize.DeactivatedSize ??= item.Size;
- SetSize(uid, (ProtoId<ItemSizePrototype>) itemToggleSize.ActivatedSize, item);
- }
- }
- else
- {
- if (itemToggleSize.DeactivatedShape != null)
- {
- SetShape(uid, itemToggleSize.DeactivatedShape, item);
- }
- if (itemToggleSize.DeactivatedSize != null)
- {
- SetSize(uid, (ProtoId<ItemSizePrototype>) itemToggleSize.DeactivatedSize, item);
- }
- }
- Dirty(uid, item);
- }
- }
|