port better borgs from frontier (#3110)
* BetterBorgs: droppable, swappable cyborg item interactions (#2766) * WIP: droppable, swappable, insertable cyborg items * Half-baked borg HandPlaceholderComponent * cyborg: sprite representation for empty slots * nullable prototype --------- Co-authored-by: Dvir <39403717+dvir001@users.noreply.github.com> * BorgSystem: check droppable items for duped mods (#2887) * BorgSystem: check droppable items for duped mods * Cache item comparer * BorgSystem: Unremoveable after equip (#2854) * raise interaction events to add fibers to things --------- Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com> Co-authored-by: Dvir <39403717+dvir001@users.noreply.github.com> Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
parent
32384762bb
commit
0f3edc0b39
|
|
@ -13,6 +13,7 @@ using Robust.Client.UserInterface.Controllers;
|
|||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared._NF.Interaction.Components;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Hands;
|
||||
|
||||
|
|
@ -138,6 +139,13 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
|
|||
handButton.SetEntity(virt.BlockingEntity);
|
||||
handButton.Blocked = true;
|
||||
}
|
||||
// Frontier - borg hand placeholder
|
||||
else if (_entities.TryGetComponent(hand.HeldEntity, out HandPlaceholderVisualsComponent? placeholder))
|
||||
{
|
||||
handButton.SetEntity(placeholder.Dummy);
|
||||
handButton.Blocked = true;
|
||||
}
|
||||
// End Frontier - borg hand placeholder
|
||||
else
|
||||
{
|
||||
handButton.SetEntity(hand.HeldEntity);
|
||||
|
|
@ -189,6 +197,13 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
|
|||
hand.SetEntity(virt.BlockingEntity);
|
||||
hand.Blocked = true;
|
||||
}
|
||||
// Frontier: borg hand placeholders
|
||||
else if (_entities.TryGetComponent(entity, out HandPlaceholderVisualsComponent? placeholder))
|
||||
{
|
||||
hand.SetEntity(placeholder.Dummy);
|
||||
hand.Blocked = true;
|
||||
}
|
||||
// End Frontier: borg hand placeholders
|
||||
else
|
||||
{
|
||||
hand.SetEntity(entity);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._NF.Hands.UI
|
||||
{
|
||||
public sealed class HandPlaceholderStatus : Control
|
||||
{
|
||||
public HandPlaceholderStatus()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<Control xmlns="https://spacestation14.io">
|
||||
<Label StyleClasses="ItemStatus" Text="{Loc 'hand-placeholder-name'}" />
|
||||
</Control>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
namespace Content.Shared._NF.Interaction.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
// Client-side component of the HandPlaceholder. Creates and tracks a client-side entity for hand blocking visuals
|
||||
public sealed partial class HandPlaceholderVisualsComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid Dummy;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
using Content.Client._NF.Hands.UI;
|
||||
using Content.Client.Items;
|
||||
using Content.Client.Items.Systems;
|
||||
using Content.Shared._NF.Interaction.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
|
||||
namespace Content.Client._NF.Interaction.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Handles interactions with items that spawn HandPlaceholder items.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class HandPlaceholderVisualsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] ContainerSystem _container = default!;
|
||||
[Dependency] ItemSystem _item = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<HandPlaceholderComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
|
||||
|
||||
SubscribeLocalEvent<HandPlaceholderVisualsComponent, ComponentRemove>(PlaceholderRemove);
|
||||
|
||||
Subs.ItemStatus<HandPlaceholderVisualsComponent>(_ => new HandPlaceholderStatus());
|
||||
}
|
||||
|
||||
private void OnAfterAutoHandleState(Entity<HandPlaceholderComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
if (!TryComp(ent, out HandPlaceholderVisualsComponent? placeholder))
|
||||
return;
|
||||
|
||||
if (placeholder.Dummy != EntityUid.Invalid)
|
||||
QueueDel(placeholder.Dummy);
|
||||
placeholder.Dummy = Spawn(ent.Comp.Prototype);
|
||||
|
||||
if (_container.IsEntityInContainer(ent))
|
||||
_item.VisualsChanged(ent);
|
||||
}
|
||||
|
||||
private void PlaceholderRemove(Entity<HandPlaceholderVisualsComponent> ent, ref ComponentRemove args)
|
||||
{
|
||||
if (ent.Comp.Dummy != EntityUid.Invalid)
|
||||
QueueDel(ent.Comp.Dummy);
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,8 @@ public sealed class PrototypeSaveTest
|
|||
{
|
||||
// The only prototypes that should get ignored are those that REQUIRE setup to get a sprite. At that point it is
|
||||
// the responsibility of the spawner to ensure that a valid sprite is set.
|
||||
"VirtualItem"
|
||||
"VirtualItem",
|
||||
"HandPlaceholder" // Frontier
|
||||
};
|
||||
|
||||
[Test]
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Content.Shared.Interaction.Components;
|
|||
using Content.Shared.Silicons.Borgs.Components;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Containers;
|
||||
using Content.Shared._NF.Interaction.Components; // Frontier
|
||||
|
||||
namespace Content.Server.Silicons.Borgs;
|
||||
|
||||
|
|
@ -197,6 +198,7 @@ public sealed partial class BorgSystem
|
|||
if (!component.ItemsCreated)
|
||||
{
|
||||
item = Spawn(itemProto, xform.Coordinates);
|
||||
_interaction.DoContactInteraction(chassis, item); // DeltaV - give items fibers before they might be dropped
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -225,6 +227,63 @@ public sealed partial class BorgSystem
|
|||
component.ProvidedItems.Add(handId, item);
|
||||
}
|
||||
|
||||
// Frontier: droppable cyborg items
|
||||
foreach (var itemProto in component.DroppableItems)
|
||||
{
|
||||
EntityUid item;
|
||||
|
||||
if (!component.ItemsCreated)
|
||||
{
|
||||
item = Spawn(itemProto.ID, xform.Coordinates);
|
||||
var placeComp = EnsureComp<HandPlaceholderRemoveableComponent>(item);
|
||||
placeComp.Whitelist = itemProto.Whitelist;
|
||||
placeComp.Prototype = itemProto.ID;
|
||||
Dirty(item, placeComp);
|
||||
}
|
||||
else
|
||||
{
|
||||
item = component.ProvidedContainer.ContainedEntities
|
||||
.FirstOrDefault(ent => _whitelistSystem.IsWhitelistPassOrNull(itemProto.Whitelist, ent) || TryComp<HandPlaceholderComponent>(ent, out var placeholder));
|
||||
if (!item.IsValid())
|
||||
{
|
||||
Log.Debug($"no items found: {component.ProvidedContainer.ContainedEntities.Count}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Just in case, make sure the borg can't drop the placeholder.
|
||||
if (!HasComp<HandPlaceholderComponent>(item))
|
||||
{
|
||||
var placeComp = EnsureComp<HandPlaceholderRemoveableComponent>(item);
|
||||
placeComp.Whitelist = itemProto.Whitelist;
|
||||
placeComp.Prototype = itemProto.ID;
|
||||
Dirty(item, placeComp);
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.IsValid())
|
||||
{
|
||||
Log.Debug("no valid item");
|
||||
continue;
|
||||
}
|
||||
|
||||
var handId = $"{uid}-item{component.HandCounter}";
|
||||
component.HandCounter++;
|
||||
_hands.AddHand(chassis, handId, HandLocation.Middle, hands);
|
||||
_hands.DoPickup(chassis, hands.Hands[handId], item, hands);
|
||||
if (hands.Hands[handId].HeldEntity != item)
|
||||
{
|
||||
// If we didn't pick up our expected item, delete the hand. No free hands!
|
||||
_hands.RemoveHand(chassis, handId);
|
||||
}
|
||||
else if (HasComp<HandPlaceholderComponent>(item))
|
||||
{
|
||||
// Placeholders can't be put down, must be changed after picked up (otherwise it'll fail to pick up)
|
||||
EnsureComp<UnremoveableComponent>(item);
|
||||
}
|
||||
component.DroppableProvidedItems.Add(handId, (item, itemProto));
|
||||
}
|
||||
// End Frontier: droppable cyborg items
|
||||
|
||||
component.ItemsCreated = true;
|
||||
}
|
||||
|
||||
|
|
@ -244,6 +303,14 @@ public sealed partial class BorgSystem
|
|||
_hands.RemoveHand(chassis, hand, hands);
|
||||
}
|
||||
component.ProvidedItems.Clear();
|
||||
// Frontier: droppable items
|
||||
foreach (var (hand, item) in component.DroppableProvidedItems)
|
||||
{
|
||||
QueueDel(item.Item1);
|
||||
_hands.RemoveHand(chassis, hand, hands);
|
||||
}
|
||||
component.DroppableProvidedItems.Clear();
|
||||
// End Frontier: droppable items
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -257,6 +324,20 @@ public sealed partial class BorgSystem
|
|||
_hands.RemoveHand(chassis, handId, hands);
|
||||
}
|
||||
component.ProvidedItems.Clear();
|
||||
// Frontier: remove all items from borg hands directly, not from the provided items set
|
||||
foreach (var (handId, _) in component.DroppableProvidedItems)
|
||||
{
|
||||
_hands.TryGetHand(chassis, handId, out var hand, hands);
|
||||
if (hand?.HeldEntity != null)
|
||||
{
|
||||
RemComp<UnremoveableComponent>(hand.HeldEntity.Value);
|
||||
_container.Insert(hand.HeldEntity.Value, component.ProvidedContainer);
|
||||
}
|
||||
|
||||
_hands.RemoveHand(chassis, handId, hands);
|
||||
}
|
||||
component.DroppableProvidedItems.Clear();
|
||||
// End Frontier
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -283,13 +364,16 @@ public sealed partial class BorgSystem
|
|||
|
||||
if (TryComp<ItemBorgModuleComponent>(module, out var itemModuleComp))
|
||||
{
|
||||
var droppableComparer = new DroppableBorgItemComparer(); // Frontier: cached comparer
|
||||
foreach (var containedModuleUid in component.ModuleContainer.ContainedEntities)
|
||||
{
|
||||
if (!TryComp<ItemBorgModuleComponent>(containedModuleUid, out var containedItemModuleComp))
|
||||
continue;
|
||||
|
||||
if (containedItemModuleComp.Items.Count == itemModuleComp.Items.Count &&
|
||||
containedItemModuleComp.Items.All(itemModuleComp.Items.Contains))
|
||||
containedItemModuleComp.DroppableItems.Count == itemModuleComp.DroppableItems.Count && // Frontier
|
||||
containedItemModuleComp.Items.All(itemModuleComp.Items.Contains) &&
|
||||
containedItemModuleComp.DroppableItems.All(x => itemModuleComp.DroppableItems.Contains(x, droppableComparer))) // Frontier
|
||||
{
|
||||
if (user != null)
|
||||
Popup.PopupEntity(Loc.GetString("borg-module-duplicate"), uid, user.Value);
|
||||
|
|
@ -301,6 +385,30 @@ public sealed partial class BorgSystem
|
|||
return true;
|
||||
}
|
||||
|
||||
// Frontier: droppable borg item comparator
|
||||
private sealed class DroppableBorgItemComparer : IEqualityComparer<DroppableBorgItem>
|
||||
{
|
||||
public bool Equals(DroppableBorgItem? x, DroppableBorgItem? y)
|
||||
{
|
||||
// Same object (or both null)
|
||||
if (ReferenceEquals(x, y))
|
||||
return true;
|
||||
// One-side null
|
||||
if (x == null || y == null)
|
||||
return false;
|
||||
// Otherwise, use EntProtoId of item
|
||||
return x.ID == y.ID;
|
||||
}
|
||||
|
||||
public int GetHashCode(DroppableBorgItem obj)
|
||||
{
|
||||
if (obj is null)
|
||||
return 0;
|
||||
return obj.ID.GetHashCode();
|
||||
}
|
||||
}
|
||||
// End Frontier
|
||||
|
||||
/// <summary>
|
||||
/// Check if a module can be removed from a borg.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
|
|||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interaction = default!; // DeltaV
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Content.Server._NF.Whitelist.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Whitelist component for book bags to avoid tag redefinition and collisions
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class NFBookBagComponent : Component;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Content.Server._NF.Whitelist.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Whitelist component for lighters to avoid tag redefinition and collisions
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class NFLighterComponent : Component;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Content.Server._NF.Whitelist.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Whitelist component for ore bags to avoid tag redefinition and collisions
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class NFOreBagComponent : Component;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Content.Server._NF.Whitelist.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Whitelist component for plant bags to avoid tag redefinition and collisions
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class NFPlantBagComponent : Component;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
namespace Content.Server._NF.Whitelist.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Whitelist component for shakers to avoid tag redefinition and collisions
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class NFShakerComponent : Component;
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Interaction.Components
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Robust.Shared.Containers;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
|
@ -14,15 +15,27 @@ public sealed partial class ItemBorgModuleComponent : Component
|
|||
/// <summary>
|
||||
/// The items that are provided.
|
||||
/// </summary>
|
||||
[DataField("items", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>), required: true)]
|
||||
[DataField("items", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))] // Frontier: removed
|
||||
public List<string> Items = new();
|
||||
|
||||
/// <summary>
|
||||
/// Frontier: The droppable items that are provided.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<DroppableBorgItem> DroppableItems = new();
|
||||
|
||||
/// <summary>
|
||||
/// The entities from <see cref="Items"/> that were spawned.
|
||||
/// </summary>
|
||||
[DataField("providedItems")]
|
||||
public SortedDictionary<string, EntityUid> ProvidedItems = new();
|
||||
|
||||
/// <summary>
|
||||
/// The entities from <see cref="Items"/> that were spawned.
|
||||
/// </summary>
|
||||
[DataField("droppableProvidedItems")]
|
||||
public SortedDictionary<string, (EntityUid, DroppableBorgItem)> DroppableProvidedItems = new();
|
||||
|
||||
/// <summary>
|
||||
/// A counter that ensures a unique
|
||||
/// </summary>
|
||||
|
|
@ -49,3 +62,13 @@ public sealed partial class ItemBorgModuleComponent : Component
|
|||
public string ProvidedContainerId = "provided_container";
|
||||
}
|
||||
|
||||
// Frontier: droppable borg item data definitions
|
||||
[DataDefinition]
|
||||
public sealed partial class DroppableBorgItem
|
||||
{
|
||||
[IdDataField]
|
||||
public EntProtoId ID;
|
||||
|
||||
[DataField]
|
||||
public EntityWhitelist Whitelist;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._NF.Interaction.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent]
|
||||
[AutoGenerateComponentState(true)]
|
||||
// When an entity with this is removed from a hand, it is replaced with a placeholder entity that blocks the hand's use until re-equipped with the same prototype.
|
||||
public sealed partial class HandPlaceholderComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// A whitelist to match entities that this should accept.
|
||||
/// </summary>
|
||||
[ViewVariables, AutoNetworkedField]
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
[ViewVariables, AutoNetworkedField]
|
||||
public EntProtoId? Prototype;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._NF.Interaction.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent]
|
||||
// When an entity with this is removed from a hand, it is replaced with a placeholder entity that blocks the hand's use until re-equipped with the same prototype.
|
||||
public sealed partial class HandPlaceholderRemoveableComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
[DataField]
|
||||
public EntProtoId? Prototype;
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
using Content.Shared._NF.Interaction.Components;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Whitelist;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._NF.Interaction.Systems;
|
||||
|
||||
/// <summary>
|
||||
/// Handles interactions with items that spawn HandPlaceholder items.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class HandPlaceholderSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interaction = default!; // DeltaV
|
||||
[Dependency] private readonly SharedItemSystem _item = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<HandPlaceholderRemoveableComponent, GotUnequippedHandEvent>(OnUnequipHand);
|
||||
SubscribeLocalEvent<HandPlaceholderRemoveableComponent, DroppedEvent>(OnDropped);
|
||||
|
||||
SubscribeLocalEvent<HandPlaceholderComponent, AfterInteractEvent>(AfterInteract);
|
||||
SubscribeLocalEvent<HandPlaceholderComponent, BeforeRangedInteractEvent>(BeforeRangedInteract);
|
||||
}
|
||||
|
||||
private void OnUnequipHand(Entity<HandPlaceholderRemoveableComponent> ent, ref GotUnequippedHandEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return; // If this is happening in practice, this is a bug.
|
||||
|
||||
SpawnAndPickUpPlaceholder(ent, args.User);
|
||||
RemCompDeferred<HandPlaceholderRemoveableComponent>(ent);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnDropped(Entity<HandPlaceholderRemoveableComponent> ent, ref DroppedEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return; // If this is happening in practice, this is a bug.
|
||||
|
||||
SpawnAndPickUpPlaceholder(ent, args.User);
|
||||
RemCompDeferred<HandPlaceholderRemoveableComponent>(ent);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void SpawnAndPickUpPlaceholder(Entity<HandPlaceholderRemoveableComponent> ent, EntityUid user)
|
||||
{
|
||||
if (_net.IsServer)
|
||||
{
|
||||
var placeholder = Spawn("HandPlaceholder");
|
||||
if (TryComp<HandPlaceholderComponent>(placeholder, out var placeComp))
|
||||
{
|
||||
placeComp.Whitelist = ent.Comp.Whitelist;
|
||||
placeComp.Prototype = ent.Comp.Prototype;
|
||||
Dirty(placeholder, placeComp);
|
||||
}
|
||||
|
||||
if (_proto.TryIndex(ent.Comp.Prototype, out var itemProto))
|
||||
_metadata.SetEntityName(placeholder, itemProto.Name);
|
||||
|
||||
if (!_hands.TryPickup(user, placeholder)) // Can we get the hand this came from?
|
||||
QueueDel(placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
private void BeforeRangedInteract(Entity<HandPlaceholderComponent> ent, ref BeforeRangedInteractEvent args)
|
||||
{
|
||||
if (args.Target == null || args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
TryToPickUpTarget(ent, args.Target.Value, args.User);
|
||||
}
|
||||
|
||||
private void AfterInteract(Entity<HandPlaceholderComponent> ent, ref AfterInteractEvent args)
|
||||
{
|
||||
if (args.Target == null || args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
TryToPickUpTarget(ent, args.Target.Value, args.User);
|
||||
}
|
||||
|
||||
private void TryToPickUpTarget(Entity<HandPlaceholderComponent> ent, EntityUid target, EntityUid user)
|
||||
{
|
||||
if (_whitelist.IsWhitelistFail(ent.Comp.Whitelist, target))
|
||||
return;
|
||||
|
||||
// Can't get the hand we're holding this with? Something's wrong, abort. No empty hands.
|
||||
if (!_hands.IsHolding(user, ent, out var hand))
|
||||
return;
|
||||
|
||||
// Cache the whitelist/prototype, entity might be deleted.
|
||||
var whitelist = ent.Comp.Whitelist;
|
||||
var prototype = ent.Comp.Prototype;
|
||||
|
||||
if (_net.IsServer)
|
||||
Del(ent);
|
||||
|
||||
_hands.DoPickup(user, hand, target); // Force pickup - empty hands are not okay
|
||||
var placeComp = EnsureComp<HandPlaceholderRemoveableComponent>(target);
|
||||
placeComp.Whitelist = whitelist;
|
||||
placeComp.Prototype = prototype;
|
||||
Dirty(target, placeComp);
|
||||
_interaction.DoContactInteraction(user, target); // DeltaV - borgs picking up items leaves fibers
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
hand-placeholder-name = Module slot for
|
||||
|
|
@ -39,6 +39,7 @@
|
|||
mixOnInteract: false
|
||||
reactionTypes:
|
||||
- Shake
|
||||
- type: NFShaker # Frontier
|
||||
|
||||
- type: entity
|
||||
parent: DrinkGlassBase
|
||||
|
|
|
|||
|
|
@ -157,3 +157,4 @@
|
|||
difficulty: 2
|
||||
recipes:
|
||||
- PlantBagOfHolding
|
||||
- type: NFPlantBag # Frontier
|
||||
|
|
|
|||
|
|
@ -28,3 +28,4 @@
|
|||
- TabletopBoard
|
||||
- Write
|
||||
- type: Dumpable
|
||||
- type: NFBookBag # Frontier
|
||||
|
|
|
|||
|
|
@ -134,8 +134,13 @@
|
|||
- state: generic
|
||||
- state: icon-fire-extinguisher
|
||||
- type: ItemBorgModule
|
||||
items:
|
||||
- FireExtinguisher
|
||||
# Frontier: droppable borg items
|
||||
droppableItems:
|
||||
- id: FireExtinguisher
|
||||
whitelist:
|
||||
tags:
|
||||
- FireExtinguisher
|
||||
# End Frontier
|
||||
- type: BorgModuleIcon
|
||||
icon: { sprite: Interface/Actions/actions_borg.rsi, state: extinguisher-module }
|
||||
|
||||
|
|
@ -221,9 +226,16 @@
|
|||
items:
|
||||
- MiningDrill
|
||||
- MineralScannerUnpowered
|
||||
- OreBag
|
||||
# - OreBag # Frontier
|
||||
- Crowbar
|
||||
- RadioHandheld
|
||||
# Frontier: droppable borg items
|
||||
droppableItems:
|
||||
- id: OreBag
|
||||
whitelist:
|
||||
components:
|
||||
- NFOreBag
|
||||
# End Frontier: droppable borg items
|
||||
- type: BorgModuleIcon
|
||||
icon: { sprite: Interface/Actions/actions_borg.rsi, state: mining-module }
|
||||
|
||||
|
|
@ -345,8 +357,15 @@
|
|||
- type: ItemBorgModule
|
||||
items:
|
||||
- MopItem
|
||||
- Bucket
|
||||
# - Bucket # Frontier
|
||||
- TrashBag
|
||||
# Frontier: droppable items
|
||||
droppableItems:
|
||||
- id: Bucket
|
||||
whitelist:
|
||||
tags:
|
||||
- Bucket
|
||||
# End Frontier
|
||||
- type: BorgModuleIcon
|
||||
icon: { sprite: Interface/Actions/actions_borg.rsi, state: cleaning-module }
|
||||
|
||||
|
|
@ -433,10 +452,21 @@
|
|||
- type: ItemBorgModule
|
||||
items:
|
||||
- HandheldHealthAnalyzerUnpowered
|
||||
- Beaker
|
||||
- Beaker
|
||||
# - Beaker # Frontier
|
||||
# - Beaker # Frontier
|
||||
- BorgDropper
|
||||
- BorgHypo
|
||||
# Frontier: droppable borg items
|
||||
droppableItems:
|
||||
- id: Beaker
|
||||
whitelist:
|
||||
tags:
|
||||
- GlassBeaker
|
||||
- id: Beaker
|
||||
whitelist:
|
||||
tags:
|
||||
- GlassBeaker
|
||||
# End Frontier: droppable borg items
|
||||
- type: BorgModuleIcon
|
||||
icon: { sprite: Interface/Actions/actions_borg.rsi, state: adv-diagnosis-module }
|
||||
|
||||
|
|
@ -489,11 +519,26 @@
|
|||
- type: ItemBorgModule
|
||||
items:
|
||||
- Pen
|
||||
- BooksBag
|
||||
# - BooksBag # Frontier
|
||||
- HandLabeler
|
||||
- Lighter
|
||||
- DrinkShaker
|
||||
# - Lighter # Frontier
|
||||
# - DrinkShaker # Frontier
|
||||
- BorgDropper
|
||||
# Frontier: droppable
|
||||
droppableItems:
|
||||
- id: BooksBag
|
||||
whitelist:
|
||||
components:
|
||||
- NFBookBag
|
||||
- id: Lighter
|
||||
whitelist:
|
||||
components:
|
||||
- NFLighter
|
||||
- id: DrinkShaker
|
||||
whitelist:
|
||||
components:
|
||||
- NFShaker
|
||||
# End Frontier
|
||||
- type: BorgModuleIcon
|
||||
icon: { sprite: Interface/Actions/actions_borg.rsi, state: service-module }
|
||||
|
||||
|
|
@ -528,7 +573,14 @@
|
|||
- HydroponicsToolMiniHoe
|
||||
- HydroponicsToolSpade
|
||||
- HydroponicsToolClippers
|
||||
- Bucket
|
||||
# - Bucket # Frontier
|
||||
# Frontier: droppable borg items
|
||||
droppableItems:
|
||||
- id: Bucket
|
||||
whitelist:
|
||||
tags:
|
||||
- Bucket
|
||||
# End Frontier
|
||||
- type: BorgModuleIcon
|
||||
icon: { sprite: Interface/Actions/actions_borg.rsi, state: gardening-module }
|
||||
|
||||
|
|
@ -545,7 +597,14 @@
|
|||
items:
|
||||
- HydroponicsToolScythe
|
||||
- HydroponicsToolHatchet
|
||||
- PlantBag
|
||||
# - PlantBag # Frontier
|
||||
# Frontier: droppable borg items
|
||||
droppableItems:
|
||||
- id: PlantBag
|
||||
whitelist:
|
||||
components:
|
||||
- NFPlantBag
|
||||
# End Frontier
|
||||
- type: BorgModuleIcon
|
||||
icon: { sprite: Interface/Actions/actions_borg.rsi, state: harvesting-module }
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,9 @@
|
|||
enum.ToggleVisuals.Layer:
|
||||
True: { state: icon_on }
|
||||
False: { state: icon }
|
||||
# End DeltaV Additions
|
||||
- type: ReverseEngineering # DeltaV
|
||||
- type: ReverseEngineering
|
||||
difficulty: 2
|
||||
recipes:
|
||||
- OreBagOfHolding
|
||||
# End DeltaV Additions
|
||||
- type: NFOreBag # Frontier
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@
|
|||
collection: lighterOnSounds
|
||||
endSound:
|
||||
collection: lighterOffSounds
|
||||
- type: NFLighter # Frontier
|
||||
|
||||
- type: entity
|
||||
name: cheap lighter
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
- type: entity
|
||||
id: HandPlaceholder
|
||||
name: unknown tool
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Item
|
||||
size: Ginormous # no storage insertion visuals
|
||||
- type: Unremoveable
|
||||
- type: HandPlaceholder
|
||||
- type: HandPlaceholderVisuals
|
||||
Loading…
Reference in New Issue