Delta-v/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs

201 lines
7.7 KiB
C#

using Content.Shared.Actions;
using Content.Shared.DoAfter;
using Content.Shared.Hands;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Content.Shared.Item.PseudoItem;
using Content.Shared.Popups;
using Content.Shared.Storage;
using Content.Shared.Storage.EntitySystems;
using Content.Shared.Tag;
using Content.Shared.Verbs;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
namespace Content.Shared.Nyanotrasen.Item.PseudoItem;
public abstract partial class SharedPseudoItemSystem : EntitySystem
{
[Dependency] private readonly SharedStorageSystem _storage = default!;
[Dependency] private readonly SharedItemSystem _item = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly SharedContainerSystem _container = default!; // Floofstation
[Dependency] private readonly SharedHandsSystem _hands = default!; // Floofstation
private readonly ProtoId<TagPrototype> PreventTag = "PreventLabel";
private readonly EntProtoId SleepActionId = "ActionSleep"; // The action used for sleeping inside bags. Currently uses the default sleep action (same as beds)
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PseudoItemComponent, GetVerbsEvent<InnateVerb>>(AddInsertVerb);
SubscribeLocalEvent<PseudoItemComponent, EntGotRemovedFromContainerMessage>(OnEntRemoved);
SubscribeLocalEvent<PseudoItemComponent, GettingPickedUpAttemptEvent>(OnGettingPickedUpAttempt);
SubscribeLocalEvent<PseudoItemComponent, DropAttemptEvent>(OnDropAttempt);
SubscribeLocalEvent<PseudoItemComponent, ContainerGettingInsertedAttemptEvent>(OnInsertAttempt);
SubscribeLocalEvent<PseudoItemComponent, InteractionAttemptEvent>(OnInteractAttempt);
SubscribeLocalEvent<PseudoItemComponent, PseudoItemInsertDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<PseudoItemComponent, AttackAttemptEvent>(OnAttackAttempt);
}
private void AddInsertVerb(EntityUid uid, PseudoItemComponent component, GetVerbsEvent<InnateVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
return;
if (component.Active)
return;
if (!TryComp<StorageComponent>(args.Target, out var targetStorage))
return;
if (!CheckItemFits((uid, component), (args.Target, targetStorage)))
return;
if (Transform(args.Target).ParentUid == uid)
return;
InnateVerb verb = new()
{
Act = () =>
{
TryInsert(args.Target, uid, component, targetStorage);
},
Text = Loc.GetString("action-name-insert-self"),
Priority = 2
};
args.Verbs.Add(verb);
}
public bool TryInsert(EntityUid storageUid, EntityUid toInsert, PseudoItemComponent component,
StorageComponent? storage = null)
{
if (!Resolve(storageUid, ref storage))
return false;
if (!CheckItemFits((toInsert, component), (storageUid, storage)))
return false;
var itemComp = new ItemComponent
{ Size = component.Size, Shape = component.Shape, StoredOffset = component.StoredOffset };
AddComp(toInsert, itemComp);
_item.VisualsChanged(toInsert);
_tag.TryAddTag(toInsert, PreventTag);
if (!_storage.Insert(storageUid, toInsert, out _, null, storage))
{
component.Active = false;
RemComp<ItemComponent>(toInsert);
return false;
}
// If the storage allows sleeping inside, add the respective action
if (HasComp<AllowsSleepInsideComponent>(storageUid))
_actions.AddAction(toInsert, ref component.SleepAction, SleepActionId, toInsert);
component.Active = true;
return true;
}
private void OnEntRemoved(EntityUid uid, PseudoItemComponent component, EntGotRemovedFromContainerMessage args)
{
if (!component.Active)
return;
RemComp<ItemComponent>(uid);
component.Active = false;
_actions.RemoveAction(uid, component.SleepAction); // Remove sleep action if it was added
}
protected virtual void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component,
GettingPickedUpAttemptEvent args)
{
args.Cancel(); // Floof - this is a terrible idea. This triggers every time ANY system checks if a pseudo-item can be picked up.
// WHY DID YOU DO THAT, NYANOTRASEN???
// if (args.User == args.Item)
// return;
//
// _transform.AttachToGridOrMap(uid);
// args.Cancel();
}
private void OnDropAttempt(EntityUid uid, PseudoItemComponent component, DropAttemptEvent args)
{
if (!component.Active)
return;
// Floof - we try to get the containing container and try to drop it into it
// If possible, we do it, since a bagged cat probably can put things back into the bag just like they can pick them up.
string? failReason = null;
if (_hands.GetActiveItem(uid) is { Valid: true, } droppedItem
&& _container.TryGetContainingContainer(Transform(uid).ParentUid, uid, out var pseudoItemContainer)
&& TryComp<StorageComponent>(pseudoItemContainer.Owner, out var targetStorage)
&& _storage.CanInsert(pseudoItemContainer.Owner, droppedItem, out failReason, targetStorage, ignoreStacks: true)
)
_storage.Insert(pseudoItemContainer.Owner, droppedItem, out _, uid, targetStorage, stackAutomatically: false);
if (failReason != null)
_popupSystem.PopupEntity(Loc.GetString(failReason), uid, uid);
args.Cancel();
}
private void OnInsertAttempt(EntityUid uid, PseudoItemComponent component,
ContainerGettingInsertedAttemptEvent args)
{
if (!component.Active)
return;
// This hopefully shouldn't trigger, but this is a failsafe just in case so we dont bluespace them cats
args.Cancel();
}
// Prevents moving within the bag :)
private void OnInteractAttempt(EntityUid uid, PseudoItemComponent component, InteractionAttemptEvent args)
{
// Floof - why the fuck.
// if (args.Uid == args.Target && component.Active)
// args.Cancelled = true;
}
private void OnDoAfter(EntityUid uid, PseudoItemComponent component, DoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Used == null)
return;
args.Handled = TryInsert(args.Args.Used.Value, uid, component);
}
protected void StartInsertDoAfter(EntityUid inserter, EntityUid toInsert, EntityUid storageEntity,
PseudoItemComponent? pseudoItem = null)
{
if (!Resolve(toInsert, ref pseudoItem))
return;
var ev = new PseudoItemInsertDoAfterEvent();
var args = new DoAfterArgs(EntityManager, inserter, 5f, ev, toInsert, toInsert, storageEntity)
{
BreakOnMove = true,
NeedHand = true
};
if (_doAfter.TryStartDoAfter(args))
{
// Show a popup to the person getting picked up
_popupSystem.PopupEntity(Loc.GetString("carry-started", ("carrier", inserter)), toInsert, toInsert);
}
}
private void OnAttackAttempt(EntityUid uid, PseudoItemComponent component, AttackAttemptEvent args)
{
if (component.Active)
args.Cancel();
}
}